diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-scan.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-scan.c | 629 |
1 files changed, 629 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c new file mode 100644 index 00000000000..77e528f5db8 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c | |||
@@ -0,0 +1,629 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * GPL LICENSE SUMMARY | ||
4 | * | ||
5 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of version 2 of the GNU General Public License as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, | ||
19 | * USA | ||
20 | * | ||
21 | * The full GNU General Public License is included in this distribution | ||
22 | * in the file called LICENSE.GPL. | ||
23 | * | ||
24 | * Contact Information: | ||
25 | * Intel Linux Wireless <ilw@linux.intel.com> | ||
26 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
27 | *****************************************************************************/ | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/types.h> | ||
30 | #include <linux/etherdevice.h> | ||
31 | #include <net/mac80211.h> | ||
32 | |||
33 | #include "iwl-eeprom.h" | ||
34 | #include "iwl-dev.h" | ||
35 | #include "iwl-core.h" | ||
36 | #include "iwl-sta.h" | ||
37 | #include "iwl-io.h" | ||
38 | #include "iwl-helpers.h" | ||
39 | #include "iwl-agn.h" | ||
40 | #include "iwl-trans.h" | ||
41 | |||
42 | /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after | ||
43 | * sending probe req. This should be set long enough to hear probe responses | ||
44 | * from more than one AP. */ | ||
45 | #define IWL_ACTIVE_DWELL_TIME_24 (30) /* all times in msec */ | ||
46 | #define IWL_ACTIVE_DWELL_TIME_52 (20) | ||
47 | |||
48 | #define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3) | ||
49 | #define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2) | ||
50 | |||
51 | /* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. | ||
52 | * Must be set longer than active dwell time. | ||
53 | * For the most reliable scan, set > AP beacon interval (typically 100msec). */ | ||
54 | #define IWL_PASSIVE_DWELL_TIME_24 (20) /* all times in msec */ | ||
55 | #define IWL_PASSIVE_DWELL_TIME_52 (10) | ||
56 | #define IWL_PASSIVE_DWELL_BASE (100) | ||
57 | #define IWL_CHANNEL_TUNE_TIME 5 | ||
58 | |||
59 | static int iwl_send_scan_abort(struct iwl_priv *priv) | ||
60 | { | ||
61 | int ret; | ||
62 | struct iwl_rx_packet *pkt; | ||
63 | struct iwl_host_cmd cmd = { | ||
64 | .id = REPLY_SCAN_ABORT_CMD, | ||
65 | .flags = CMD_SYNC | CMD_WANT_SKB, | ||
66 | }; | ||
67 | |||
68 | /* Exit instantly with error when device is not ready | ||
69 | * to receive scan abort command or it does not perform | ||
70 | * hardware scan currently */ | ||
71 | if (!test_bit(STATUS_READY, &priv->status) || | ||
72 | !test_bit(STATUS_GEO_CONFIGURED, &priv->status) || | ||
73 | !test_bit(STATUS_SCAN_HW, &priv->status) || | ||
74 | test_bit(STATUS_FW_ERROR, &priv->status) || | ||
75 | test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
76 | return -EIO; | ||
77 | |||
78 | ret = trans_send_cmd(&priv->trans, &cmd); | ||
79 | if (ret) | ||
80 | return ret; | ||
81 | |||
82 | pkt = (struct iwl_rx_packet *)cmd.reply_page; | ||
83 | if (pkt->u.status != CAN_ABORT_STATUS) { | ||
84 | /* The scan abort will return 1 for success or | ||
85 | * 2 for "failure". A failure condition can be | ||
86 | * due to simply not being in an active scan which | ||
87 | * can occur if we send the scan abort before we | ||
88 | * the microcode has notified us that a scan is | ||
89 | * completed. */ | ||
90 | IWL_DEBUG_SCAN(priv, "SCAN_ABORT ret %d.\n", pkt->u.status); | ||
91 | ret = -EIO; | ||
92 | } | ||
93 | |||
94 | iwl_free_pages(priv, cmd.reply_page); | ||
95 | return ret; | ||
96 | } | ||
97 | |||
98 | static void iwl_complete_scan(struct iwl_priv *priv, bool aborted) | ||
99 | { | ||
100 | /* check if scan was requested from mac80211 */ | ||
101 | if (priv->scan_request) { | ||
102 | IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n"); | ||
103 | ieee80211_scan_completed(priv->hw, aborted); | ||
104 | } | ||
105 | |||
106 | priv->scan_type = IWL_SCAN_NORMAL; | ||
107 | priv->scan_vif = NULL; | ||
108 | priv->scan_request = NULL; | ||
109 | } | ||
110 | |||
111 | void iwl_force_scan_end(struct iwl_priv *priv) | ||
112 | { | ||
113 | lockdep_assert_held(&priv->mutex); | ||
114 | |||
115 | if (!test_bit(STATUS_SCANNING, &priv->status)) { | ||
116 | IWL_DEBUG_SCAN(priv, "Forcing scan end while not scanning\n"); | ||
117 | return; | ||
118 | } | ||
119 | |||
120 | IWL_DEBUG_SCAN(priv, "Forcing scan end\n"); | ||
121 | clear_bit(STATUS_SCANNING, &priv->status); | ||
122 | clear_bit(STATUS_SCAN_HW, &priv->status); | ||
123 | clear_bit(STATUS_SCAN_ABORTING, &priv->status); | ||
124 | iwl_complete_scan(priv, true); | ||
125 | } | ||
126 | |||
127 | static void iwl_do_scan_abort(struct iwl_priv *priv) | ||
128 | { | ||
129 | int ret; | ||
130 | |||
131 | lockdep_assert_held(&priv->mutex); | ||
132 | |||
133 | if (!test_bit(STATUS_SCANNING, &priv->status)) { | ||
134 | IWL_DEBUG_SCAN(priv, "Not performing scan to abort\n"); | ||
135 | return; | ||
136 | } | ||
137 | |||
138 | if (test_and_set_bit(STATUS_SCAN_ABORTING, &priv->status)) { | ||
139 | IWL_DEBUG_SCAN(priv, "Scan abort in progress\n"); | ||
140 | return; | ||
141 | } | ||
142 | |||
143 | ret = iwl_send_scan_abort(priv); | ||
144 | if (ret) { | ||
145 | IWL_DEBUG_SCAN(priv, "Send scan abort failed %d\n", ret); | ||
146 | iwl_force_scan_end(priv); | ||
147 | } else | ||
148 | IWL_DEBUG_SCAN(priv, "Successfully send scan abort\n"); | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * iwl_scan_cancel - Cancel any currently executing HW scan | ||
153 | */ | ||
154 | int iwl_scan_cancel(struct iwl_priv *priv) | ||
155 | { | ||
156 | IWL_DEBUG_SCAN(priv, "Queuing abort scan\n"); | ||
157 | queue_work(priv->workqueue, &priv->abort_scan); | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | /** | ||
162 | * iwl_scan_cancel_timeout - Cancel any currently executing HW scan | ||
163 | * @ms: amount of time to wait (in milliseconds) for scan to abort | ||
164 | * | ||
165 | */ | ||
166 | int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) | ||
167 | { | ||
168 | unsigned long timeout = jiffies + msecs_to_jiffies(ms); | ||
169 | |||
170 | lockdep_assert_held(&priv->mutex); | ||
171 | |||
172 | IWL_DEBUG_SCAN(priv, "Scan cancel timeout\n"); | ||
173 | |||
174 | iwl_do_scan_abort(priv); | ||
175 | |||
176 | while (time_before_eq(jiffies, timeout)) { | ||
177 | if (!test_bit(STATUS_SCAN_HW, &priv->status)) | ||
178 | break; | ||
179 | msleep(20); | ||
180 | } | ||
181 | |||
182 | return test_bit(STATUS_SCAN_HW, &priv->status); | ||
183 | } | ||
184 | |||
185 | /* Service response to REPLY_SCAN_CMD (0x80) */ | ||
186 | static void iwl_rx_reply_scan(struct iwl_priv *priv, | ||
187 | struct iwl_rx_mem_buffer *rxb) | ||
188 | { | ||
189 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
190 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
191 | struct iwl_scanreq_notification *notif = | ||
192 | (struct iwl_scanreq_notification *)pkt->u.raw; | ||
193 | |||
194 | IWL_DEBUG_SCAN(priv, "Scan request status = 0x%x\n", notif->status); | ||
195 | #endif | ||
196 | } | ||
197 | |||
198 | /* Service SCAN_START_NOTIFICATION (0x82) */ | ||
199 | static void iwl_rx_scan_start_notif(struct iwl_priv *priv, | ||
200 | struct iwl_rx_mem_buffer *rxb) | ||
201 | { | ||
202 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
203 | struct iwl_scanstart_notification *notif = | ||
204 | (struct iwl_scanstart_notification *)pkt->u.raw; | ||
205 | priv->scan_start_tsf = le32_to_cpu(notif->tsf_low); | ||
206 | IWL_DEBUG_SCAN(priv, "Scan start: " | ||
207 | "%d [802.11%s] " | ||
208 | "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n", | ||
209 | notif->channel, | ||
210 | notif->band ? "bg" : "a", | ||
211 | le32_to_cpu(notif->tsf_high), | ||
212 | le32_to_cpu(notif->tsf_low), | ||
213 | notif->status, notif->beacon_timer); | ||
214 | } | ||
215 | |||
216 | /* Service SCAN_RESULTS_NOTIFICATION (0x83) */ | ||
217 | static void iwl_rx_scan_results_notif(struct iwl_priv *priv, | ||
218 | struct iwl_rx_mem_buffer *rxb) | ||
219 | { | ||
220 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
221 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
222 | struct iwl_scanresults_notification *notif = | ||
223 | (struct iwl_scanresults_notification *)pkt->u.raw; | ||
224 | |||
225 | IWL_DEBUG_SCAN(priv, "Scan ch.res: " | ||
226 | "%d [802.11%s] " | ||
227 | "(TSF: 0x%08X:%08X) - %d " | ||
228 | "elapsed=%lu usec\n", | ||
229 | notif->channel, | ||
230 | notif->band ? "bg" : "a", | ||
231 | le32_to_cpu(notif->tsf_high), | ||
232 | le32_to_cpu(notif->tsf_low), | ||
233 | le32_to_cpu(notif->statistics[0]), | ||
234 | le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf); | ||
235 | #endif | ||
236 | } | ||
237 | |||
238 | /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ | ||
239 | static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, | ||
240 | struct iwl_rx_mem_buffer *rxb) | ||
241 | { | ||
242 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
243 | struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; | ||
244 | |||
245 | IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", | ||
246 | scan_notif->scanned_channels, | ||
247 | scan_notif->tsf_low, | ||
248 | scan_notif->tsf_high, scan_notif->status); | ||
249 | |||
250 | /* The HW is no longer scanning */ | ||
251 | clear_bit(STATUS_SCAN_HW, &priv->status); | ||
252 | |||
253 | IWL_DEBUG_SCAN(priv, "Scan on %sGHz took %dms\n", | ||
254 | (priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2", | ||
255 | jiffies_to_msecs(jiffies - priv->scan_start)); | ||
256 | |||
257 | queue_work(priv->workqueue, &priv->scan_completed); | ||
258 | |||
259 | if (priv->iw_mode != NL80211_IFTYPE_ADHOC && | ||
260 | iwl_advanced_bt_coexist(priv) && | ||
261 | priv->bt_status != scan_notif->bt_status) { | ||
262 | if (scan_notif->bt_status) { | ||
263 | /* BT on */ | ||
264 | if (!priv->bt_ch_announce) | ||
265 | priv->bt_traffic_load = | ||
266 | IWL_BT_COEX_TRAFFIC_LOAD_HIGH; | ||
267 | /* | ||
268 | * otherwise, no traffic load information provided | ||
269 | * no changes made | ||
270 | */ | ||
271 | } else { | ||
272 | /* BT off */ | ||
273 | priv->bt_traffic_load = | ||
274 | IWL_BT_COEX_TRAFFIC_LOAD_NONE; | ||
275 | } | ||
276 | priv->bt_status = scan_notif->bt_status; | ||
277 | queue_work(priv->workqueue, &priv->bt_traffic_change_work); | ||
278 | } | ||
279 | } | ||
280 | |||
281 | void iwl_setup_rx_scan_handlers(struct iwl_priv *priv) | ||
282 | { | ||
283 | /* scan handlers */ | ||
284 | priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan; | ||
285 | priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif; | ||
286 | priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] = | ||
287 | iwl_rx_scan_results_notif; | ||
288 | priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = | ||
289 | iwl_rx_scan_complete_notif; | ||
290 | } | ||
291 | |||
292 | inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, | ||
293 | enum ieee80211_band band, | ||
294 | u8 n_probes) | ||
295 | { | ||
296 | if (band == IEEE80211_BAND_5GHZ) | ||
297 | return IWL_ACTIVE_DWELL_TIME_52 + | ||
298 | IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1); | ||
299 | else | ||
300 | return IWL_ACTIVE_DWELL_TIME_24 + | ||
301 | IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1); | ||
302 | } | ||
303 | |||
304 | u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, | ||
305 | enum ieee80211_band band, | ||
306 | struct ieee80211_vif *vif) | ||
307 | { | ||
308 | struct iwl_rxon_context *ctx; | ||
309 | u16 passive = (band == IEEE80211_BAND_2GHZ) ? | ||
310 | IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : | ||
311 | IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; | ||
312 | |||
313 | if (iwl_is_any_associated(priv)) { | ||
314 | /* | ||
315 | * If we're associated, we clamp the maximum passive | ||
316 | * dwell time to be 98% of the smallest beacon interval | ||
317 | * (minus 2 * channel tune time) | ||
318 | */ | ||
319 | for_each_context(priv, ctx) { | ||
320 | u16 value; | ||
321 | |||
322 | if (!iwl_is_associated_ctx(ctx)) | ||
323 | continue; | ||
324 | value = ctx->vif ? ctx->vif->bss_conf.beacon_int : 0; | ||
325 | if ((value > IWL_PASSIVE_DWELL_BASE) || !value) | ||
326 | value = IWL_PASSIVE_DWELL_BASE; | ||
327 | value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; | ||
328 | passive = min(value, passive); | ||
329 | } | ||
330 | } | ||
331 | |||
332 | return passive; | ||
333 | } | ||
334 | |||
335 | void iwl_init_scan_params(struct iwl_priv *priv) | ||
336 | { | ||
337 | u8 ant_idx = fls(priv->hw_params.valid_tx_ant) - 1; | ||
338 | if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ]) | ||
339 | priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx; | ||
340 | if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ]) | ||
341 | priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx; | ||
342 | } | ||
343 | |||
344 | int __must_check iwl_scan_initiate(struct iwl_priv *priv, | ||
345 | struct ieee80211_vif *vif, | ||
346 | enum iwl_scan_type scan_type, | ||
347 | enum ieee80211_band band) | ||
348 | { | ||
349 | int ret; | ||
350 | |||
351 | lockdep_assert_held(&priv->mutex); | ||
352 | |||
353 | cancel_delayed_work(&priv->scan_check); | ||
354 | |||
355 | if (!iwl_is_ready_rf(priv)) { | ||
356 | IWL_WARN(priv, "Request scan called when driver not ready.\n"); | ||
357 | return -EIO; | ||
358 | } | ||
359 | |||
360 | if (test_bit(STATUS_SCAN_HW, &priv->status)) { | ||
361 | IWL_DEBUG_SCAN(priv, | ||
362 | "Multiple concurrent scan requests in parallel.\n"); | ||
363 | return -EBUSY; | ||
364 | } | ||
365 | |||
366 | if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { | ||
367 | IWL_DEBUG_SCAN(priv, "Scan request while abort pending.\n"); | ||
368 | return -EBUSY; | ||
369 | } | ||
370 | |||
371 | IWL_DEBUG_SCAN(priv, "Starting %sscan...\n", | ||
372 | scan_type == IWL_SCAN_NORMAL ? "" : | ||
373 | scan_type == IWL_SCAN_OFFCH_TX ? "offchan TX " : | ||
374 | "internal short "); | ||
375 | |||
376 | set_bit(STATUS_SCANNING, &priv->status); | ||
377 | priv->scan_type = scan_type; | ||
378 | priv->scan_start = jiffies; | ||
379 | priv->scan_band = band; | ||
380 | |||
381 | ret = iwlagn_request_scan(priv, vif); | ||
382 | if (ret) { | ||
383 | clear_bit(STATUS_SCANNING, &priv->status); | ||
384 | priv->scan_type = IWL_SCAN_NORMAL; | ||
385 | return ret; | ||
386 | } | ||
387 | |||
388 | queue_delayed_work(priv->workqueue, &priv->scan_check, | ||
389 | IWL_SCAN_CHECK_WATCHDOG); | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | int iwl_mac_hw_scan(struct ieee80211_hw *hw, | ||
395 | struct ieee80211_vif *vif, | ||
396 | struct cfg80211_scan_request *req) | ||
397 | { | ||
398 | struct iwl_priv *priv = hw->priv; | ||
399 | int ret; | ||
400 | |||
401 | IWL_DEBUG_MAC80211(priv, "enter\n"); | ||
402 | |||
403 | if (req->n_channels == 0) | ||
404 | return -EINVAL; | ||
405 | |||
406 | mutex_lock(&priv->mutex); | ||
407 | |||
408 | /* | ||
409 | * If an internal scan is in progress, just set | ||
410 | * up the scan_request as per above. | ||
411 | */ | ||
412 | if (priv->scan_type != IWL_SCAN_NORMAL) { | ||
413 | IWL_DEBUG_SCAN(priv, | ||
414 | "SCAN request during internal scan - defer\n"); | ||
415 | priv->scan_request = req; | ||
416 | priv->scan_vif = vif; | ||
417 | ret = 0; | ||
418 | } else { | ||
419 | priv->scan_request = req; | ||
420 | priv->scan_vif = vif; | ||
421 | /* | ||
422 | * mac80211 will only ask for one band at a time | ||
423 | * so using channels[0] here is ok | ||
424 | */ | ||
425 | ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL, | ||
426 | req->channels[0]->band); | ||
427 | if (ret) { | ||
428 | priv->scan_request = NULL; | ||
429 | priv->scan_vif = NULL; | ||
430 | } | ||
431 | } | ||
432 | |||
433 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
434 | |||
435 | mutex_unlock(&priv->mutex); | ||
436 | |||
437 | return ret; | ||
438 | } | ||
439 | |||
440 | /* | ||
441 | * internal short scan, this function should only been called while associated. | ||
442 | * It will reset and tune the radio to prevent possible RF related problem | ||
443 | */ | ||
444 | void iwl_internal_short_hw_scan(struct iwl_priv *priv) | ||
445 | { | ||
446 | queue_work(priv->workqueue, &priv->start_internal_scan); | ||
447 | } | ||
448 | |||
449 | static void iwl_bg_start_internal_scan(struct work_struct *work) | ||
450 | { | ||
451 | struct iwl_priv *priv = | ||
452 | container_of(work, struct iwl_priv, start_internal_scan); | ||
453 | |||
454 | IWL_DEBUG_SCAN(priv, "Start internal scan\n"); | ||
455 | |||
456 | mutex_lock(&priv->mutex); | ||
457 | |||
458 | if (priv->scan_type == IWL_SCAN_RADIO_RESET) { | ||
459 | IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n"); | ||
460 | goto unlock; | ||
461 | } | ||
462 | |||
463 | if (test_bit(STATUS_SCANNING, &priv->status)) { | ||
464 | IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); | ||
465 | goto unlock; | ||
466 | } | ||
467 | |||
468 | if (iwl_scan_initiate(priv, NULL, IWL_SCAN_RADIO_RESET, priv->band)) | ||
469 | IWL_DEBUG_SCAN(priv, "failed to start internal short scan\n"); | ||
470 | unlock: | ||
471 | mutex_unlock(&priv->mutex); | ||
472 | } | ||
473 | |||
474 | static void iwl_bg_scan_check(struct work_struct *data) | ||
475 | { | ||
476 | struct iwl_priv *priv = | ||
477 | container_of(data, struct iwl_priv, scan_check.work); | ||
478 | |||
479 | IWL_DEBUG_SCAN(priv, "Scan check work\n"); | ||
480 | |||
481 | /* Since we are here firmware does not finish scan and | ||
482 | * most likely is in bad shape, so we don't bother to | ||
483 | * send abort command, just force scan complete to mac80211 */ | ||
484 | mutex_lock(&priv->mutex); | ||
485 | iwl_force_scan_end(priv); | ||
486 | mutex_unlock(&priv->mutex); | ||
487 | } | ||
488 | |||
489 | /** | ||
490 | * iwl_fill_probe_req - fill in all required fields and IE for probe request | ||
491 | */ | ||
492 | |||
493 | u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, | ||
494 | const u8 *ta, const u8 *ies, int ie_len, int left) | ||
495 | { | ||
496 | int len = 0; | ||
497 | u8 *pos = NULL; | ||
498 | |||
499 | /* Make sure there is enough space for the probe request, | ||
500 | * two mandatory IEs and the data */ | ||
501 | left -= 24; | ||
502 | if (left < 0) | ||
503 | return 0; | ||
504 | |||
505 | frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); | ||
506 | memcpy(frame->da, iwl_bcast_addr, ETH_ALEN); | ||
507 | memcpy(frame->sa, ta, ETH_ALEN); | ||
508 | memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN); | ||
509 | frame->seq_ctrl = 0; | ||
510 | |||
511 | len += 24; | ||
512 | |||
513 | /* ...next IE... */ | ||
514 | pos = &frame->u.probe_req.variable[0]; | ||
515 | |||
516 | /* fill in our indirect SSID IE */ | ||
517 | left -= 2; | ||
518 | if (left < 0) | ||
519 | return 0; | ||
520 | *pos++ = WLAN_EID_SSID; | ||
521 | *pos++ = 0; | ||
522 | |||
523 | len += 2; | ||
524 | |||
525 | if (WARN_ON(left < ie_len)) | ||
526 | return len; | ||
527 | |||
528 | if (ies && ie_len) { | ||
529 | memcpy(pos, ies, ie_len); | ||
530 | len += ie_len; | ||
531 | } | ||
532 | |||
533 | return (u16)len; | ||
534 | } | ||
535 | |||
536 | static void iwl_bg_abort_scan(struct work_struct *work) | ||
537 | { | ||
538 | struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan); | ||
539 | |||
540 | IWL_DEBUG_SCAN(priv, "Abort scan work\n"); | ||
541 | |||
542 | /* We keep scan_check work queued in case when firmware will not | ||
543 | * report back scan completed notification */ | ||
544 | mutex_lock(&priv->mutex); | ||
545 | iwl_scan_cancel_timeout(priv, 200); | ||
546 | mutex_unlock(&priv->mutex); | ||
547 | } | ||
548 | |||
549 | static void iwl_bg_scan_completed(struct work_struct *work) | ||
550 | { | ||
551 | struct iwl_priv *priv = | ||
552 | container_of(work, struct iwl_priv, scan_completed); | ||
553 | bool aborted; | ||
554 | |||
555 | IWL_DEBUG_SCAN(priv, "Completed scan.\n"); | ||
556 | |||
557 | cancel_delayed_work(&priv->scan_check); | ||
558 | |||
559 | mutex_lock(&priv->mutex); | ||
560 | |||
561 | aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status); | ||
562 | if (aborted) | ||
563 | IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n"); | ||
564 | |||
565 | if (!test_and_clear_bit(STATUS_SCANNING, &priv->status)) { | ||
566 | IWL_DEBUG_SCAN(priv, "Scan already completed.\n"); | ||
567 | goto out_settings; | ||
568 | } | ||
569 | |||
570 | if (priv->scan_type == IWL_SCAN_OFFCH_TX && priv->offchan_tx_skb) { | ||
571 | ieee80211_tx_status_irqsafe(priv->hw, | ||
572 | priv->offchan_tx_skb); | ||
573 | priv->offchan_tx_skb = NULL; | ||
574 | } | ||
575 | |||
576 | if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) { | ||
577 | int err; | ||
578 | |||
579 | /* Check if mac80211 requested scan during our internal scan */ | ||
580 | if (priv->scan_request == NULL) | ||
581 | goto out_complete; | ||
582 | |||
583 | /* If so request a new scan */ | ||
584 | err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL, | ||
585 | priv->scan_request->channels[0]->band); | ||
586 | if (err) { | ||
587 | IWL_DEBUG_SCAN(priv, | ||
588 | "failed to initiate pending scan: %d\n", err); | ||
589 | aborted = true; | ||
590 | goto out_complete; | ||
591 | } | ||
592 | |||
593 | goto out; | ||
594 | } | ||
595 | |||
596 | out_complete: | ||
597 | iwl_complete_scan(priv, aborted); | ||
598 | |||
599 | out_settings: | ||
600 | /* Can we still talk to firmware ? */ | ||
601 | if (!iwl_is_ready_rf(priv)) | ||
602 | goto out; | ||
603 | |||
604 | iwlagn_post_scan(priv); | ||
605 | |||
606 | out: | ||
607 | mutex_unlock(&priv->mutex); | ||
608 | } | ||
609 | |||
610 | void iwl_setup_scan_deferred_work(struct iwl_priv *priv) | ||
611 | { | ||
612 | INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); | ||
613 | INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan); | ||
614 | INIT_WORK(&priv->start_internal_scan, iwl_bg_start_internal_scan); | ||
615 | INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check); | ||
616 | } | ||
617 | |||
618 | void iwl_cancel_scan_deferred_work(struct iwl_priv *priv) | ||
619 | { | ||
620 | cancel_work_sync(&priv->start_internal_scan); | ||
621 | cancel_work_sync(&priv->abort_scan); | ||
622 | cancel_work_sync(&priv->scan_completed); | ||
623 | |||
624 | if (cancel_delayed_work_sync(&priv->scan_check)) { | ||
625 | mutex_lock(&priv->mutex); | ||
626 | iwl_force_scan_end(priv); | ||
627 | mutex_unlock(&priv->mutex); | ||
628 | } | ||
629 | } | ||