aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/iface.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-07-11 10:38:09 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-07-12 06:10:50 -0400
commit685fb72b63faf09a767cc28332545f5830b91be8 (patch)
tree236e971df0e369a17a4938131ff20d4b60ec568d /net/mac80211/iface.c
parent8e95ea49c94908cb10e698c5637d57f0fbdc796d (diff)
mac80211: iterate the virtual monitor interface
If the virtual monitor interface is requested by the driver, it should also be iterated over when the driver wants to iterate all active interfaces. To allow that protect it with the iflist_mtx. Change-Id: I58ac5de2f4ce93d12c5a98ecd2859f60158d5d69 Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r--net/mac80211/iface.c29
1 files changed, 19 insertions, 10 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index e3c49748ce8f..334ee0fb18ca 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -334,17 +334,21 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)
334int ieee80211_add_virtual_monitor(struct ieee80211_local *local) 334int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
335{ 335{
336 struct ieee80211_sub_if_data *sdata; 336 struct ieee80211_sub_if_data *sdata;
337 int ret; 337 int ret = 0;
338 338
339 if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)) 339 if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
340 return 0; 340 return 0;
341 341
342 mutex_lock(&local->iflist_mtx);
343
342 if (local->monitor_sdata) 344 if (local->monitor_sdata)
343 return 0; 345 goto out_unlock;
344 346
345 sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL); 347 sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
346 if (!sdata) 348 if (!sdata) {
347 return -ENOMEM; 349 ret = -ENOMEM;
350 goto out_unlock;
351 }
348 352
349 /* set up data */ 353 /* set up data */
350 sdata->local = local; 354 sdata->local = local;
@@ -358,18 +362,19 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
358 if (WARN_ON(ret)) { 362 if (WARN_ON(ret)) {
359 /* ok .. stupid driver, it asked for this! */ 363 /* ok .. stupid driver, it asked for this! */
360 kfree(sdata); 364 kfree(sdata);
361 return ret; 365 goto out_unlock;
362 } 366 }
363 367
364 ret = ieee80211_check_queues(sdata); 368 ret = ieee80211_check_queues(sdata);
365 if (ret) { 369 if (ret) {
366 kfree(sdata); 370 kfree(sdata);
367 return ret; 371 goto out_unlock;
368 } 372 }
369 373
370 rcu_assign_pointer(local->monitor_sdata, sdata); 374 rcu_assign_pointer(local->monitor_sdata, sdata);
371 375 out_unlock:
372 return 0; 376 mutex_unlock(&local->iflist_mtx);
377 return ret;
373} 378}
374 379
375void ieee80211_del_virtual_monitor(struct ieee80211_local *local) 380void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
@@ -379,10 +384,12 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
379 if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)) 384 if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
380 return; 385 return;
381 386
382 sdata = rtnl_dereference(local->monitor_sdata); 387 mutex_lock(&local->iflist_mtx);
383 388
389 sdata = rcu_dereference_protected(local->monitor_sdata,
390 lockdep_is_held(&local->iflist_mtx));
384 if (!sdata) 391 if (!sdata)
385 return; 392 goto out_unlock;
386 393
387 rcu_assign_pointer(local->monitor_sdata, NULL); 394 rcu_assign_pointer(local->monitor_sdata, NULL);
388 synchronize_net(); 395 synchronize_net();
@@ -390,6 +397,8 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
390 drv_remove_interface(local, sdata); 397 drv_remove_interface(local, sdata);
391 398
392 kfree(sdata); 399 kfree(sdata);
400 out_unlock:
401 mutex_unlock(&local->iflist_mtx);
393} 402}
394 403
395/* 404/*