regd.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. /******************************************************************************
  2. *
  3. * Copyright(c) 2009-2010 Realtek Corporation.
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of version 2 of the GNU General Public License as
  7. * published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12. * more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along with
  15. * this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
  17. *
  18. * The full GNU General Public License is included in this distribution in the
  19. * file called LICENSE.
  20. *
  21. * Contact Information:
  22. * wlanfae <wlanfae@realtek.com>
  23. * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
  24. * Hsinchu 300, Taiwan.
  25. *
  26. * Larry Finger <Larry.Finger@lwfinger.net>
  27. *
  28. *****************************************************************************/
  29. #include "wifi.h"
  30. #include "regd.h"
  31. static struct country_code_to_enum_rd allCountries[] = {
  32. {COUNTRY_CODE_FCC, "US"},
  33. {COUNTRY_CODE_IC, "US"},
  34. {COUNTRY_CODE_ETSI, "EC"},
  35. {COUNTRY_CODE_SPAIN, "EC"},
  36. {COUNTRY_CODE_FRANCE, "EC"},
  37. {COUNTRY_CODE_MKK, "JP"},
  38. {COUNTRY_CODE_MKK1, "JP"},
  39. {COUNTRY_CODE_ISRAEL, "EC"},
  40. {COUNTRY_CODE_TELEC, "JP"},
  41. {COUNTRY_CODE_MIC, "JP"},
  42. {COUNTRY_CODE_GLOBAL_DOMAIN, "JP"},
  43. {COUNTRY_CODE_WORLD_WIDE_13, "EC"},
  44. {COUNTRY_CODE_TELEC_NETGEAR, "EC"},
  45. };
  46. /*
  47. *Only these channels all allow active
  48. *scan on all world regulatory domains
  49. */
  50. #define RTL819x_2GHZ_CH01_11 \
  51. REG_RULE(2412-10, 2462+10, 40, 0, 20, 0)
  52. /*
  53. *We enable active scan on these a case
  54. *by case basis by regulatory domain
  55. */
  56. #define RTL819x_2GHZ_CH12_13 \
  57. REG_RULE(2467-10, 2472+10, 40, 0, 20,\
  58. NL80211_RRF_PASSIVE_SCAN)
  59. #define RTL819x_2GHZ_CH14 \
  60. REG_RULE(2484-10, 2484+10, 40, 0, 20, \
  61. NL80211_RRF_PASSIVE_SCAN | \
  62. NL80211_RRF_NO_OFDM)
  63. static const struct ieee80211_regdomain rtl_regdom_11 = {
  64. .n_reg_rules = 1,
  65. .alpha2 = "99",
  66. .reg_rules = {
  67. RTL819x_2GHZ_CH01_11,
  68. }
  69. };
  70. static const struct ieee80211_regdomain rtl_regdom_global = {
  71. .n_reg_rules = 3,
  72. .alpha2 = "99",
  73. .reg_rules = {
  74. RTL819x_2GHZ_CH01_11,
  75. RTL819x_2GHZ_CH12_13,
  76. RTL819x_2GHZ_CH14,
  77. }
  78. };
  79. static const struct ieee80211_regdomain rtl_regdom_world = {
  80. .n_reg_rules = 2,
  81. .alpha2 = "99",
  82. .reg_rules = {
  83. RTL819x_2GHZ_CH01_11,
  84. RTL819x_2GHZ_CH12_13,
  85. }
  86. };
  87. static bool _rtl_is_radar_freq(u16 center_freq)
  88. {
  89. return (center_freq >= 5260 && center_freq <= 5700);
  90. }
  91. static void _rtl_reg_apply_beaconing_flags(struct wiphy *wiphy,
  92. enum nl80211_reg_initiator initiator)
  93. {
  94. enum ieee80211_band band;
  95. struct ieee80211_supported_band *sband;
  96. const struct ieee80211_reg_rule *reg_rule;
  97. struct ieee80211_channel *ch;
  98. unsigned int i;
  99. u32 bandwidth = 0;
  100. int r;
  101. for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
  102. if (!wiphy->bands[band])
  103. continue;
  104. sband = wiphy->bands[band];
  105. for (i = 0; i < sband->n_channels; i++) {
  106. ch = &sband->channels[i];
  107. if (_rtl_is_radar_freq(ch->center_freq) ||
  108. (ch->flags & IEEE80211_CHAN_RADAR))
  109. continue;
  110. if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
  111. r = freq_reg_info(wiphy, ch->center_freq,
  112. bandwidth, &reg_rule);
  113. if (r)
  114. continue;
  115. /*
  116. *If 11d had a rule for this channel ensure
  117. *we enable adhoc/beaconing if it allows us to
  118. *use it. Note that we would have disabled it
  119. *by applying our static world regdomain by
  120. *default during init, prior to calling our
  121. *regulatory_hint().
  122. */
  123. if (!(reg_rule->flags & NL80211_RRF_NO_IBSS))
  124. ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
  125. if (!(reg_rule->
  126. flags & NL80211_RRF_PASSIVE_SCAN))
  127. ch->flags &=
  128. ~IEEE80211_CHAN_PASSIVE_SCAN;
  129. } else {
  130. if (ch->beacon_found)
  131. ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
  132. IEEE80211_CHAN_PASSIVE_SCAN);
  133. }
  134. }
  135. }
  136. }
  137. /* Allows active scan scan on Ch 12 and 13 */
  138. static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
  139. enum nl80211_reg_initiator
  140. initiator)
  141. {
  142. struct ieee80211_supported_band *sband;
  143. struct ieee80211_channel *ch;
  144. const struct ieee80211_reg_rule *reg_rule;
  145. u32 bandwidth = 0;
  146. int r;
  147. sband = wiphy->bands[IEEE80211_BAND_2GHZ];
  148. /*
  149. *If no country IE has been received always enable active scan
  150. *on these channels. This is only done for specific regulatory SKUs
  151. */
  152. if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
  153. ch = &sband->channels[11]; /* CH 12 */
  154. if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
  155. ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
  156. ch = &sband->channels[12]; /* CH 13 */
  157. if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
  158. ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
  159. return;
  160. }
  161. /*
  162. *If a country IE has been recieved check its rule for this
  163. *channel first before enabling active scan. The passive scan
  164. *would have been enforced by the initial processing of our
  165. *custom regulatory domain.
  166. */
  167. ch = &sband->channels[11]; /* CH 12 */
  168. r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
  169. if (!r) {
  170. if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
  171. if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
  172. ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
  173. }
  174. ch = &sband->channels[12]; /* CH 13 */
  175. r = freq_reg_info(wiphy, ch->center_freq, bandwidth, &reg_rule);
  176. if (!r) {
  177. if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
  178. if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
  179. ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
  180. }
  181. }
  182. /*
  183. *Always apply Radar/DFS rules on
  184. *freq range 5260 MHz - 5700 MHz
  185. */
  186. static void _rtl_reg_apply_radar_flags(struct wiphy *wiphy)
  187. {
  188. struct ieee80211_supported_band *sband;
  189. struct ieee80211_channel *ch;
  190. unsigned int i;
  191. if (!wiphy->bands[IEEE80211_BAND_5GHZ])
  192. return;
  193. sband = wiphy->bands[IEEE80211_BAND_5GHZ];
  194. for (i = 0; i < sband->n_channels; i++) {
  195. ch = &sband->channels[i];
  196. if (!_rtl_is_radar_freq(ch->center_freq))
  197. continue;
  198. /*
  199. *We always enable radar detection/DFS on this
  200. *frequency range. Additionally we also apply on
  201. *this frequency range:
  202. *- If STA mode does not yet have DFS supports disable
  203. * active scanning
  204. *- If adhoc mode does not support DFS yet then disable
  205. * adhoc in the frequency.
  206. *- If AP mode does not yet support radar detection/DFS
  207. *do not allow AP mode
  208. */
  209. if (!(ch->flags & IEEE80211_CHAN_DISABLED))
  210. ch->flags |= IEEE80211_CHAN_RADAR |
  211. IEEE80211_CHAN_NO_IBSS |
  212. IEEE80211_CHAN_PASSIVE_SCAN;
  213. }
  214. }
  215. static void _rtl_reg_apply_world_flags(struct wiphy *wiphy,
  216. enum nl80211_reg_initiator initiator,
  217. struct rtl_regulatory *reg)
  218. {
  219. _rtl_reg_apply_beaconing_flags(wiphy, initiator);
  220. _rtl_reg_apply_active_scan_flags(wiphy, initiator);
  221. return;
  222. }
  223. static void _rtl_dump_channel_map(struct wiphy *wiphy)
  224. {
  225. enum ieee80211_band band;
  226. struct ieee80211_supported_band *sband;
  227. struct ieee80211_channel *ch;
  228. unsigned int i;
  229. for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
  230. if (!wiphy->bands[band])
  231. continue;
  232. sband = wiphy->bands[band];
  233. for (i = 0; i < sband->n_channels; i++)
  234. ch = &sband->channels[i];
  235. }
  236. }
  237. static int _rtl_reg_notifier_apply(struct wiphy *wiphy,
  238. struct regulatory_request *request,
  239. struct rtl_regulatory *reg)
  240. {
  241. /* We always apply this */
  242. _rtl_reg_apply_radar_flags(wiphy);
  243. switch (request->initiator) {
  244. case NL80211_REGDOM_SET_BY_DRIVER:
  245. case NL80211_REGDOM_SET_BY_CORE:
  246. case NL80211_REGDOM_SET_BY_USER:
  247. break;
  248. case NL80211_REGDOM_SET_BY_COUNTRY_IE:
  249. _rtl_reg_apply_world_flags(wiphy, request->initiator, reg);
  250. break;
  251. }
  252. _rtl_dump_channel_map(wiphy);
  253. return 0;
  254. }
  255. static const struct ieee80211_regdomain *_rtl_regdomain_select(
  256. struct rtl_regulatory *reg)
  257. {
  258. switch (reg->country_code) {
  259. case COUNTRY_CODE_FCC:
  260. case COUNTRY_CODE_IC:
  261. return &rtl_regdom_11;
  262. case COUNTRY_CODE_ETSI:
  263. case COUNTRY_CODE_SPAIN:
  264. case COUNTRY_CODE_FRANCE:
  265. case COUNTRY_CODE_ISRAEL:
  266. case COUNTRY_CODE_TELEC_NETGEAR:
  267. return &rtl_regdom_world;
  268. case COUNTRY_CODE_MKK:
  269. case COUNTRY_CODE_MKK1:
  270. case COUNTRY_CODE_TELEC:
  271. case COUNTRY_CODE_MIC:
  272. return &rtl_regdom_global;
  273. case COUNTRY_CODE_GLOBAL_DOMAIN:
  274. return &rtl_regdom_global;
  275. case COUNTRY_CODE_WORLD_WIDE_13:
  276. return &rtl_regdom_world;
  277. default:
  278. return &rtl_regdom_world;
  279. }
  280. }
  281. static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg,
  282. struct wiphy *wiphy,
  283. int (*reg_notifier) (struct wiphy *wiphy,
  284. struct regulatory_request *
  285. request))
  286. {
  287. const struct ieee80211_regdomain *regd;
  288. wiphy->reg_notifier = reg_notifier;
  289. wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
  290. wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY;
  291. wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS;
  292. regd = _rtl_regdomain_select(reg);
  293. wiphy_apply_custom_regulatory(wiphy, regd);
  294. _rtl_reg_apply_radar_flags(wiphy);
  295. _rtl_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg);
  296. return 0;
  297. }
  298. static struct country_code_to_enum_rd *_rtl_regd_find_country(u16 countrycode)
  299. {
  300. int i;
  301. for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
  302. if (allCountries[i].countrycode == countrycode)
  303. return &allCountries[i];
  304. }
  305. return NULL;
  306. }
  307. int rtl_regd_init(struct ieee80211_hw *hw,
  308. int (*reg_notifier) (struct wiphy *wiphy,
  309. struct regulatory_request *request))
  310. {
  311. struct rtl_priv *rtlpriv = rtl_priv(hw);
  312. struct wiphy *wiphy = hw->wiphy;
  313. struct country_code_to_enum_rd *country = NULL;
  314. if (wiphy == NULL || &rtlpriv->regd == NULL)
  315. return -EINVAL;
  316. /* force the channel plan to world wide 13 */
  317. rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13;
  318. RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE,
  319. (KERN_DEBUG "rtl: EEPROM regdomain: 0x%0x\n",
  320. rtlpriv->regd.country_code));
  321. if (rtlpriv->regd.country_code >= COUNTRY_CODE_MAX) {
  322. RT_TRACE(rtlpriv, COMP_REGD, DBG_DMESG,
  323. (KERN_DEBUG "rtl: EEPROM indicates invalid contry code"
  324. "world wide 13 should be used\n"));
  325. rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13;
  326. }
  327. country = _rtl_regd_find_country(rtlpriv->regd.country_code);
  328. if (country) {
  329. rtlpriv->regd.alpha2[0] = country->isoName[0];
  330. rtlpriv->regd.alpha2[1] = country->isoName[1];
  331. } else {
  332. rtlpriv->regd.alpha2[0] = '0';
  333. rtlpriv->regd.alpha2[1] = '0';
  334. }
  335. RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE,
  336. (KERN_DEBUG "rtl: Country alpha2 being used: %c%c\n",
  337. rtlpriv->regd.alpha2[0], rtlpriv->regd.alpha2[1]));
  338. _rtl_regd_init_wiphy(&rtlpriv->regd, wiphy, reg_notifier);
  339. return 0;
  340. }
  341. int rtl_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
  342. {
  343. struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
  344. struct rtl_priv *rtlpriv = rtl_priv(hw);
  345. RT_TRACE(rtlpriv, COMP_REGD, DBG_LOUD, ("\n"));
  346. return _rtl_reg_notifier_apply(wiphy, request, &rtlpriv->regd);
  347. }