aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-08-21 16:07:20 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-09-26 07:21:37 -0400
commitc7c71066c27f2bafb2ce3b10c407c0285f56acfa (patch)
tree183c3557d596a8ae69bf3ae9219e7ef49456052e
parent272b98c6455f00884f0350f775c5342358ebb73f (diff)
mac80211: add ieee80211_iterate_active_interfaces_rtnl()
If it is needed to disconnect multiple virtual interfaces after (WoWLAN-) suspend, the most obvious approach would be to iterate all interfaces by calling ieee80211_iterate_active_interfaces() and then call ieee80211_resume_disconnect() for each one. This is what the iwlmvm driver does. Unfortunately, this causes a locking dependency from mac80211's iflist_mtx to the key_mtx. This is problematic as the former is intentionally never held while calling any driver operation to allow drivers to iterate with their own locks held. The key_mtx is held while installing a key into the driver though, so this new lock dependency means drivers implementing the logic above can no longer hold their own lock while iterating. To fix this, add a new ieee80211_iterate_active_interfaces_rtnl() function that iterates while the RTNL is already held. This is true during suspend/resume, so that then the locking dependency isn't introduced. While at it, also refactor the various interface iterators and keep only a single implementation called by the various cases. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/net/mac80211.h19
-rw-r--r--net/mac80211/util.c71
2 files changed, 53 insertions, 37 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index cc6035f1a2f1..3411c59b636b 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3920,6 +3920,25 @@ void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw,
3920 void *data); 3920 void *data);
3921 3921
3922/** 3922/**
3923 * ieee80211_iterate_active_interfaces_rtnl - iterate active interfaces
3924 *
3925 * This function iterates over the interfaces associated with a given
3926 * hardware that are currently active and calls the callback for them.
3927 * This version can only be used while holding the RTNL.
3928 *
3929 * @hw: the hardware struct of which the interfaces should be iterated over
3930 * @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags
3931 * @iterator: the iterator function to call, cannot sleep
3932 * @data: first argument of the iterator function
3933 */
3934void ieee80211_iterate_active_interfaces_rtnl(struct ieee80211_hw *hw,
3935 u32 iter_flags,
3936 void (*iterator)(void *data,
3937 u8 *mac,
3938 struct ieee80211_vif *vif),
3939 void *data);
3940
3941/**
3923 * ieee80211_queue_work - add work onto the mac80211 workqueue 3942 * ieee80211_queue_work - add work onto the mac80211 workqueue
3924 * 3943 *
3925 * Drivers and mac80211 use this to add work onto the mac80211 workqueue. 3944 * Drivers and mac80211 use this to add work onto the mac80211 workqueue.
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index e1b34a18b243..75a16853fb45 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -567,18 +567,15 @@ void ieee80211_flush_queues(struct ieee80211_local *local,
567 IEEE80211_QUEUE_STOP_REASON_FLUSH); 567 IEEE80211_QUEUE_STOP_REASON_FLUSH);
568} 568}
569 569
570void ieee80211_iterate_active_interfaces( 570static void __iterate_active_interfaces(struct ieee80211_local *local,
571 struct ieee80211_hw *hw, u32 iter_flags, 571 u32 iter_flags,
572 void (*iterator)(void *data, u8 *mac, 572 void (*iterator)(void *data, u8 *mac,
573 struct ieee80211_vif *vif), 573 struct ieee80211_vif *vif),
574 void *data) 574 void *data)
575{ 575{
576 struct ieee80211_local *local = hw_to_local(hw);
577 struct ieee80211_sub_if_data *sdata; 576 struct ieee80211_sub_if_data *sdata;
578 577
579 mutex_lock(&local->iflist_mtx); 578 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
580
581 list_for_each_entry(sdata, &local->interfaces, list) {
582 switch (sdata->vif.type) { 579 switch (sdata->vif.type) {
583 case NL80211_IFTYPE_MONITOR: 580 case NL80211_IFTYPE_MONITOR:
584 if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)) 581 if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
@@ -597,13 +594,25 @@ void ieee80211_iterate_active_interfaces(
597 &sdata->vif); 594 &sdata->vif);
598 } 595 }
599 596
600 sdata = rcu_dereference_protected(local->monitor_sdata, 597 sdata = rcu_dereference_check(local->monitor_sdata,
601 lockdep_is_held(&local->iflist_mtx)); 598 lockdep_is_held(&local->iflist_mtx) ||
599 lockdep_rtnl_is_held());
602 if (sdata && 600 if (sdata &&
603 (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || 601 (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL ||
604 sdata->flags & IEEE80211_SDATA_IN_DRIVER)) 602 sdata->flags & IEEE80211_SDATA_IN_DRIVER))
605 iterator(data, sdata->vif.addr, &sdata->vif); 603 iterator(data, sdata->vif.addr, &sdata->vif);
604}
606 605
606void ieee80211_iterate_active_interfaces(
607 struct ieee80211_hw *hw, u32 iter_flags,
608 void (*iterator)(void *data, u8 *mac,
609 struct ieee80211_vif *vif),
610 void *data)
611{
612 struct ieee80211_local *local = hw_to_local(hw);
613
614 mutex_lock(&local->iflist_mtx);
615 __iterate_active_interfaces(local, iter_flags, iterator, data);
607 mutex_unlock(&local->iflist_mtx); 616 mutex_unlock(&local->iflist_mtx);
608} 617}
609EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); 618EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
@@ -615,38 +624,26 @@ void ieee80211_iterate_active_interfaces_atomic(
615 void *data) 624 void *data)
616{ 625{
617 struct ieee80211_local *local = hw_to_local(hw); 626 struct ieee80211_local *local = hw_to_local(hw);
618 struct ieee80211_sub_if_data *sdata;
619 627
620 rcu_read_lock(); 628 rcu_read_lock();
629 __iterate_active_interfaces(local, iter_flags, iterator, data);
630 rcu_read_unlock();
631}
632EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
621 633
622 list_for_each_entry_rcu(sdata, &local->interfaces, list) { 634void ieee80211_iterate_active_interfaces_rtnl(
623 switch (sdata->vif.type) { 635 struct ieee80211_hw *hw, u32 iter_flags,
624 case NL80211_IFTYPE_MONITOR: 636 void (*iterator)(void *data, u8 *mac,
625 if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE)) 637 struct ieee80211_vif *vif),
626 continue; 638 void *data)
627 break; 639{
628 case NL80211_IFTYPE_AP_VLAN: 640 struct ieee80211_local *local = hw_to_local(hw);
629 continue;
630 default:
631 break;
632 }
633 if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
634 !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
635 continue;
636 if (ieee80211_sdata_running(sdata))
637 iterator(data, sdata->vif.addr,
638 &sdata->vif);
639 }
640 641
641 sdata = rcu_dereference(local->monitor_sdata); 642 ASSERT_RTNL();
642 if (sdata &&
643 (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL ||
644 sdata->flags & IEEE80211_SDATA_IN_DRIVER))
645 iterator(data, sdata->vif.addr, &sdata->vif);
646 643
647 rcu_read_unlock(); 644 __iterate_active_interfaces(local, iter_flags, iterator, data);
648} 645}
649EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); 646EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl);
650 647
651/* 648/*
652 * Nothing should have been stuffed into the workqueue during 649 * Nothing should have been stuffed into the workqueue during