diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/ibss.c | 22 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 6 | ||||
-rw-r--r-- | net/mac80211/main.c | 2 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 28 | ||||
-rw-r--r-- | net/mac80211/scan.c | 387 |
5 files changed, 229 insertions, 216 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 9fe1f937e0b4..25ff583612ef 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -432,15 +432,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) | |||
432 | printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " | 432 | printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " |
433 | "IBSS networks with same SSID (merge)\n", sdata->dev->name); | 433 | "IBSS networks with same SSID (merge)\n", sdata->dev->name); |
434 | 434 | ||
435 | /* XXX maybe racy? */ | 435 | ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len); |
436 | if (sdata->local->scan_req) | ||
437 | return; | ||
438 | |||
439 | memcpy(sdata->local->int_scan_req.ssids[0].ssid, | ||
440 | ifibss->ssid, IEEE80211_MAX_SSID_LEN); | ||
441 | sdata->local->int_scan_req.ssids[0].ssid_len = ifibss->ssid_len; | ||
442 | if (ieee80211_request_scan(sdata, &sdata->local->int_scan_req)) | ||
443 | ieee80211_scan_failed(sdata->local); | ||
444 | } | 436 | } |
445 | 437 | ||
446 | static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | 438 | static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) |
@@ -553,16 +545,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
553 | printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " | 545 | printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " |
554 | "join\n", sdata->dev->name); | 546 | "join\n", sdata->dev->name); |
555 | 547 | ||
556 | /* XXX maybe racy? */ | 548 | ieee80211_request_internal_scan(sdata, ifibss->ssid, |
557 | if (local->scan_req) | 549 | ifibss->ssid_len); |
558 | return; | ||
559 | |||
560 | memcpy(local->int_scan_req.ssids[0].ssid, | ||
561 | ifibss->ssid, IEEE80211_MAX_SSID_LEN); | ||
562 | local->int_scan_req.ssids[0].ssid_len = | ||
563 | ifibss->ssid_len; | ||
564 | if (ieee80211_request_scan(sdata, &local->int_scan_req)) | ||
565 | ieee80211_scan_failed(local); | ||
566 | } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) { | 550 | } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) { |
567 | int interval = IEEE80211_SCAN_INTERVAL; | 551 | int interval = IEEE80211_SCAN_INTERVAL; |
568 | 552 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 1579bc92c88d..e6fd4bcf1c3c 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -659,6 +659,7 @@ struct ieee80211_local { | |||
659 | 659 | ||
660 | 660 | ||
661 | /* Scanning and BSS list */ | 661 | /* Scanning and BSS list */ |
662 | struct mutex scan_mtx; | ||
662 | bool sw_scanning, hw_scanning; | 663 | bool sw_scanning, hw_scanning; |
663 | struct cfg80211_ssid scan_ssid; | 664 | struct cfg80211_ssid scan_ssid; |
664 | struct cfg80211_scan_request int_scan_req; | 665 | struct cfg80211_scan_request int_scan_req; |
@@ -947,6 +948,8 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); | |||
947 | 948 | ||
948 | /* scan/BSS handling */ | 949 | /* scan/BSS handling */ |
949 | void ieee80211_scan_work(struct work_struct *work); | 950 | void ieee80211_scan_work(struct work_struct *work); |
951 | int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, | ||
952 | const u8 *ssid, u8 ssid_len); | ||
950 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | 953 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, |
951 | struct cfg80211_scan_request *req); | 954 | struct cfg80211_scan_request *req); |
952 | int ieee80211_scan_results(struct ieee80211_local *local, | 955 | int ieee80211_scan_results(struct ieee80211_local *local, |
@@ -960,9 +963,6 @@ int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, | |||
960 | const char *ie, size_t len); | 963 | const char *ie, size_t len); |
961 | 964 | ||
962 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); | 965 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); |
963 | void ieee80211_scan_failed(struct ieee80211_local *local); | ||
964 | int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, | ||
965 | struct cfg80211_scan_request *req); | ||
966 | struct ieee80211_bss * | 966 | struct ieee80211_bss * |
967 | ieee80211_bss_info_update(struct ieee80211_local *local, | 967 | ieee80211_bss_info_update(struct ieee80211_local *local, |
968 | struct ieee80211_rx_status *rx_status, | 968 | struct ieee80211_rx_status *rx_status, |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 5ca62ea15079..e00d124e4ef7 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -783,6 +783,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
783 | 783 | ||
784 | INIT_LIST_HEAD(&local->interfaces); | 784 | INIT_LIST_HEAD(&local->interfaces); |
785 | mutex_init(&local->iflist_mtx); | 785 | mutex_init(&local->iflist_mtx); |
786 | mutex_init(&local->scan_mtx); | ||
786 | 787 | ||
787 | spin_lock_init(&local->key_lock); | 788 | spin_lock_init(&local->key_lock); |
788 | 789 | ||
@@ -1126,6 +1127,7 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) | |||
1126 | struct ieee80211_local *local = hw_to_local(hw); | 1127 | struct ieee80211_local *local = hw_to_local(hw); |
1127 | 1128 | ||
1128 | mutex_destroy(&local->iflist_mtx); | 1129 | mutex_destroy(&local->iflist_mtx); |
1130 | mutex_destroy(&local->scan_mtx); | ||
1129 | 1131 | ||
1130 | wiphy_free(local->hw.wiphy); | 1132 | wiphy_free(local->hw.wiphy); |
1131 | } | 1133 | } |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index f8925ca7c8f0..a2f5e6223059 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -2072,19 +2072,15 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata) | |||
2072 | return 0; | 2072 | return 0; |
2073 | } else { | 2073 | } else { |
2074 | if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { | 2074 | if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { |
2075 | u8 ssid_len = 0; | ||
2076 | |||
2077 | if (!(ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL)) | ||
2078 | ssid_len = ifmgd->ssid_len; | ||
2079 | |||
2075 | ifmgd->assoc_scan_tries++; | 2080 | ifmgd->assoc_scan_tries++; |
2076 | /* XXX maybe racy? */ | ||
2077 | if (local->scan_req) | ||
2078 | return -1; | ||
2079 | memcpy(local->int_scan_req.ssids[0].ssid, | ||
2080 | ifmgd->ssid, IEEE80211_MAX_SSID_LEN); | ||
2081 | if (ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL) | ||
2082 | local->int_scan_req.ssids[0].ssid_len = 0; | ||
2083 | else | ||
2084 | local->int_scan_req.ssids[0].ssid_len = ifmgd->ssid_len; | ||
2085 | 2081 | ||
2086 | if (ieee80211_start_scan(sdata, &local->int_scan_req)) | 2082 | ieee80211_request_internal_scan(sdata, ifmgd->ssid, |
2087 | ieee80211_scan_failed(local); | 2083 | ssid_len); |
2088 | 2084 | ||
2089 | ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; | 2085 | ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; |
2090 | set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); | 2086 | set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); |
@@ -2122,14 +2118,8 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2122 | ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE && | 2118 | ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE && |
2123 | ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE && | 2119 | ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE && |
2124 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) { | 2120 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) { |
2125 | /* | 2121 | queue_delayed_work(local->hw.workqueue, &local->scan_work, |
2126 | * The call to ieee80211_start_scan can fail but ieee80211_request_scan | 2122 | round_jiffies_relative(0)); |
2127 | * (which queued ieee80211_sta_work) did not return an error. Thus, call | ||
2128 | * ieee80211_scan_failed here if ieee80211_start_scan fails in order to | ||
2129 | * notify the scan requester. | ||
2130 | */ | ||
2131 | if (ieee80211_start_scan(sdata, local->scan_req)) | ||
2132 | ieee80211_scan_failed(local); | ||
2133 | return; | 2123 | return; |
2134 | } | 2124 | } |
2135 | 2125 | ||
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index f25b07feabf9..086d21645cbc 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -202,18 +202,6 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | |||
202 | return RX_QUEUED; | 202 | return RX_QUEUED; |
203 | } | 203 | } |
204 | 204 | ||
205 | void ieee80211_scan_failed(struct ieee80211_local *local) | ||
206 | { | ||
207 | if (WARN_ON(!local->scan_req)) | ||
208 | return; | ||
209 | |||
210 | /* notify cfg80211 about the failed scan */ | ||
211 | if (local->scan_req != &local->int_scan_req) | ||
212 | cfg80211_scan_done(local->scan_req, true); | ||
213 | |||
214 | local->scan_req = NULL; | ||
215 | } | ||
216 | |||
217 | /* | 205 | /* |
218 | * inform AP that we will go to sleep so that it will buffer the frames | 206 | * inform AP that we will go to sleep so that it will buffer the frames |
219 | * while we scan | 207 | * while we scan |
@@ -274,29 +262,46 @@ static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata) | |||
274 | } | 262 | } |
275 | } | 263 | } |
276 | 264 | ||
265 | static void ieee80211_restore_scan_ies(struct ieee80211_local *local) | ||
266 | { | ||
267 | kfree(local->scan_req->ie); | ||
268 | local->scan_req->ie = local->orig_ies; | ||
269 | local->scan_req->ie_len = local->orig_ies_len; | ||
270 | } | ||
271 | |||
277 | void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | 272 | void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) |
278 | { | 273 | { |
279 | struct ieee80211_local *local = hw_to_local(hw); | 274 | struct ieee80211_local *local = hw_to_local(hw); |
280 | struct ieee80211_sub_if_data *sdata; | 275 | struct ieee80211_sub_if_data *sdata; |
276 | bool was_hw_scan; | ||
281 | 277 | ||
282 | if (WARN_ON(!local->hw_scanning && !local->sw_scanning)) | 278 | mutex_lock(&local->scan_mtx); |
283 | return; | ||
284 | 279 | ||
285 | if (WARN_ON(!local->scan_req)) | 280 | if (WARN_ON(!local->hw_scanning && !local->sw_scanning)) { |
281 | mutex_unlock(&local->scan_mtx); | ||
286 | return; | 282 | return; |
283 | } | ||
287 | 284 | ||
288 | if (local->hw_scanning) { | 285 | if (WARN_ON(!local->scan_req)) { |
289 | kfree(local->scan_req->ie); | 286 | mutex_unlock(&local->scan_mtx); |
290 | local->scan_req->ie = local->orig_ies; | 287 | return; |
291 | local->scan_req->ie_len = local->orig_ies_len; | ||
292 | } | 288 | } |
293 | 289 | ||
290 | if (local->hw_scanning) | ||
291 | ieee80211_restore_scan_ies(local); | ||
292 | |||
294 | if (local->scan_req != &local->int_scan_req) | 293 | if (local->scan_req != &local->int_scan_req) |
295 | cfg80211_scan_done(local->scan_req, aborted); | 294 | cfg80211_scan_done(local->scan_req, aborted); |
296 | local->scan_req = NULL; | 295 | local->scan_req = NULL; |
297 | 296 | ||
298 | if (local->hw_scanning) { | 297 | was_hw_scan = local->hw_scanning; |
299 | local->hw_scanning = false; | 298 | local->hw_scanning = false; |
299 | local->sw_scanning = false; | ||
300 | |||
301 | /* we only have to protect scan_req and hw/sw scan */ | ||
302 | mutex_unlock(&local->scan_mtx); | ||
303 | |||
304 | if (was_hw_scan) { | ||
300 | /* | 305 | /* |
301 | * Somebody might have requested channel change during scan | 306 | * Somebody might have requested channel change during scan |
302 | * that we won't have acted upon, try now. ieee80211_hw_config | 307 | * that we won't have acted upon, try now. ieee80211_hw_config |
@@ -306,7 +311,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
306 | goto done; | 311 | goto done; |
307 | } | 312 | } |
308 | 313 | ||
309 | local->sw_scanning = false; | ||
310 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 314 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); |
311 | 315 | ||
312 | netif_tx_lock_bh(local->mdev); | 316 | netif_tx_lock_bh(local->mdev); |
@@ -354,6 +358,146 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
354 | } | 358 | } |
355 | EXPORT_SYMBOL(ieee80211_scan_completed); | 359 | EXPORT_SYMBOL(ieee80211_scan_completed); |
356 | 360 | ||
361 | static int ieee80211_start_sw_scan(struct ieee80211_local *local) | ||
362 | { | ||
363 | struct ieee80211_sub_if_data *sdata; | ||
364 | |||
365 | /* | ||
366 | * Hardware/driver doesn't support hw_scan, so use software | ||
367 | * scanning instead. First send a nullfunc frame with power save | ||
368 | * bit on so that AP will buffer the frames for us while we are not | ||
369 | * listening, then send probe requests to each channel and wait for | ||
370 | * the responses. After all channels are scanned, tune back to the | ||
371 | * original channel and send a nullfunc frame with power save bit | ||
372 | * off to trigger the AP to send us all the buffered frames. | ||
373 | * | ||
374 | * Note that while local->sw_scanning is true everything else but | ||
375 | * nullfunc frames and probe requests will be dropped in | ||
376 | * ieee80211_tx_h_check_assoc(). | ||
377 | */ | ||
378 | if (local->ops->sw_scan_start) | ||
379 | local->ops->sw_scan_start(local_to_hw(local)); | ||
380 | |||
381 | mutex_lock(&local->iflist_mtx); | ||
382 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
383 | if (!netif_running(sdata->dev)) | ||
384 | continue; | ||
385 | |||
386 | /* disable beaconing */ | ||
387 | if (sdata->vif.type == NL80211_IFTYPE_AP || | ||
388 | sdata->vif.type == NL80211_IFTYPE_ADHOC || | ||
389 | sdata->vif.type == NL80211_IFTYPE_MESH_POINT) | ||
390 | ieee80211_if_config(sdata, | ||
391 | IEEE80211_IFCC_BEACON_ENABLED); | ||
392 | |||
393 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
394 | if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { | ||
395 | netif_tx_stop_all_queues(sdata->dev); | ||
396 | ieee80211_scan_ps_enable(sdata); | ||
397 | } | ||
398 | } else | ||
399 | netif_tx_stop_all_queues(sdata->dev); | ||
400 | } | ||
401 | mutex_unlock(&local->iflist_mtx); | ||
402 | |||
403 | local->scan_state = SCAN_SET_CHANNEL; | ||
404 | local->scan_channel_idx = 0; | ||
405 | |||
406 | netif_addr_lock_bh(local->mdev); | ||
407 | local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; | ||
408 | local->ops->configure_filter(local_to_hw(local), | ||
409 | FIF_BCN_PRBRESP_PROMISC, | ||
410 | &local->filter_flags, | ||
411 | local->mdev->mc_count, | ||
412 | local->mdev->mc_list); | ||
413 | netif_addr_unlock_bh(local->mdev); | ||
414 | |||
415 | /* TODO: start scan as soon as all nullfunc frames are ACKed */ | ||
416 | queue_delayed_work(local->hw.workqueue, &local->scan_work, | ||
417 | IEEE80211_CHANNEL_TIME); | ||
418 | |||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | |||
423 | static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | ||
424 | struct cfg80211_scan_request *req) | ||
425 | { | ||
426 | struct ieee80211_local *local = sdata->local; | ||
427 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
428 | int rc; | ||
429 | |||
430 | if (local->scan_req) | ||
431 | return -EBUSY; | ||
432 | |||
433 | if (local->ops->hw_scan) { | ||
434 | u8 *ies; | ||
435 | int ielen; | ||
436 | |||
437 | ies = kmalloc(2 + IEEE80211_MAX_SSID_LEN + | ||
438 | local->scan_ies_len + req->ie_len, GFP_KERNEL); | ||
439 | if (!ies) | ||
440 | return -ENOMEM; | ||
441 | |||
442 | ielen = ieee80211_build_preq_ies(local, ies, | ||
443 | req->ie, req->ie_len); | ||
444 | local->orig_ies = req->ie; | ||
445 | local->orig_ies_len = req->ie_len; | ||
446 | req->ie = ies; | ||
447 | req->ie_len = ielen; | ||
448 | } | ||
449 | |||
450 | local->scan_req = req; | ||
451 | local->scan_sdata = sdata; | ||
452 | |||
453 | if (req != &local->int_scan_req && | ||
454 | sdata->vif.type == NL80211_IFTYPE_STATION && | ||
455 | (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE || | ||
456 | ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE || | ||
457 | ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE)) { | ||
458 | /* actually wait for the assoc to finish/time out */ | ||
459 | set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request); | ||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | if (local->ops->hw_scan) | ||
464 | local->hw_scanning = true; | ||
465 | else | ||
466 | local->sw_scanning = true; | ||
467 | /* | ||
468 | * Kicking off the scan need not be protected, | ||
469 | * only the scan variable stuff, since now | ||
470 | * local->scan_req is assigned and other callers | ||
471 | * will abort their scan attempts. | ||
472 | * | ||
473 | * This avoids getting a scan_mtx -> iflist_mtx | ||
474 | * dependency, so that the scan completed calls | ||
475 | * have more locking freedom. | ||
476 | */ | ||
477 | mutex_unlock(&local->scan_mtx); | ||
478 | |||
479 | if (local->ops->hw_scan) | ||
480 | rc = local->ops->hw_scan(local_to_hw(local), | ||
481 | local->scan_req); | ||
482 | else | ||
483 | rc = ieee80211_start_sw_scan(local); | ||
484 | |||
485 | mutex_lock(&local->scan_mtx); | ||
486 | |||
487 | if (rc) { | ||
488 | if (local->ops->hw_scan) { | ||
489 | local->hw_scanning = false; | ||
490 | ieee80211_restore_scan_ies(local); | ||
491 | } else | ||
492 | local->sw_scanning = false; | ||
493 | |||
494 | local->scan_req = NULL; | ||
495 | local->scan_sdata = NULL; | ||
496 | } | ||
497 | |||
498 | return rc; | ||
499 | } | ||
500 | |||
357 | void ieee80211_scan_work(struct work_struct *work) | 501 | void ieee80211_scan_work(struct work_struct *work) |
358 | { | 502 | { |
359 | struct ieee80211_local *local = | 503 | struct ieee80211_local *local = |
@@ -363,17 +507,41 @@ void ieee80211_scan_work(struct work_struct *work) | |||
363 | int skip, i; | 507 | int skip, i; |
364 | unsigned long next_delay = 0; | 508 | unsigned long next_delay = 0; |
365 | 509 | ||
510 | mutex_lock(&local->scan_mtx); | ||
511 | if (!sdata || !local->scan_req) { | ||
512 | mutex_unlock(&local->scan_mtx); | ||
513 | return; | ||
514 | } | ||
515 | |||
516 | if (local->scan_req && !(local->sw_scanning || local->hw_scanning)) { | ||
517 | struct cfg80211_scan_request *req = local->scan_req; | ||
518 | int rc; | ||
519 | |||
520 | local->scan_req = NULL; | ||
521 | |||
522 | rc = __ieee80211_start_scan(sdata, req); | ||
523 | mutex_unlock(&local->scan_mtx); | ||
524 | |||
525 | if (rc) | ||
526 | ieee80211_scan_completed(&local->hw, true); | ||
527 | return; | ||
528 | } | ||
529 | |||
530 | mutex_unlock(&local->scan_mtx); | ||
531 | |||
366 | /* | 532 | /* |
367 | * Avoid re-scheduling when the sdata is going away. | 533 | * Avoid re-scheduling when the sdata is going away. |
368 | */ | 534 | */ |
369 | if (!netif_running(sdata->dev)) | 535 | if (!netif_running(sdata->dev)) { |
536 | ieee80211_scan_completed(&local->hw, true); | ||
370 | return; | 537 | return; |
538 | } | ||
371 | 539 | ||
372 | switch (local->scan_state) { | 540 | switch (local->scan_state) { |
373 | case SCAN_SET_CHANNEL: | 541 | case SCAN_SET_CHANNEL: |
374 | /* if no more bands/channels left, complete scan */ | 542 | /* if no more bands/channels left, complete scan */ |
375 | if (local->scan_channel_idx >= local->scan_req->n_channels) { | 543 | if (local->scan_channel_idx >= local->scan_req->n_channels) { |
376 | ieee80211_scan_completed(local_to_hw(local), false); | 544 | ieee80211_scan_completed(&local->hw, false); |
377 | return; | 545 | return; |
378 | } | 546 | } |
379 | skip = 0; | 547 | skip = 0; |
@@ -422,166 +590,35 @@ void ieee80211_scan_work(struct work_struct *work) | |||
422 | next_delay); | 590 | next_delay); |
423 | } | 591 | } |
424 | 592 | ||
425 | 593 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | |
426 | int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, | 594 | struct cfg80211_scan_request *req) |
427 | struct cfg80211_scan_request *req) | ||
428 | { | 595 | { |
429 | struct ieee80211_local *local = scan_sdata->local; | 596 | int res; |
430 | struct ieee80211_sub_if_data *sdata; | ||
431 | |||
432 | if (!req) | ||
433 | return -EINVAL; | ||
434 | |||
435 | if (local->scan_req && local->scan_req != req) | ||
436 | return -EBUSY; | ||
437 | |||
438 | local->scan_req = req; | ||
439 | |||
440 | /* MLME-SCAN.request (page 118) page 144 (11.1.3.1) | ||
441 | * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS | ||
442 | * BSSID: MACAddress | ||
443 | * SSID | ||
444 | * ScanType: ACTIVE, PASSIVE | ||
445 | * ProbeDelay: delay (in microseconds) to be used prior to transmitting | ||
446 | * a Probe frame during active scanning | ||
447 | * ChannelList | ||
448 | * MinChannelTime (>= ProbeDelay), in TU | ||
449 | * MaxChannelTime: (>= MinChannelTime), in TU | ||
450 | */ | ||
451 | |||
452 | /* MLME-SCAN.confirm | ||
453 | * BSSDescriptionSet | ||
454 | * ResultCode: SUCCESS, INVALID_PARAMETERS | ||
455 | */ | ||
456 | |||
457 | if (local->sw_scanning || local->hw_scanning) { | ||
458 | if (local->scan_sdata == scan_sdata) | ||
459 | return 0; | ||
460 | return -EBUSY; | ||
461 | } | ||
462 | |||
463 | if (local->ops->hw_scan) { | ||
464 | u8 *ies; | ||
465 | int rc, ielen; | ||
466 | |||
467 | ies = kmalloc(2 + IEEE80211_MAX_SSID_LEN + | ||
468 | local->scan_ies_len + req->ie_len, GFP_KERNEL); | ||
469 | if (!ies) | ||
470 | return -ENOMEM; | ||
471 | 597 | ||
472 | ielen = ieee80211_build_preq_ies(local, ies, | 598 | mutex_lock(&sdata->local->scan_mtx); |
473 | req->ie, req->ie_len); | 599 | res = __ieee80211_start_scan(sdata, req); |
474 | local->orig_ies = req->ie; | 600 | mutex_unlock(&sdata->local->scan_mtx); |
475 | local->orig_ies_len = req->ie_len; | ||
476 | req->ie = ies; | ||
477 | req->ie_len = ielen; | ||
478 | |||
479 | local->hw_scanning = true; | ||
480 | rc = local->ops->hw_scan(local_to_hw(local), req); | ||
481 | if (rc) { | ||
482 | local->hw_scanning = false; | ||
483 | kfree(ies); | ||
484 | req->ie_len = local->orig_ies_len; | ||
485 | req->ie = local->orig_ies; | ||
486 | return rc; | ||
487 | } | ||
488 | local->scan_sdata = scan_sdata; | ||
489 | return 0; | ||
490 | } | ||
491 | 601 | ||
492 | /* | 602 | return res; |
493 | * Hardware/driver doesn't support hw_scan, so use software | ||
494 | * scanning instead. First send a nullfunc frame with power save | ||
495 | * bit on so that AP will buffer the frames for us while we are not | ||
496 | * listening, then send probe requests to each channel and wait for | ||
497 | * the responses. After all channels are scanned, tune back to the | ||
498 | * original channel and send a nullfunc frame with power save bit | ||
499 | * off to trigger the AP to send us all the buffered frames. | ||
500 | * | ||
501 | * Note that while local->sw_scanning is true everything else but | ||
502 | * nullfunc frames and probe requests will be dropped in | ||
503 | * ieee80211_tx_h_check_assoc(). | ||
504 | */ | ||
505 | local->sw_scanning = true; | ||
506 | if (local->ops->sw_scan_start) | ||
507 | local->ops->sw_scan_start(local_to_hw(local)); | ||
508 | |||
509 | mutex_lock(&local->iflist_mtx); | ||
510 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
511 | if (!netif_running(sdata->dev)) | ||
512 | continue; | ||
513 | |||
514 | /* disable beaconing */ | ||
515 | if (sdata->vif.type == NL80211_IFTYPE_AP || | ||
516 | sdata->vif.type == NL80211_IFTYPE_ADHOC || | ||
517 | sdata->vif.type == NL80211_IFTYPE_MESH_POINT) | ||
518 | ieee80211_if_config(sdata, | ||
519 | IEEE80211_IFCC_BEACON_ENABLED); | ||
520 | |||
521 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
522 | if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { | ||
523 | netif_tx_stop_all_queues(sdata->dev); | ||
524 | ieee80211_scan_ps_enable(sdata); | ||
525 | } | ||
526 | } else | ||
527 | netif_tx_stop_all_queues(sdata->dev); | ||
528 | } | ||
529 | mutex_unlock(&local->iflist_mtx); | ||
530 | |||
531 | local->scan_state = SCAN_SET_CHANNEL; | ||
532 | local->scan_channel_idx = 0; | ||
533 | local->scan_sdata = scan_sdata; | ||
534 | local->scan_req = req; | ||
535 | |||
536 | netif_addr_lock_bh(local->mdev); | ||
537 | local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; | ||
538 | local->ops->configure_filter(local_to_hw(local), | ||
539 | FIF_BCN_PRBRESP_PROMISC, | ||
540 | &local->filter_flags, | ||
541 | local->mdev->mc_count, | ||
542 | local->mdev->mc_list); | ||
543 | netif_addr_unlock_bh(local->mdev); | ||
544 | |||
545 | /* TODO: start scan as soon as all nullfunc frames are ACKed */ | ||
546 | queue_delayed_work(local->hw.workqueue, &local->scan_work, | ||
547 | IEEE80211_CHANNEL_TIME); | ||
548 | |||
549 | return 0; | ||
550 | } | 603 | } |
551 | 604 | ||
552 | 605 | int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, | |
553 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | 606 | const u8 *ssid, u8 ssid_len) |
554 | struct cfg80211_scan_request *req) | ||
555 | { | 607 | { |
556 | struct ieee80211_local *local = sdata->local; | 608 | struct ieee80211_local *local = sdata->local; |
557 | struct ieee80211_if_managed *ifmgd; | 609 | int ret = -EBUSY; |
558 | |||
559 | if (!req) | ||
560 | return -EINVAL; | ||
561 | |||
562 | if (local->scan_req && local->scan_req != req) | ||
563 | return -EBUSY; | ||
564 | |||
565 | local->scan_req = req; | ||
566 | 610 | ||
567 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 611 | mutex_lock(&local->scan_mtx); |
568 | return ieee80211_start_scan(sdata, req); | ||
569 | 612 | ||
570 | /* | 613 | /* busy scanning */ |
571 | * STA has a state machine that might need to defer scanning | 614 | if (local->scan_req) |
572 | * while it's trying to associate/authenticate, therefore we | 615 | goto unlock; |
573 | * queue it up to the state machine in that case. | ||
574 | */ | ||
575 | 616 | ||
576 | if (local->sw_scanning || local->hw_scanning) { | 617 | memcpy(local->int_scan_req.ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN); |
577 | if (local->scan_sdata == sdata) | 618 | local->int_scan_req.ssids[0].ssid_len = ssid_len; |
578 | return 0; | ||
579 | return -EBUSY; | ||
580 | } | ||
581 | |||
582 | ifmgd = &sdata->u.mgd; | ||
583 | set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request); | ||
584 | queue_work(local->hw.workqueue, &ifmgd->work); | ||
585 | 619 | ||
586 | return 0; | 620 | ret = __ieee80211_start_scan(sdata, &sdata->local->int_scan_req); |
621 | unlock: | ||
622 | mutex_unlock(&local->scan_mtx); | ||
623 | return ret; | ||
587 | } | 624 | } |