scan.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /*
  2. * This file is part of wl1271
  3. *
  4. * Copyright (C) 2009-2010 Nokia Corporation
  5. *
  6. * Contact: Luciano Coelho <luciano.coelho@nokia.com>
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * version 2 as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  20. * 02110-1301 USA
  21. *
  22. */
  23. #include <linux/ieee80211.h>
  24. #include "wlcore.h"
  25. #include "debug.h"
  26. #include "cmd.h"
  27. #include "scan.h"
  28. #include "acx.h"
  29. #include "ps.h"
  30. #include "tx.h"
  31. void wl1271_scan_complete_work(struct work_struct *work)
  32. {
  33. struct delayed_work *dwork;
  34. struct wl1271 *wl;
  35. struct ieee80211_vif *vif;
  36. struct wl12xx_vif *wlvif;
  37. int ret;
  38. dwork = container_of(work, struct delayed_work, work);
  39. wl = container_of(dwork, struct wl1271, scan_complete_work);
  40. wl1271_debug(DEBUG_SCAN, "Scanning complete");
  41. mutex_lock(&wl->mutex);
  42. if (unlikely(wl->state != WLCORE_STATE_ON))
  43. goto out;
  44. if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
  45. goto out;
  46. vif = wl->scan_vif;
  47. wlvif = wl12xx_vif_to_data(vif);
  48. /*
  49. * Rearm the tx watchdog just before idling scan. This
  50. * prevents just-finished scans from triggering the watchdog
  51. */
  52. wl12xx_rearm_tx_watchdog_locked(wl);
  53. wl->scan.state = WL1271_SCAN_STATE_IDLE;
  54. memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
  55. wl->scan.req = NULL;
  56. wl->scan_vif = NULL;
  57. ret = wl1271_ps_elp_wakeup(wl);
  58. if (ret < 0)
  59. goto out;
  60. if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
  61. /* restore hardware connection monitoring template */
  62. wl1271_cmd_build_ap_probe_req(wl, wlvif, wlvif->probereq);
  63. }
  64. wl1271_ps_elp_sleep(wl);
  65. if (wl->scan.failed) {
  66. wl1271_info("Scan completed due to error.");
  67. wl12xx_queue_recovery_work(wl);
  68. }
  69. ieee80211_scan_completed(wl->hw, false);
  70. out:
  71. mutex_unlock(&wl->mutex);
  72. }
  73. static int
  74. wlcore_scan_get_channels(struct wl1271 *wl,
  75. struct ieee80211_channel *req_channels[],
  76. u32 n_channels,
  77. u32 n_ssids,
  78. struct conn_scan_ch_params *channels,
  79. u32 band, bool radar, bool passive,
  80. int start, int max_channels,
  81. u8 *n_pactive_ch)
  82. {
  83. struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
  84. int i, j;
  85. u32 flags;
  86. bool force_passive = !n_ssids;
  87. u32 min_dwell_time_active, max_dwell_time_active, delta_per_probe;
  88. u32 dwell_time_passive, dwell_time_dfs;
  89. if (band == IEEE80211_BAND_5GHZ)
  90. delta_per_probe = c->dwell_time_delta_per_probe_5;
  91. else
  92. delta_per_probe = c->dwell_time_delta_per_probe;
  93. min_dwell_time_active = c->base_dwell_time +
  94. n_ssids * c->num_probe_reqs * delta_per_probe;
  95. max_dwell_time_active = min_dwell_time_active + c->max_dwell_time_delta;
  96. min_dwell_time_active = DIV_ROUND_UP(min_dwell_time_active, 1000);
  97. max_dwell_time_active = DIV_ROUND_UP(max_dwell_time_active, 1000);
  98. dwell_time_passive = DIV_ROUND_UP(c->dwell_time_passive, 1000);
  99. dwell_time_dfs = DIV_ROUND_UP(c->dwell_time_dfs, 1000);
  100. for (i = 0, j = start;
  101. i < n_channels && j < max_channels;
  102. i++) {
  103. flags = req_channels[i]->flags;
  104. if (force_passive)
  105. flags |= IEEE80211_CHAN_PASSIVE_SCAN;
  106. if ((req_channels[i]->band == band) &&
  107. !(flags & IEEE80211_CHAN_DISABLED) &&
  108. (!!(flags & IEEE80211_CHAN_RADAR) == radar) &&
  109. /* if radar is set, we ignore the passive flag */
  110. (radar ||
  111. !!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) {
  112. wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
  113. req_channels[i]->band,
  114. req_channels[i]->center_freq);
  115. wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X",
  116. req_channels[i]->hw_value,
  117. req_channels[i]->flags);
  118. wl1271_debug(DEBUG_SCAN, "max_power %d",
  119. req_channels[i]->max_power);
  120. wl1271_debug(DEBUG_SCAN, "min_dwell_time %d max dwell time %d",
  121. min_dwell_time_active,
  122. max_dwell_time_active);
  123. if (flags & IEEE80211_CHAN_RADAR) {
  124. channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS;
  125. channels[j].passive_duration =
  126. cpu_to_le16(dwell_time_dfs);
  127. } else {
  128. channels[j].passive_duration =
  129. cpu_to_le16(dwell_time_passive);
  130. }
  131. channels[j].min_duration =
  132. cpu_to_le16(min_dwell_time_active);
  133. channels[j].max_duration =
  134. cpu_to_le16(max_dwell_time_active);
  135. channels[j].tx_power_att = req_channels[i]->max_power;
  136. channels[j].channel = req_channels[i]->hw_value;
  137. if (n_pactive_ch &&
  138. (band == IEEE80211_BAND_2GHZ) &&
  139. (channels[j].channel >= 12) &&
  140. (channels[j].channel <= 14) &&
  141. (flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
  142. !force_passive) {
  143. /* pactive channels treated as DFS */
  144. channels[j].flags = SCAN_CHANNEL_FLAGS_DFS;
  145. /*
  146. * n_pactive_ch is counted down from the end of
  147. * the passive channel list
  148. */
  149. (*n_pactive_ch)++;
  150. wl1271_debug(DEBUG_SCAN, "n_pactive_ch = %d",
  151. *n_pactive_ch);
  152. }
  153. j++;
  154. }
  155. }
  156. return j - start;
  157. }
  158. bool
  159. wlcore_set_scan_chan_params(struct wl1271 *wl,
  160. struct wlcore_scan_channels *cfg,
  161. struct ieee80211_channel *channels[],
  162. u32 n_channels,
  163. u32 n_ssids)
  164. {
  165. u8 n_pactive_ch = 0;
  166. cfg->passive[0] =
  167. wlcore_scan_get_channels(wl,
  168. channels,
  169. n_channels,
  170. n_ssids,
  171. cfg->channels_2,
  172. IEEE80211_BAND_2GHZ,
  173. false, true, 0,
  174. MAX_CHANNELS_2GHZ,
  175. &n_pactive_ch);
  176. cfg->active[0] =
  177. wlcore_scan_get_channels(wl,
  178. channels,
  179. n_channels,
  180. n_ssids,
  181. cfg->channels_2,
  182. IEEE80211_BAND_2GHZ,
  183. false, false,
  184. cfg->passive[0],
  185. MAX_CHANNELS_2GHZ,
  186. &n_pactive_ch);
  187. cfg->passive[1] =
  188. wlcore_scan_get_channels(wl,
  189. channels,
  190. n_channels,
  191. n_ssids,
  192. cfg->channels_5,
  193. IEEE80211_BAND_5GHZ,
  194. false, true, 0,
  195. MAX_CHANNELS_5GHZ,
  196. &n_pactive_ch);
  197. cfg->dfs =
  198. wlcore_scan_get_channels(wl,
  199. channels,
  200. n_channels,
  201. n_ssids,
  202. cfg->channels_5,
  203. IEEE80211_BAND_5GHZ,
  204. true, true,
  205. cfg->passive[1],
  206. MAX_CHANNELS_5GHZ,
  207. &n_pactive_ch);
  208. cfg->active[1] =
  209. wlcore_scan_get_channels(wl,
  210. channels,
  211. n_channels,
  212. n_ssids,
  213. cfg->channels_5,
  214. IEEE80211_BAND_5GHZ,
  215. false, false,
  216. cfg->passive[1] + cfg->dfs,
  217. MAX_CHANNELS_5GHZ,
  218. &n_pactive_ch);
  219. /* 802.11j channels are not supported yet */
  220. cfg->passive[2] = 0;
  221. cfg->active[2] = 0;
  222. cfg->passive_active = n_pactive_ch;
  223. wl1271_debug(DEBUG_SCAN, " 2.4GHz: active %d passive %d",
  224. cfg->active[0], cfg->passive[0]);
  225. wl1271_debug(DEBUG_SCAN, " 5GHz: active %d passive %d",
  226. cfg->active[1], cfg->passive[1]);
  227. wl1271_debug(DEBUG_SCAN, " DFS: %d", cfg->dfs);
  228. return cfg->passive[0] || cfg->active[0] ||
  229. cfg->passive[1] || cfg->active[1] || cfg->dfs ||
  230. cfg->passive[2] || cfg->active[2];
  231. }
  232. EXPORT_SYMBOL_GPL(wlcore_set_scan_chan_params);
  233. int wlcore_scan(struct wl1271 *wl, struct ieee80211_vif *vif,
  234. const u8 *ssid, size_t ssid_len,
  235. struct cfg80211_scan_request *req)
  236. {
  237. struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
  238. /*
  239. * cfg80211 should guarantee that we don't get more channels
  240. * than what we have registered.
  241. */
  242. BUG_ON(req->n_channels > WL1271_MAX_CHANNELS);
  243. if (wl->scan.state != WL1271_SCAN_STATE_IDLE)
  244. return -EBUSY;
  245. wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE;
  246. if (ssid_len && ssid) {
  247. wl->scan.ssid_len = ssid_len;
  248. memcpy(wl->scan.ssid, ssid, ssid_len);
  249. } else {
  250. wl->scan.ssid_len = 0;
  251. }
  252. wl->scan_vif = vif;
  253. wl->scan.req = req;
  254. memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
  255. /* we assume failure so that timeout scenarios are handled correctly */
  256. wl->scan.failed = true;
  257. ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
  258. msecs_to_jiffies(WL1271_SCAN_TIMEOUT));
  259. wl->ops->scan_start(wl, wlvif, req);
  260. return 0;
  261. }
  262. /* Returns the scan type to be used or a negative value on error */
  263. int
  264. wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl,
  265. struct wl12xx_vif *wlvif,
  266. struct cfg80211_sched_scan_request *req)
  267. {
  268. struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL;
  269. struct cfg80211_match_set *sets = req->match_sets;
  270. struct cfg80211_ssid *ssids = req->ssids;
  271. int ret = 0, type, i, j, n_match_ssids = 0;
  272. wl1271_debug(DEBUG_CMD, "cmd sched scan ssid list");
  273. /* count the match sets that contain SSIDs */
  274. for (i = 0; i < req->n_match_sets; i++)
  275. if (sets[i].ssid.ssid_len > 0)
  276. n_match_ssids++;
  277. /* No filter, no ssids or only bcast ssid */
  278. if (!n_match_ssids &&
  279. (!req->n_ssids ||
  280. (req->n_ssids == 1 && req->ssids[0].ssid_len == 0))) {
  281. type = SCAN_SSID_FILTER_ANY;
  282. goto out;
  283. }
  284. cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
  285. if (!cmd) {
  286. ret = -ENOMEM;
  287. goto out;
  288. }
  289. cmd->role_id = wlvif->role_id;
  290. if (!n_match_ssids) {
  291. /* No filter, with ssids */
  292. type = SCAN_SSID_FILTER_DISABLED;
  293. for (i = 0; i < req->n_ssids; i++) {
  294. cmd->ssids[cmd->n_ssids].type = (ssids[i].ssid_len) ?
  295. SCAN_SSID_TYPE_HIDDEN : SCAN_SSID_TYPE_PUBLIC;
  296. cmd->ssids[cmd->n_ssids].len = ssids[i].ssid_len;
  297. memcpy(cmd->ssids[cmd->n_ssids].ssid, ssids[i].ssid,
  298. ssids[i].ssid_len);
  299. cmd->n_ssids++;
  300. }
  301. } else {
  302. type = SCAN_SSID_FILTER_LIST;
  303. /* Add all SSIDs from the filters */
  304. for (i = 0; i < req->n_match_sets; i++) {
  305. /* ignore sets without SSIDs */
  306. if (!sets[i].ssid.ssid_len)
  307. continue;
  308. cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_PUBLIC;
  309. cmd->ssids[cmd->n_ssids].len = sets[i].ssid.ssid_len;
  310. memcpy(cmd->ssids[cmd->n_ssids].ssid,
  311. sets[i].ssid.ssid, sets[i].ssid.ssid_len);
  312. cmd->n_ssids++;
  313. }
  314. if ((req->n_ssids > 1) ||
  315. (req->n_ssids == 1 && req->ssids[0].ssid_len > 0)) {
  316. /*
  317. * Mark all the SSIDs passed in the SSID list as HIDDEN,
  318. * so they're used in probe requests.
  319. */
  320. for (i = 0; i < req->n_ssids; i++) {
  321. if (!req->ssids[i].ssid_len)
  322. continue;
  323. for (j = 0; j < cmd->n_ssids; j++)
  324. if ((req->ssids[i].ssid_len ==
  325. cmd->ssids[j].len) &&
  326. !memcmp(req->ssids[i].ssid,
  327. cmd->ssids[j].ssid,
  328. req->ssids[i].ssid_len)) {
  329. cmd->ssids[j].type =
  330. SCAN_SSID_TYPE_HIDDEN;
  331. break;
  332. }
  333. /* Fail if SSID isn't present in the filters */
  334. if (j == cmd->n_ssids) {
  335. ret = -EINVAL;
  336. goto out_free;
  337. }
  338. }
  339. }
  340. }
  341. wl1271_dump(DEBUG_SCAN, "SSID_LIST: ", cmd, sizeof(*cmd));
  342. ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_SSID_CFG, cmd,
  343. sizeof(*cmd), 0);
  344. if (ret < 0) {
  345. wl1271_error("cmd sched scan ssid list failed");
  346. goto out_free;
  347. }
  348. out_free:
  349. kfree(cmd);
  350. out:
  351. if (ret < 0)
  352. return ret;
  353. return type;
  354. }
  355. EXPORT_SYMBOL_GPL(wlcore_scan_sched_scan_ssid_list);
  356. void wl1271_scan_sched_scan_results(struct wl1271 *wl)
  357. {
  358. wl1271_debug(DEBUG_SCAN, "got periodic scan results");
  359. ieee80211_sched_scan_results(wl->hw);
  360. }