aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/scan.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-04-23 10:01:47 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-05-06 15:14:31 -0400
commitf3b85252f081581a8f257545ed748062dce7798b (patch)
tree899a804545850c7e1b1e3eea5c743df2c8cddf3d /net/mac80211/scan.c
parent2d72289095e9621158acf1d59a830cfe920fa93b (diff)
mac80211: fix scan races and rework scanning
There are some places marked /* XXX maybe racy? */ and they really are racy because there's no locking. This patch reworks much of the scan code, and introduces proper locking for the scan request as well as the internal scanning (which is necessary for IBSS/managed modes). Helper functions are added to call the scanning code whenever necessary. The scan deferring is changed to simply queue the scanning work instead of trying to start the scan in place, the scanning work will then take care of the rest. Also, currently when internal scans are requested for an interface that is trying to associate, we reject such scans. This was not intended, the mlme code has provisions to scan twice when it can't find the BSS to associate with right away; this has never worked properly. Fix this by not rejecting internal scan requests for an interface that is associating. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/scan.c')
-rw-r--r--net/mac80211/scan.c387
1 files changed, 212 insertions, 175 deletions
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
205void 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
265static 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
277void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) 272void 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}
355EXPORT_SYMBOL(ieee80211_scan_completed); 359EXPORT_SYMBOL(ieee80211_scan_completed);
356 360
361static 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
423static 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
357void ieee80211_scan_work(struct work_struct *work) 501void 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 593int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
426int 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 605int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
553int 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}