18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2008-2009 Atheros Communications Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 58c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 68c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 98c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 108c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 118c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 128c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 138c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 148c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/kernel.h> 208c2ecf20Sopenharmony_ci#include <linux/export.h> 218c2ecf20Sopenharmony_ci#include <net/cfg80211.h> 228c2ecf20Sopenharmony_ci#include <net/mac80211.h> 238c2ecf20Sopenharmony_ci#include "regd.h" 248c2ecf20Sopenharmony_ci#include "regd_common.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic int __ath_regd_init(struct ath_regulatory *reg); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * This is a set of common rules used by our world regulatory domains. 308c2ecf20Sopenharmony_ci * We have 12 world regulatory domains. To save space we consolidate 318c2ecf20Sopenharmony_ci * the regulatory domains in 5 structures by frequency and change 328c2ecf20Sopenharmony_ci * the flags on our reg_notifier() on a case by case basis. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* Only these channels all allow active scan on all world regulatory domains */ 368c2ecf20Sopenharmony_ci#define ATH_2GHZ_CH01_11 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* We enable active scan on these a case by case basis by regulatory domain */ 398c2ecf20Sopenharmony_ci#define ATH_2GHZ_CH12_13 REG_RULE(2467-10, 2472+10, 40, 0, 20,\ 408c2ecf20Sopenharmony_ci NL80211_RRF_NO_IR) 418c2ecf20Sopenharmony_ci#define ATH_2GHZ_CH14 REG_RULE(2484-10, 2484+10, 40, 0, 20,\ 428c2ecf20Sopenharmony_ci NL80211_RRF_NO_IR | \ 438c2ecf20Sopenharmony_ci NL80211_RRF_NO_OFDM) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* We allow IBSS on these on a case by case basis by regulatory domain */ 468c2ecf20Sopenharmony_ci#define ATH_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\ 478c2ecf20Sopenharmony_ci NL80211_RRF_NO_IR) 488c2ecf20Sopenharmony_ci#define ATH_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\ 498c2ecf20Sopenharmony_ci NL80211_RRF_NO_IR) 508c2ecf20Sopenharmony_ci#define ATH_5GHZ_5725_5850 REG_RULE(5725-10, 5850+10, 80, 0, 30,\ 518c2ecf20Sopenharmony_ci NL80211_RRF_NO_IR) 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define ATH_2GHZ_ALL ATH_2GHZ_CH01_11, \ 548c2ecf20Sopenharmony_ci ATH_2GHZ_CH12_13, \ 558c2ecf20Sopenharmony_ci ATH_2GHZ_CH14 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define ATH_5GHZ_ALL ATH_5GHZ_5150_5350, \ 588c2ecf20Sopenharmony_ci ATH_5GHZ_5470_5850 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* This one skips what we call "mid band" */ 618c2ecf20Sopenharmony_ci#define ATH_5GHZ_NO_MIDBAND ATH_5GHZ_5150_5350, \ 628c2ecf20Sopenharmony_ci ATH_5GHZ_5725_5850 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* Can be used for: 658c2ecf20Sopenharmony_ci * 0x60, 0x61, 0x62 */ 668c2ecf20Sopenharmony_cistatic const struct ieee80211_regdomain ath_world_regdom_60_61_62 = { 678c2ecf20Sopenharmony_ci .n_reg_rules = 5, 688c2ecf20Sopenharmony_ci .alpha2 = "99", 698c2ecf20Sopenharmony_ci .reg_rules = { 708c2ecf20Sopenharmony_ci ATH_2GHZ_ALL, 718c2ecf20Sopenharmony_ci ATH_5GHZ_ALL, 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* Can be used by 0x63 and 0x65 */ 768c2ecf20Sopenharmony_cistatic const struct ieee80211_regdomain ath_world_regdom_63_65 = { 778c2ecf20Sopenharmony_ci .n_reg_rules = 4, 788c2ecf20Sopenharmony_ci .alpha2 = "99", 798c2ecf20Sopenharmony_ci .reg_rules = { 808c2ecf20Sopenharmony_ci ATH_2GHZ_CH01_11, 818c2ecf20Sopenharmony_ci ATH_2GHZ_CH12_13, 828c2ecf20Sopenharmony_ci ATH_5GHZ_NO_MIDBAND, 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/* Can be used by 0x64 only */ 878c2ecf20Sopenharmony_cistatic const struct ieee80211_regdomain ath_world_regdom_64 = { 888c2ecf20Sopenharmony_ci .n_reg_rules = 3, 898c2ecf20Sopenharmony_ci .alpha2 = "99", 908c2ecf20Sopenharmony_ci .reg_rules = { 918c2ecf20Sopenharmony_ci ATH_2GHZ_CH01_11, 928c2ecf20Sopenharmony_ci ATH_5GHZ_NO_MIDBAND, 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci}; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* Can be used by 0x66 and 0x69 */ 978c2ecf20Sopenharmony_cistatic const struct ieee80211_regdomain ath_world_regdom_66_69 = { 988c2ecf20Sopenharmony_ci .n_reg_rules = 3, 998c2ecf20Sopenharmony_ci .alpha2 = "99", 1008c2ecf20Sopenharmony_ci .reg_rules = { 1018c2ecf20Sopenharmony_ci ATH_2GHZ_CH01_11, 1028c2ecf20Sopenharmony_ci ATH_5GHZ_ALL, 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* Can be used by 0x67, 0x68, 0x6A and 0x6C */ 1078c2ecf20Sopenharmony_cistatic const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = { 1088c2ecf20Sopenharmony_ci .n_reg_rules = 4, 1098c2ecf20Sopenharmony_ci .alpha2 = "99", 1108c2ecf20Sopenharmony_ci .reg_rules = { 1118c2ecf20Sopenharmony_ci ATH_2GHZ_CH01_11, 1128c2ecf20Sopenharmony_ci ATH_2GHZ_CH12_13, 1138c2ecf20Sopenharmony_ci ATH_5GHZ_ALL, 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci}; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic bool dynamic_country_user_possible(struct ath_regulatory *reg) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_ATH_REG_DYNAMIC_USER_CERT_TESTING)) 1208c2ecf20Sopenharmony_ci return true; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci switch (reg->country_code) { 1238c2ecf20Sopenharmony_ci case CTRY_UNITED_STATES: 1248c2ecf20Sopenharmony_ci case CTRY_JAPAN1: 1258c2ecf20Sopenharmony_ci case CTRY_JAPAN2: 1268c2ecf20Sopenharmony_ci case CTRY_JAPAN3: 1278c2ecf20Sopenharmony_ci case CTRY_JAPAN4: 1288c2ecf20Sopenharmony_ci case CTRY_JAPAN5: 1298c2ecf20Sopenharmony_ci case CTRY_JAPAN6: 1308c2ecf20Sopenharmony_ci case CTRY_JAPAN7: 1318c2ecf20Sopenharmony_ci case CTRY_JAPAN8: 1328c2ecf20Sopenharmony_ci case CTRY_JAPAN9: 1338c2ecf20Sopenharmony_ci case CTRY_JAPAN10: 1348c2ecf20Sopenharmony_ci case CTRY_JAPAN11: 1358c2ecf20Sopenharmony_ci case CTRY_JAPAN12: 1368c2ecf20Sopenharmony_ci case CTRY_JAPAN13: 1378c2ecf20Sopenharmony_ci case CTRY_JAPAN14: 1388c2ecf20Sopenharmony_ci case CTRY_JAPAN15: 1398c2ecf20Sopenharmony_ci case CTRY_JAPAN16: 1408c2ecf20Sopenharmony_ci case CTRY_JAPAN17: 1418c2ecf20Sopenharmony_ci case CTRY_JAPAN18: 1428c2ecf20Sopenharmony_ci case CTRY_JAPAN19: 1438c2ecf20Sopenharmony_ci case CTRY_JAPAN20: 1448c2ecf20Sopenharmony_ci case CTRY_JAPAN21: 1458c2ecf20Sopenharmony_ci case CTRY_JAPAN22: 1468c2ecf20Sopenharmony_ci case CTRY_JAPAN23: 1478c2ecf20Sopenharmony_ci case CTRY_JAPAN24: 1488c2ecf20Sopenharmony_ci case CTRY_JAPAN25: 1498c2ecf20Sopenharmony_ci case CTRY_JAPAN26: 1508c2ecf20Sopenharmony_ci case CTRY_JAPAN27: 1518c2ecf20Sopenharmony_ci case CTRY_JAPAN28: 1528c2ecf20Sopenharmony_ci case CTRY_JAPAN29: 1538c2ecf20Sopenharmony_ci case CTRY_JAPAN30: 1548c2ecf20Sopenharmony_ci case CTRY_JAPAN31: 1558c2ecf20Sopenharmony_ci case CTRY_JAPAN32: 1568c2ecf20Sopenharmony_ci case CTRY_JAPAN33: 1578c2ecf20Sopenharmony_ci case CTRY_JAPAN34: 1588c2ecf20Sopenharmony_ci case CTRY_JAPAN35: 1598c2ecf20Sopenharmony_ci case CTRY_JAPAN36: 1608c2ecf20Sopenharmony_ci case CTRY_JAPAN37: 1618c2ecf20Sopenharmony_ci case CTRY_JAPAN38: 1628c2ecf20Sopenharmony_ci case CTRY_JAPAN39: 1638c2ecf20Sopenharmony_ci case CTRY_JAPAN40: 1648c2ecf20Sopenharmony_ci case CTRY_JAPAN41: 1658c2ecf20Sopenharmony_ci case CTRY_JAPAN42: 1668c2ecf20Sopenharmony_ci case CTRY_JAPAN43: 1678c2ecf20Sopenharmony_ci case CTRY_JAPAN44: 1688c2ecf20Sopenharmony_ci case CTRY_JAPAN45: 1698c2ecf20Sopenharmony_ci case CTRY_JAPAN46: 1708c2ecf20Sopenharmony_ci case CTRY_JAPAN47: 1718c2ecf20Sopenharmony_ci case CTRY_JAPAN48: 1728c2ecf20Sopenharmony_ci case CTRY_JAPAN49: 1738c2ecf20Sopenharmony_ci case CTRY_JAPAN50: 1748c2ecf20Sopenharmony_ci case CTRY_JAPAN51: 1758c2ecf20Sopenharmony_ci case CTRY_JAPAN52: 1768c2ecf20Sopenharmony_ci case CTRY_JAPAN53: 1778c2ecf20Sopenharmony_ci case CTRY_JAPAN54: 1788c2ecf20Sopenharmony_ci case CTRY_JAPAN55: 1798c2ecf20Sopenharmony_ci case CTRY_JAPAN56: 1808c2ecf20Sopenharmony_ci case CTRY_JAPAN57: 1818c2ecf20Sopenharmony_ci case CTRY_JAPAN58: 1828c2ecf20Sopenharmony_ci case CTRY_JAPAN59: 1838c2ecf20Sopenharmony_ci return false; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci return true; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic bool ath_reg_dyn_country_user_allow(struct ath_regulatory *reg) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS)) 1928c2ecf20Sopenharmony_ci return false; 1938c2ecf20Sopenharmony_ci if (!dynamic_country_user_possible(reg)) 1948c2ecf20Sopenharmony_ci return false; 1958c2ecf20Sopenharmony_ci return true; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic inline bool is_wwr_sku(u16 regd) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci return ((regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) && 2018c2ecf20Sopenharmony_ci (((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) || 2028c2ecf20Sopenharmony_ci (regd == WORLD)); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic u16 ath_regd_get_eepromRD(struct ath_regulatory *reg) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cibool ath_is_world_regd(struct ath_regulatory *reg) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci return is_wwr_sku(ath_regd_get_eepromRD(reg)); 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath_is_world_regd); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic const struct ieee80211_regdomain *ath_default_world_regdomain(void) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci /* this is the most restrictive */ 2198c2ecf20Sopenharmony_ci return &ath_world_regdom_64; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic const struct 2238c2ecf20Sopenharmony_ciieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci switch (reg->regpair->reg_domain) { 2268c2ecf20Sopenharmony_ci case 0x60: 2278c2ecf20Sopenharmony_ci case 0x61: 2288c2ecf20Sopenharmony_ci case 0x62: 2298c2ecf20Sopenharmony_ci return &ath_world_regdom_60_61_62; 2308c2ecf20Sopenharmony_ci case 0x63: 2318c2ecf20Sopenharmony_ci case 0x65: 2328c2ecf20Sopenharmony_ci return &ath_world_regdom_63_65; 2338c2ecf20Sopenharmony_ci case 0x64: 2348c2ecf20Sopenharmony_ci return &ath_world_regdom_64; 2358c2ecf20Sopenharmony_ci case 0x66: 2368c2ecf20Sopenharmony_ci case 0x69: 2378c2ecf20Sopenharmony_ci return &ath_world_regdom_66_69; 2388c2ecf20Sopenharmony_ci case 0x67: 2398c2ecf20Sopenharmony_ci case 0x68: 2408c2ecf20Sopenharmony_ci case 0x6A: 2418c2ecf20Sopenharmony_ci case 0x6C: 2428c2ecf20Sopenharmony_ci return &ath_world_regdom_67_68_6A_6C; 2438c2ecf20Sopenharmony_ci default: 2448c2ecf20Sopenharmony_ci WARN_ON(1); 2458c2ecf20Sopenharmony_ci return ath_default_world_regdomain(); 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cibool ath_is_49ghz_allowed(u16 regdomain) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci /* possibly more */ 2528c2ecf20Sopenharmony_ci return regdomain == MKK9_MKKC; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath_is_49ghz_allowed); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci/* Frequency is one where radar detection is required */ 2578c2ecf20Sopenharmony_cistatic bool ath_is_radar_freq(u16 center_freq, 2588c2ecf20Sopenharmony_ci struct ath_regulatory *reg) 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci if (reg->country_code == CTRY_INDIA) 2628c2ecf20Sopenharmony_ci return (center_freq >= 5500 && center_freq <= 5700); 2638c2ecf20Sopenharmony_ci return (center_freq >= 5260 && center_freq <= 5700); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic void ath_force_clear_no_ir_chan(struct wiphy *wiphy, 2678c2ecf20Sopenharmony_ci struct ieee80211_channel *ch) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci const struct ieee80211_reg_rule *reg_rule; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq)); 2728c2ecf20Sopenharmony_ci if (IS_ERR(reg_rule)) 2738c2ecf20Sopenharmony_ci return; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (!(reg_rule->flags & NL80211_RRF_NO_IR)) 2768c2ecf20Sopenharmony_ci if (ch->flags & IEEE80211_CHAN_NO_IR) 2778c2ecf20Sopenharmony_ci ch->flags &= ~IEEE80211_CHAN_NO_IR; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic void ath_force_clear_no_ir_freq(struct wiphy *wiphy, u16 center_freq) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci struct ieee80211_channel *ch; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci ch = ieee80211_get_channel(wiphy, center_freq); 2858c2ecf20Sopenharmony_ci if (!ch) 2868c2ecf20Sopenharmony_ci return; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci ath_force_clear_no_ir_chan(wiphy, ch); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic void ath_force_no_ir_chan(struct ieee80211_channel *ch) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci ch->flags |= IEEE80211_CHAN_NO_IR; 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic void ath_force_no_ir_freq(struct wiphy *wiphy, u16 center_freq) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci struct ieee80211_channel *ch; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci ch = ieee80211_get_channel(wiphy, center_freq); 3018c2ecf20Sopenharmony_ci if (!ch) 3028c2ecf20Sopenharmony_ci return; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci ath_force_no_ir_chan(ch); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic void 3088c2ecf20Sopenharmony_ci__ath_reg_apply_beaconing_flags(struct wiphy *wiphy, 3098c2ecf20Sopenharmony_ci struct ath_regulatory *reg, 3108c2ecf20Sopenharmony_ci enum nl80211_reg_initiator initiator, 3118c2ecf20Sopenharmony_ci struct ieee80211_channel *ch) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci if (ath_is_radar_freq(ch->center_freq, reg) || 3148c2ecf20Sopenharmony_ci (ch->flags & IEEE80211_CHAN_RADAR)) 3158c2ecf20Sopenharmony_ci return; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci switch (initiator) { 3188c2ecf20Sopenharmony_ci case NL80211_REGDOM_SET_BY_COUNTRY_IE: 3198c2ecf20Sopenharmony_ci ath_force_clear_no_ir_chan(wiphy, ch); 3208c2ecf20Sopenharmony_ci break; 3218c2ecf20Sopenharmony_ci case NL80211_REGDOM_SET_BY_USER: 3228c2ecf20Sopenharmony_ci if (ath_reg_dyn_country_user_allow(reg)) 3238c2ecf20Sopenharmony_ci ath_force_clear_no_ir_chan(wiphy, ch); 3248c2ecf20Sopenharmony_ci break; 3258c2ecf20Sopenharmony_ci default: 3268c2ecf20Sopenharmony_ci if (ch->beacon_found) 3278c2ecf20Sopenharmony_ci ch->flags &= ~IEEE80211_CHAN_NO_IR; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci/* 3328c2ecf20Sopenharmony_ci * These exception rules do not apply radar frequencies. 3338c2ecf20Sopenharmony_ci * 3348c2ecf20Sopenharmony_ci * - We enable initiating radiation if the country IE says its fine: 3358c2ecf20Sopenharmony_ci * - If no country IE has been processed and a we determine we have 3368c2ecf20Sopenharmony_ci * received a beacon on a channel we can enable initiating radiation. 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_cistatic void 3398c2ecf20Sopenharmony_ciath_reg_apply_beaconing_flags(struct wiphy *wiphy, 3408c2ecf20Sopenharmony_ci struct ath_regulatory *reg, 3418c2ecf20Sopenharmony_ci enum nl80211_reg_initiator initiator) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci enum nl80211_band band; 3448c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 3458c2ecf20Sopenharmony_ci struct ieee80211_channel *ch; 3468c2ecf20Sopenharmony_ci unsigned int i; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci for (band = 0; band < NUM_NL80211_BANDS; band++) { 3498c2ecf20Sopenharmony_ci if (!wiphy->bands[band]) 3508c2ecf20Sopenharmony_ci continue; 3518c2ecf20Sopenharmony_ci sband = wiphy->bands[band]; 3528c2ecf20Sopenharmony_ci for (i = 0; i < sband->n_channels; i++) { 3538c2ecf20Sopenharmony_ci ch = &sband->channels[i]; 3548c2ecf20Sopenharmony_ci __ath_reg_apply_beaconing_flags(wiphy, reg, 3558c2ecf20Sopenharmony_ci initiator, ch); 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci/** 3618c2ecf20Sopenharmony_ci * ath_reg_apply_ir_flags() 3628c2ecf20Sopenharmony_ci * @wiphy: the wiphy to use 3638c2ecf20Sopenharmony_ci * @initiator: the regulatory hint initiator 3648c2ecf20Sopenharmony_ci * 3658c2ecf20Sopenharmony_ci * If no country IE has been received always enable passive scan 3668c2ecf20Sopenharmony_ci * and no-ibss on these channels. This is only done for specific 3678c2ecf20Sopenharmony_ci * regulatory SKUs. 3688c2ecf20Sopenharmony_ci * 3698c2ecf20Sopenharmony_ci * If a country IE has been received check its rule for this 3708c2ecf20Sopenharmony_ci * channel first before enabling active scan. The passive scan 3718c2ecf20Sopenharmony_ci * would have been enforced by the initial processing of our 3728c2ecf20Sopenharmony_ci * custom regulatory domain. 3738c2ecf20Sopenharmony_ci */ 3748c2ecf20Sopenharmony_cistatic void 3758c2ecf20Sopenharmony_ciath_reg_apply_ir_flags(struct wiphy *wiphy, 3768c2ecf20Sopenharmony_ci struct ath_regulatory *reg, 3778c2ecf20Sopenharmony_ci enum nl80211_reg_initiator initiator) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci sband = wiphy->bands[NL80211_BAND_2GHZ]; 3828c2ecf20Sopenharmony_ci if (!sband) 3838c2ecf20Sopenharmony_ci return; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci switch(initiator) { 3868c2ecf20Sopenharmony_ci case NL80211_REGDOM_SET_BY_COUNTRY_IE: 3878c2ecf20Sopenharmony_ci ath_force_clear_no_ir_freq(wiphy, 2467); 3888c2ecf20Sopenharmony_ci ath_force_clear_no_ir_freq(wiphy, 2472); 3898c2ecf20Sopenharmony_ci break; 3908c2ecf20Sopenharmony_ci case NL80211_REGDOM_SET_BY_USER: 3918c2ecf20Sopenharmony_ci if (!ath_reg_dyn_country_user_allow(reg)) 3928c2ecf20Sopenharmony_ci break; 3938c2ecf20Sopenharmony_ci ath_force_clear_no_ir_freq(wiphy, 2467); 3948c2ecf20Sopenharmony_ci ath_force_clear_no_ir_freq(wiphy, 2472); 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci default: 3978c2ecf20Sopenharmony_ci ath_force_no_ir_freq(wiphy, 2467); 3988c2ecf20Sopenharmony_ci ath_force_no_ir_freq(wiphy, 2472); 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci/* Always apply Radar/DFS rules on freq range 5500 MHz - 5700 MHz */ 4038c2ecf20Sopenharmony_cistatic void ath_reg_apply_radar_flags(struct wiphy *wiphy, 4048c2ecf20Sopenharmony_ci struct ath_regulatory *reg) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 4078c2ecf20Sopenharmony_ci struct ieee80211_channel *ch; 4088c2ecf20Sopenharmony_ci unsigned int i; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (!wiphy->bands[NL80211_BAND_5GHZ]) 4118c2ecf20Sopenharmony_ci return; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci sband = wiphy->bands[NL80211_BAND_5GHZ]; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci for (i = 0; i < sband->n_channels; i++) { 4168c2ecf20Sopenharmony_ci ch = &sband->channels[i]; 4178c2ecf20Sopenharmony_ci if (!ath_is_radar_freq(ch->center_freq, reg)) 4188c2ecf20Sopenharmony_ci continue; 4198c2ecf20Sopenharmony_ci /* We always enable radar detection/DFS on this 4208c2ecf20Sopenharmony_ci * frequency range. Additionally we also apply on 4218c2ecf20Sopenharmony_ci * this frequency range: 4228c2ecf20Sopenharmony_ci * - If STA mode does not yet have DFS supports disable 4238c2ecf20Sopenharmony_ci * active scanning 4248c2ecf20Sopenharmony_ci * - If adhoc mode does not support DFS yet then 4258c2ecf20Sopenharmony_ci * disable adhoc in the frequency. 4268c2ecf20Sopenharmony_ci * - If AP mode does not yet support radar detection/DFS 4278c2ecf20Sopenharmony_ci * do not allow AP mode 4288c2ecf20Sopenharmony_ci */ 4298c2ecf20Sopenharmony_ci if (!(ch->flags & IEEE80211_CHAN_DISABLED)) 4308c2ecf20Sopenharmony_ci ch->flags |= IEEE80211_CHAN_RADAR | 4318c2ecf20Sopenharmony_ci IEEE80211_CHAN_NO_IR; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic void ath_reg_apply_world_flags(struct wiphy *wiphy, 4368c2ecf20Sopenharmony_ci enum nl80211_reg_initiator initiator, 4378c2ecf20Sopenharmony_ci struct ath_regulatory *reg) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci switch (reg->regpair->reg_domain) { 4408c2ecf20Sopenharmony_ci case 0x60: 4418c2ecf20Sopenharmony_ci case 0x63: 4428c2ecf20Sopenharmony_ci case 0x66: 4438c2ecf20Sopenharmony_ci case 0x67: 4448c2ecf20Sopenharmony_ci case 0x6C: 4458c2ecf20Sopenharmony_ci ath_reg_apply_beaconing_flags(wiphy, reg, initiator); 4468c2ecf20Sopenharmony_ci break; 4478c2ecf20Sopenharmony_ci case 0x68: 4488c2ecf20Sopenharmony_ci ath_reg_apply_beaconing_flags(wiphy, reg, initiator); 4498c2ecf20Sopenharmony_ci ath_reg_apply_ir_flags(wiphy, reg, initiator); 4508c2ecf20Sopenharmony_ci break; 4518c2ecf20Sopenharmony_ci default: 4528c2ecf20Sopenharmony_ci if (ath_reg_dyn_country_user_allow(reg)) 4538c2ecf20Sopenharmony_ci ath_reg_apply_beaconing_flags(wiphy, reg, initiator); 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ciu16 ath_regd_find_country_by_name(char *alpha2) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci unsigned int i; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(allCountries); i++) { 4628c2ecf20Sopenharmony_ci if (!memcmp(allCountries[i].isoName, alpha2, 2)) 4638c2ecf20Sopenharmony_ci return allCountries[i].countryCode; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci return -1; 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath_regd_find_country_by_name); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic int __ath_reg_dyn_country(struct wiphy *wiphy, 4718c2ecf20Sopenharmony_ci struct ath_regulatory *reg, 4728c2ecf20Sopenharmony_ci struct regulatory_request *request) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci u16 country_code; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && 4778c2ecf20Sopenharmony_ci !ath_is_world_regd(reg)) 4788c2ecf20Sopenharmony_ci return -EINVAL; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci country_code = ath_regd_find_country_by_name(request->alpha2); 4818c2ecf20Sopenharmony_ci if (country_code == (u16) -1) 4828c2ecf20Sopenharmony_ci return -EINVAL; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci reg->current_rd = COUNTRY_ERD_FLAG; 4858c2ecf20Sopenharmony_ci reg->current_rd |= country_code; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci __ath_regd_init(reg); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci ath_reg_apply_world_flags(wiphy, request->initiator, reg); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci return 0; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic void ath_reg_dyn_country(struct wiphy *wiphy, 4958c2ecf20Sopenharmony_ci struct ath_regulatory *reg, 4968c2ecf20Sopenharmony_ci struct regulatory_request *request) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci if (__ath_reg_dyn_country(wiphy, reg, request)) 4998c2ecf20Sopenharmony_ci return; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ath: regdomain 0x%0x " 5028c2ecf20Sopenharmony_ci "dynamically updated by %s\n", 5038c2ecf20Sopenharmony_ci reg->current_rd, 5048c2ecf20Sopenharmony_ci reg_initiator_name(request->initiator)); 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_civoid ath_reg_notifier_apply(struct wiphy *wiphy, 5088c2ecf20Sopenharmony_ci struct regulatory_request *request, 5098c2ecf20Sopenharmony_ci struct ath_regulatory *reg) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci struct ath_common *common = container_of(reg, struct ath_common, 5128c2ecf20Sopenharmony_ci regulatory); 5138c2ecf20Sopenharmony_ci /* We always apply this */ 5148c2ecf20Sopenharmony_ci ath_reg_apply_radar_flags(wiphy, reg); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci /* 5178c2ecf20Sopenharmony_ci * This would happen when we have sent a custom regulatory request 5188c2ecf20Sopenharmony_ci * a world regulatory domain and the scheduler hasn't yet processed 5198c2ecf20Sopenharmony_ci * any pending requests in the queue. 5208c2ecf20Sopenharmony_ci */ 5218c2ecf20Sopenharmony_ci if (!request) 5228c2ecf20Sopenharmony_ci return; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci reg->region = request->dfs_region; 5258c2ecf20Sopenharmony_ci switch (request->initiator) { 5268c2ecf20Sopenharmony_ci case NL80211_REGDOM_SET_BY_CORE: 5278c2ecf20Sopenharmony_ci /* 5288c2ecf20Sopenharmony_ci * If common->reg_world_copy is world roaming it means we *were* 5298c2ecf20Sopenharmony_ci * world roaming... so we now have to restore that data. 5308c2ecf20Sopenharmony_ci */ 5318c2ecf20Sopenharmony_ci if (!ath_is_world_regd(&common->reg_world_copy)) 5328c2ecf20Sopenharmony_ci break; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci memcpy(reg, &common->reg_world_copy, 5358c2ecf20Sopenharmony_ci sizeof(struct ath_regulatory)); 5368c2ecf20Sopenharmony_ci break; 5378c2ecf20Sopenharmony_ci case NL80211_REGDOM_SET_BY_DRIVER: 5388c2ecf20Sopenharmony_ci break; 5398c2ecf20Sopenharmony_ci case NL80211_REGDOM_SET_BY_USER: 5408c2ecf20Sopenharmony_ci if (ath_reg_dyn_country_user_allow(reg)) 5418c2ecf20Sopenharmony_ci ath_reg_dyn_country(wiphy, reg, request); 5428c2ecf20Sopenharmony_ci break; 5438c2ecf20Sopenharmony_ci case NL80211_REGDOM_SET_BY_COUNTRY_IE: 5448c2ecf20Sopenharmony_ci ath_reg_dyn_country(wiphy, reg, request); 5458c2ecf20Sopenharmony_ci break; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath_reg_notifier_apply); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cistatic bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci u16 rd = ath_regd_get_eepromRD(reg); 5538c2ecf20Sopenharmony_ci int i; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (rd & COUNTRY_ERD_FLAG) { 5568c2ecf20Sopenharmony_ci /* EEPROM value is a country code */ 5578c2ecf20Sopenharmony_ci u16 cc = rd & ~COUNTRY_ERD_FLAG; 5588c2ecf20Sopenharmony_ci printk(KERN_DEBUG 5598c2ecf20Sopenharmony_ci "ath: EEPROM indicates we should expect " 5608c2ecf20Sopenharmony_ci "a country code\n"); 5618c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(allCountries); i++) 5628c2ecf20Sopenharmony_ci if (allCountries[i].countryCode == cc) 5638c2ecf20Sopenharmony_ci return true; 5648c2ecf20Sopenharmony_ci } else { 5658c2ecf20Sopenharmony_ci /* EEPROM value is a regpair value */ 5668c2ecf20Sopenharmony_ci if (rd != CTRY_DEFAULT) 5678c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ath: EEPROM indicates we " 5688c2ecf20Sopenharmony_ci "should expect a direct regpair map\n"); 5698c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) 5708c2ecf20Sopenharmony_ci if (regDomainPairs[i].reg_domain == rd) 5718c2ecf20Sopenharmony_ci return true; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci printk(KERN_DEBUG 5748c2ecf20Sopenharmony_ci "ath: invalid regulatory domain/country code 0x%x\n", rd); 5758c2ecf20Sopenharmony_ci return false; 5768c2ecf20Sopenharmony_ci} 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci/* EEPROM country code to regpair mapping */ 5798c2ecf20Sopenharmony_cistatic struct country_code_to_enum_rd* 5808c2ecf20Sopenharmony_ciath_regd_find_country(u16 countryCode) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci int i; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(allCountries); i++) { 5858c2ecf20Sopenharmony_ci if (allCountries[i].countryCode == countryCode) 5868c2ecf20Sopenharmony_ci return &allCountries[i]; 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci return NULL; 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci/* EEPROM rd code to regpair mapping */ 5928c2ecf20Sopenharmony_cistatic struct country_code_to_enum_rd* 5938c2ecf20Sopenharmony_ciath_regd_find_country_by_rd(int regdmn) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci int i; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(allCountries); i++) { 5988c2ecf20Sopenharmony_ci if (allCountries[i].regDmnEnum == regdmn) 5998c2ecf20Sopenharmony_ci return &allCountries[i]; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci return NULL; 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci/* Returns the map of the EEPROM set RD to a country code */ 6058c2ecf20Sopenharmony_cistatic u16 ath_regd_get_default_country(u16 rd) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci if (rd & COUNTRY_ERD_FLAG) { 6088c2ecf20Sopenharmony_ci struct country_code_to_enum_rd *country = NULL; 6098c2ecf20Sopenharmony_ci u16 cc = rd & ~COUNTRY_ERD_FLAG; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci country = ath_regd_find_country(cc); 6128c2ecf20Sopenharmony_ci if (country != NULL) 6138c2ecf20Sopenharmony_ci return cc; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci return CTRY_DEFAULT; 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cistatic struct reg_dmn_pair_mapping* 6208c2ecf20Sopenharmony_ciath_get_regpair(int regdmn) 6218c2ecf20Sopenharmony_ci{ 6228c2ecf20Sopenharmony_ci int i; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (regdmn == NO_ENUMRD) 6258c2ecf20Sopenharmony_ci return NULL; 6268c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { 6278c2ecf20Sopenharmony_ci if (regDomainPairs[i].reg_domain == regdmn) 6288c2ecf20Sopenharmony_ci return ®DomainPairs[i]; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci return NULL; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic int 6348c2ecf20Sopenharmony_ciath_regd_init_wiphy(struct ath_regulatory *reg, 6358c2ecf20Sopenharmony_ci struct wiphy *wiphy, 6368c2ecf20Sopenharmony_ci void (*reg_notifier)(struct wiphy *wiphy, 6378c2ecf20Sopenharmony_ci struct regulatory_request *request)) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci const struct ieee80211_regdomain *regd; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci wiphy->reg_notifier = reg_notifier; 6428c2ecf20Sopenharmony_ci wiphy->regulatory_flags |= REGULATORY_STRICT_REG | 6438c2ecf20Sopenharmony_ci REGULATORY_CUSTOM_REG; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci if (ath_is_world_regd(reg)) { 6468c2ecf20Sopenharmony_ci /* 6478c2ecf20Sopenharmony_ci * Anything applied here (prior to wiphy registration) gets 6488c2ecf20Sopenharmony_ci * saved on the wiphy orig_* parameters 6498c2ecf20Sopenharmony_ci */ 6508c2ecf20Sopenharmony_ci regd = ath_world_regdomain(reg); 6518c2ecf20Sopenharmony_ci wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_FOLLOW_POWER; 6528c2ecf20Sopenharmony_ci } else { 6538c2ecf20Sopenharmony_ci /* 6548c2ecf20Sopenharmony_ci * This gets applied in the case of the absence of CRDA, 6558c2ecf20Sopenharmony_ci * it's our own custom world regulatory domain, similar to 6568c2ecf20Sopenharmony_ci * cfg80211's but we enable passive scanning. 6578c2ecf20Sopenharmony_ci */ 6588c2ecf20Sopenharmony_ci regd = ath_default_world_regdomain(); 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci wiphy_apply_custom_regulatory(wiphy, regd); 6628c2ecf20Sopenharmony_ci ath_reg_apply_radar_flags(wiphy, reg); 6638c2ecf20Sopenharmony_ci ath_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg); 6648c2ecf20Sopenharmony_ci return 0; 6658c2ecf20Sopenharmony_ci} 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci/* 6688c2ecf20Sopenharmony_ci * Some users have reported their EEPROM programmed with 6698c2ecf20Sopenharmony_ci * 0x8000 set, this is not a supported regulatory domain 6708c2ecf20Sopenharmony_ci * but since we have more than one user with it we need 6718c2ecf20Sopenharmony_ci * a solution for them. We default to 0x64, which is the 6728c2ecf20Sopenharmony_ci * default Atheros world regulatory domain. 6738c2ecf20Sopenharmony_ci */ 6748c2ecf20Sopenharmony_cistatic void ath_regd_sanitize(struct ath_regulatory *reg) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci if (reg->current_rd != COUNTRY_ERD_FLAG) 6778c2ecf20Sopenharmony_ci return; 6788c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ath: EEPROM regdomain sanitized\n"); 6798c2ecf20Sopenharmony_ci reg->current_rd = 0x64; 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic int __ath_regd_init(struct ath_regulatory *reg) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci struct country_code_to_enum_rd *country = NULL; 6858c2ecf20Sopenharmony_ci u16 regdmn; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci if (!reg) 6888c2ecf20Sopenharmony_ci return -EINVAL; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci ath_regd_sanitize(reg); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ath: EEPROM regdomain: 0x%0x\n", reg->current_rd); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci if (!ath_regd_is_eeprom_valid(reg)) { 6958c2ecf20Sopenharmony_ci pr_err("Invalid EEPROM contents\n"); 6968c2ecf20Sopenharmony_ci return -EINVAL; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci regdmn = ath_regd_get_eepromRD(reg); 7008c2ecf20Sopenharmony_ci reg->country_code = ath_regd_get_default_country(regdmn); 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci if (reg->country_code == CTRY_DEFAULT && 7038c2ecf20Sopenharmony_ci regdmn == CTRY_DEFAULT) { 7048c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ath: EEPROM indicates default " 7058c2ecf20Sopenharmony_ci "country code should be used\n"); 7068c2ecf20Sopenharmony_ci reg->country_code = CTRY_UNITED_STATES; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci if (reg->country_code == CTRY_DEFAULT) { 7108c2ecf20Sopenharmony_ci country = NULL; 7118c2ecf20Sopenharmony_ci } else { 7128c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ath: doing EEPROM country->regdmn " 7138c2ecf20Sopenharmony_ci "map search\n"); 7148c2ecf20Sopenharmony_ci country = ath_regd_find_country(reg->country_code); 7158c2ecf20Sopenharmony_ci if (country == NULL) { 7168c2ecf20Sopenharmony_ci printk(KERN_DEBUG 7178c2ecf20Sopenharmony_ci "ath: no valid country maps found for " 7188c2ecf20Sopenharmony_ci "country code: 0x%0x\n", 7198c2ecf20Sopenharmony_ci reg->country_code); 7208c2ecf20Sopenharmony_ci return -EINVAL; 7218c2ecf20Sopenharmony_ci } else { 7228c2ecf20Sopenharmony_ci regdmn = country->regDmnEnum; 7238c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ath: country maps to " 7248c2ecf20Sopenharmony_ci "regdmn code: 0x%0x\n", 7258c2ecf20Sopenharmony_ci regdmn); 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci reg->regpair = ath_get_regpair(regdmn); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if (!reg->regpair) { 7328c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ath: " 7338c2ecf20Sopenharmony_ci "No regulatory domain pair found, cannot continue\n"); 7348c2ecf20Sopenharmony_ci return -EINVAL; 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci if (!country) 7388c2ecf20Sopenharmony_ci country = ath_regd_find_country_by_rd(regdmn); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci if (country) { 7418c2ecf20Sopenharmony_ci reg->alpha2[0] = country->isoName[0]; 7428c2ecf20Sopenharmony_ci reg->alpha2[1] = country->isoName[1]; 7438c2ecf20Sopenharmony_ci } else { 7448c2ecf20Sopenharmony_ci reg->alpha2[0] = '0'; 7458c2ecf20Sopenharmony_ci reg->alpha2[1] = '0'; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n", 7498c2ecf20Sopenharmony_ci reg->alpha2[0], reg->alpha2[1]); 7508c2ecf20Sopenharmony_ci printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n", 7518c2ecf20Sopenharmony_ci reg->regpair->reg_domain); 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci return 0; 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ciint 7578c2ecf20Sopenharmony_ciath_regd_init(struct ath_regulatory *reg, 7588c2ecf20Sopenharmony_ci struct wiphy *wiphy, 7598c2ecf20Sopenharmony_ci void (*reg_notifier)(struct wiphy *wiphy, 7608c2ecf20Sopenharmony_ci struct regulatory_request *request)) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci struct ath_common *common = container_of(reg, struct ath_common, 7638c2ecf20Sopenharmony_ci regulatory); 7648c2ecf20Sopenharmony_ci int r; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci r = __ath_regd_init(reg); 7678c2ecf20Sopenharmony_ci if (r) 7688c2ecf20Sopenharmony_ci return r; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci if (ath_is_world_regd(reg)) 7718c2ecf20Sopenharmony_ci memcpy(&common->reg_world_copy, reg, 7728c2ecf20Sopenharmony_ci sizeof(struct ath_regulatory)); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci ath_regd_init_wiphy(reg, wiphy, reg_notifier); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci return 0; 7778c2ecf20Sopenharmony_ci} 7788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath_regd_init); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ciu32 ath_regd_get_band_ctl(struct ath_regulatory *reg, 7818c2ecf20Sopenharmony_ci enum nl80211_band band) 7828c2ecf20Sopenharmony_ci{ 7838c2ecf20Sopenharmony_ci if (!reg->regpair || 7848c2ecf20Sopenharmony_ci (reg->country_code == CTRY_DEFAULT && 7858c2ecf20Sopenharmony_ci is_wwr_sku(ath_regd_get_eepromRD(reg)))) { 7868c2ecf20Sopenharmony_ci return SD_NO_CTL; 7878c2ecf20Sopenharmony_ci } 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci if (ath_regd_get_eepromRD(reg) == CTRY_DEFAULT) { 7908c2ecf20Sopenharmony_ci switch (reg->region) { 7918c2ecf20Sopenharmony_ci case NL80211_DFS_FCC: 7928c2ecf20Sopenharmony_ci return CTL_FCC; 7938c2ecf20Sopenharmony_ci case NL80211_DFS_ETSI: 7948c2ecf20Sopenharmony_ci return CTL_ETSI; 7958c2ecf20Sopenharmony_ci case NL80211_DFS_JP: 7968c2ecf20Sopenharmony_ci return CTL_MKK; 7978c2ecf20Sopenharmony_ci default: 7988c2ecf20Sopenharmony_ci break; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci switch (band) { 8038c2ecf20Sopenharmony_ci case NL80211_BAND_2GHZ: 8048c2ecf20Sopenharmony_ci return reg->regpair->reg_2ghz_ctl; 8058c2ecf20Sopenharmony_ci case NL80211_BAND_5GHZ: 8068c2ecf20Sopenharmony_ci return reg->regpair->reg_5ghz_ctl; 8078c2ecf20Sopenharmony_ci default: 8088c2ecf20Sopenharmony_ci return NO_CTL; 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci} 8118c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath_regd_get_band_ctl); 812