aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/iface.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r--net/mac80211/iface.c60
1 files changed, 41 insertions, 19 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index fbef7a1ada7a..bfb57dcc1538 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -112,10 +112,11 @@ static u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
112 } 112 }
113 } 113 }
114 114
115 if (local->scan_sdata && 115 sdata = rcu_dereference_protected(local->scan_sdata,
116 !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { 116 lockdep_is_held(&local->mtx));
117 if (sdata && !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) {
117 scanning = true; 118 scanning = true;
118 local->scan_sdata->vif.bss_conf.idle = false; 119 sdata->vif.bss_conf.idle = false;
119 } 120 }
120 121
121 list_for_each_entry(sdata, &local->interfaces, list) { 122 list_for_each_entry(sdata, &local->interfaces, list) {
@@ -330,20 +331,24 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)
330 sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; 331 sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE;
331} 332}
332 333
333int ieee80211_add_virtual_monitor(struct ieee80211_local *local) 334static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
334{ 335{
335 struct ieee80211_sub_if_data *sdata; 336 struct ieee80211_sub_if_data *sdata;
336 int ret; 337 int ret = 0;
337 338
338 if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)) 339 if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
339 return 0; 340 return 0;
340 341
342 mutex_lock(&local->iflist_mtx);
343
341 if (local->monitor_sdata) 344 if (local->monitor_sdata)
342 return 0; 345 goto out_unlock;
343 346
344 sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL); 347 sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
345 if (!sdata) 348 if (!sdata) {
346 return -ENOMEM; 349 ret = -ENOMEM;
350 goto out_unlock;
351 }
347 352
348 /* set up data */ 353 /* set up data */
349 sdata->local = local; 354 sdata->local = local;
@@ -357,31 +362,34 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
357 if (WARN_ON(ret)) { 362 if (WARN_ON(ret)) {
358 /* ok .. stupid driver, it asked for this! */ 363 /* ok .. stupid driver, it asked for this! */
359 kfree(sdata); 364 kfree(sdata);
360 return ret; 365 goto out_unlock;
361 } 366 }
362 367
363 ret = ieee80211_check_queues(sdata); 368 ret = ieee80211_check_queues(sdata);
364 if (ret) { 369 if (ret) {
365 kfree(sdata); 370 kfree(sdata);
366 return ret; 371 goto out_unlock;
367 } 372 }
368 373
369 rcu_assign_pointer(local->monitor_sdata, sdata); 374 rcu_assign_pointer(local->monitor_sdata, sdata);
370 375 out_unlock:
371 return 0; 376 mutex_unlock(&local->iflist_mtx);
377 return ret;
372} 378}
373 379
374void ieee80211_del_virtual_monitor(struct ieee80211_local *local) 380static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
375{ 381{
376 struct ieee80211_sub_if_data *sdata; 382 struct ieee80211_sub_if_data *sdata;
377 383
378 if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)) 384 if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
379 return; 385 return;
380 386
381 sdata = rtnl_dereference(local->monitor_sdata); 387 mutex_lock(&local->iflist_mtx);
382 388
389 sdata = rcu_dereference_protected(local->monitor_sdata,
390 lockdep_is_held(&local->iflist_mtx));
383 if (!sdata) 391 if (!sdata)
384 return; 392 goto out_unlock;
385 393
386 rcu_assign_pointer(local->monitor_sdata, NULL); 394 rcu_assign_pointer(local->monitor_sdata, NULL);
387 synchronize_net(); 395 synchronize_net();
@@ -389,6 +397,8 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
389 drv_remove_interface(local, sdata); 397 drv_remove_interface(local, sdata);
390 398
391 kfree(sdata); 399 kfree(sdata);
400 out_unlock:
401 mutex_unlock(&local->iflist_mtx);
392} 402}
393 403
394/* 404/*
@@ -487,6 +497,12 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
487 break; 497 break;
488 } 498 }
489 499
500 if (local->monitors == 0 && local->open_count == 0) {
501 res = ieee80211_add_virtual_monitor(local);
502 if (res)
503 goto err_stop;
504 }
505
490 /* must be before the call to ieee80211_configure_filter */ 506 /* must be before the call to ieee80211_configure_filter */
491 local->monitors++; 507 local->monitors++;
492 if (local->monitors == 1) { 508 if (local->monitors == 1) {
@@ -501,6 +517,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
501 break; 517 break;
502 default: 518 default:
503 if (coming_up) { 519 if (coming_up) {
520 ieee80211_del_virtual_monitor(local);
521
504 res = drv_add_interface(local, sdata); 522 res = drv_add_interface(local, sdata);
505 if (res) 523 if (res)
506 goto err_stop; 524 goto err_stop;
@@ -628,7 +646,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
628 646
629 clear_bit(SDATA_STATE_RUNNING, &sdata->state); 647 clear_bit(SDATA_STATE_RUNNING, &sdata->state);
630 648
631 if (local->scan_sdata == sdata) 649 if (rcu_access_pointer(local->scan_sdata) == sdata)
632 ieee80211_scan_cancel(local); 650 ieee80211_scan_cancel(local);
633 651
634 /* 652 /*
@@ -735,6 +753,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
735 if (local->monitors == 0) { 753 if (local->monitors == 0) {
736 local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; 754 local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR;
737 hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; 755 hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
756 ieee80211_del_virtual_monitor(local);
738 } 757 }
739 758
740 ieee80211_adjust_monitor_flags(sdata, -1); 759 ieee80211_adjust_monitor_flags(sdata, -1);
@@ -808,6 +827,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
808 } 827 }
809 } 828 }
810 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 829 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
830
831 if (local->monitors == local->open_count && local->monitors > 0)
832 ieee80211_add_virtual_monitor(local);
811} 833}
812 834
813static int ieee80211_stop(struct net_device *dev) 835static int ieee80211_stop(struct net_device *dev)
@@ -1373,7 +1395,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local,
1373} 1395}
1374 1396
1375int ieee80211_if_add(struct ieee80211_local *local, const char *name, 1397int ieee80211_if_add(struct ieee80211_local *local, const char *name,
1376 struct net_device **new_dev, enum nl80211_iftype type, 1398 struct wireless_dev **new_wdev, enum nl80211_iftype type,
1377 struct vif_params *params) 1399 struct vif_params *params)
1378{ 1400{
1379 struct net_device *ndev; 1401 struct net_device *ndev;
@@ -1463,8 +1485,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
1463 list_add_tail_rcu(&sdata->list, &local->interfaces); 1485 list_add_tail_rcu(&sdata->list, &local->interfaces);
1464 mutex_unlock(&local->iflist_mtx); 1486 mutex_unlock(&local->iflist_mtx);
1465 1487
1466 if (new_dev) 1488 if (new_wdev)
1467 *new_dev = ndev; 1489 *new_wdev = &sdata->wdev;
1468 1490
1469 return 0; 1491 return 0;
1470 1492