aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStanislaw Gruszka <sgruszka@redhat.com>2010-10-06 05:22:09 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-10-06 16:30:42 -0400
commite229f844d7223b7063bea1e649203ac521a58fe1 (patch)
tree59067ee607b0ad937fd541e981428b6c8cb1c5ab
parent259b62e35bf44a97983f275de569929a7d2bd5dd (diff)
mac80211: keep lock when calling __ieee80211_scan_completed()
We are taking local->mtx inside __ieee80211_scan_completed(), but just before call to that function we drop the lock. Dropping/taking lock is not good, because can lead to hard to understand race conditions. Patch split scan_completed() code into two functions, first must be called with local->mtx taken and second without it. Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com> Acked-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--net/mac80211/scan.c75
1 files changed, 39 insertions, 36 deletions
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 830c02bc398a..6964a4598176 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -249,12 +249,12 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
249 return true; 249 return true;
250} 250}
251 251
252static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) 252static bool __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
253 bool was_hw_scan)
253{ 254{
254 struct ieee80211_local *local = hw_to_local(hw); 255 struct ieee80211_local *local = hw_to_local(hw);
255 bool was_hw_scan;
256 256
257 mutex_lock(&local->mtx); 257 lockdep_assert_held(&local->mtx);
258 258
259 /* 259 /*
260 * It's ok to abort a not-yet-running scan (that 260 * It's ok to abort a not-yet-running scan (that
@@ -265,17 +265,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
265 if (WARN_ON(!local->scanning && !aborted)) 265 if (WARN_ON(!local->scanning && !aborted))
266 aborted = true; 266 aborted = true;
267 267
268 if (WARN_ON(!local->scan_req)) { 268 if (WARN_ON(!local->scan_req))
269 mutex_unlock(&local->mtx); 269 return false;
270 return;
271 }
272 270
273 was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
274 if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { 271 if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) {
275 ieee80211_queue_delayed_work(&local->hw, 272 ieee80211_queue_delayed_work(&local->hw,
276 &local->scan_work, 0); 273 &local->scan_work, 0);
277 mutex_unlock(&local->mtx); 274 return false;
278 return;
279 } 275 }
280 276
281 kfree(local->hw_scan_req); 277 kfree(local->hw_scan_req);
@@ -289,23 +285,25 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
289 local->scanning = 0; 285 local->scanning = 0;
290 local->scan_channel = NULL; 286 local->scan_channel = NULL;
291 287
292 /* we only have to protect scan_req and hw/sw scan */ 288 return true;
293 mutex_unlock(&local->mtx); 289}
294
295 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
296 if (was_hw_scan)
297 goto done;
298
299 ieee80211_configure_filter(local);
300 290
301 drv_sw_scan_complete(local); 291static void __ieee80211_scan_completed_finish(struct ieee80211_hw *hw,
292 bool was_hw_scan)
293{
294 struct ieee80211_local *local = hw_to_local(hw);
302 295
303 ieee80211_offchannel_return(local, true); 296 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
297 if (!was_hw_scan) {
298 ieee80211_configure_filter(local);
299 drv_sw_scan_complete(local);
300 ieee80211_offchannel_return(local, true);
301 }
304 302
305 done:
306 mutex_lock(&local->mtx); 303 mutex_lock(&local->mtx);
307 ieee80211_recalc_idle(local); 304 ieee80211_recalc_idle(local);
308 mutex_unlock(&local->mtx); 305 mutex_unlock(&local->mtx);
306
309 ieee80211_mlme_notify_scan_completed(local); 307 ieee80211_mlme_notify_scan_completed(local);
310 ieee80211_ibss_notify_scan_completed(local); 308 ieee80211_ibss_notify_scan_completed(local);
311 ieee80211_mesh_notify_scan_completed(local); 309 ieee80211_mesh_notify_scan_completed(local);
@@ -366,6 +364,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
366 struct ieee80211_local *local = sdata->local; 364 struct ieee80211_local *local = sdata->local;
367 int rc; 365 int rc;
368 366
367 lockdep_assert_held(&local->mtx);
368
369 if (local->scan_req) 369 if (local->scan_req)
370 return -EBUSY; 370 return -EBUSY;
371 371
@@ -447,8 +447,8 @@ ieee80211_scan_get_channel_time(struct ieee80211_channel *chan)
447 return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME; 447 return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME;
448} 448}
449 449
450static int ieee80211_scan_state_decision(struct ieee80211_local *local, 450static void ieee80211_scan_state_decision(struct ieee80211_local *local,
451 unsigned long *next_delay) 451 unsigned long *next_delay)
452{ 452{
453 bool associated = false; 453 bool associated = false;
454 bool tx_empty = true; 454 bool tx_empty = true;
@@ -458,12 +458,6 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
458 struct ieee80211_sub_if_data *sdata; 458 struct ieee80211_sub_if_data *sdata;
459 struct ieee80211_channel *next_chan; 459 struct ieee80211_channel *next_chan;
460 460
461 /* if no more bands/channels left, complete scan and advance to the idle state */
462 if (local->scan_channel_idx >= local->scan_req->n_channels) {
463 __ieee80211_scan_completed(&local->hw, false);
464 return 1;
465 }
466
467 /* 461 /*
468 * check if at least one STA interface is associated, 462 * check if at least one STA interface is associated,
469 * check if at least one STA interface has pending tx frames 463 * check if at least one STA interface has pending tx frames
@@ -535,7 +529,6 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
535 } 529 }
536 530
537 *next_delay = 0; 531 *next_delay = 0;
538 return 0;
539} 532}
540 533
541static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local, 534static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local,
@@ -651,7 +644,7 @@ void ieee80211_scan_work(struct work_struct *work)
651 container_of(work, struct ieee80211_local, scan_work.work); 644 container_of(work, struct ieee80211_local, scan_work.work);
652 struct ieee80211_sub_if_data *sdata = local->scan_sdata; 645 struct ieee80211_sub_if_data *sdata = local->scan_sdata;
653 unsigned long next_delay = 0; 646 unsigned long next_delay = 0;
654 bool aborted; 647 bool aborted, hw_scan, finish;
655 648
656 mutex_lock(&local->mtx); 649 mutex_lock(&local->mtx);
657 650
@@ -704,8 +697,12 @@ void ieee80211_scan_work(struct work_struct *work)
704 do { 697 do {
705 switch (local->next_scan_state) { 698 switch (local->next_scan_state) {
706 case SCAN_DECISION: 699 case SCAN_DECISION:
707 if (ieee80211_scan_state_decision(local, &next_delay)) 700 /* if no more bands/channels left, complete scan */
708 return; 701 if (local->scan_channel_idx >= local->scan_req->n_channels) {
702 aborted = false;
703 goto out_complete;
704 }
705 ieee80211_scan_state_decision(local, &next_delay);
709 break; 706 break;
710 case SCAN_SET_CHANNEL: 707 case SCAN_SET_CHANNEL:
711 ieee80211_scan_state_set_channel(local, &next_delay); 708 ieee80211_scan_state_set_channel(local, &next_delay);
@@ -726,8 +723,11 @@ void ieee80211_scan_work(struct work_struct *work)
726 return; 723 return;
727 724
728out_complete: 725out_complete:
726 hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
727 finish = __ieee80211_scan_completed(&local->hw, aborted, hw_scan);
729 mutex_unlock(&local->mtx); 728 mutex_unlock(&local->mtx);
730 __ieee80211_scan_completed(&local->hw, aborted); 729 if (finish)
730 __ieee80211_scan_completed_finish(&local->hw, hw_scan);
731 return; 731 return;
732 732
733out: 733out:
@@ -796,6 +796,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
796void ieee80211_scan_cancel(struct ieee80211_local *local) 796void ieee80211_scan_cancel(struct ieee80211_local *local)
797{ 797{
798 bool abortscan; 798 bool abortscan;
799 bool finish = false;
799 800
800 cancel_delayed_work_sync(&local->scan_work); 801 cancel_delayed_work_sync(&local->scan_work);
801 802
@@ -806,8 +807,10 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
806 mutex_lock(&local->mtx); 807 mutex_lock(&local->mtx);
807 abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) || 808 abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) ||
808 (!local->scanning && local->scan_req); 809 (!local->scanning && local->scan_req);
810 if (abortscan)
811 finish = __ieee80211_scan_completed(&local->hw, true, false);
809 mutex_unlock(&local->mtx); 812 mutex_unlock(&local->mtx);
810 813
811 if (abortscan) 814 if (finish)
812 __ieee80211_scan_completed(&local->hw, true); 815 __ieee80211_scan_completed_finish(&local->hw, false);
813} 816}