aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-03-31 13:23:03 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-04-01 17:14:10 -0400
commitdc6676b7f2c2072ec05254aaca32e99f87a8a417 (patch)
tree6caf7e007063f9ae6a16fdcb1912bf72d31237c2 /net/mac80211
parent4f6fab472c4c7c21d577f85fabec7628d4a05637 (diff)
mac80211: sta_info_flush() fixes
When the IBSS code tries to flush the STA list, it does so in an atomic context. Flushing isn't safe there, however, and requires the RTNL, so we need to defer it to a workqueue. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/ieee80211_sta.c2
-rw-r--r--net/mac80211/key.c9
-rw-r--r--net/mac80211/sta_info.c70
-rw-r--r--net/mac80211/sta_info.h2
5 files changed, 84 insertions, 1 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 7ab806602183..0997a0f96203 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -606,6 +606,8 @@ struct ieee80211_local {
606 spinlock_t sta_lock; 606 spinlock_t sta_lock;
607 unsigned long num_sta; 607 unsigned long num_sta;
608 struct list_head sta_list; 608 struct list_head sta_list;
609 struct list_head sta_flush_list;
610 struct work_struct sta_flush_work;
609 struct sta_info *sta_hash[STA_HASH_SIZE]; 611 struct sta_info *sta_hash[STA_HASH_SIZE];
610 struct timer_list sta_cleanup; 612 struct timer_list sta_cleanup;
611 613
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index c5a47f8d873a..75b96a754333 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -2254,7 +2254,7 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
2254 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 2254 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
2255 2255
2256 /* Remove possible STA entries from other IBSS networks. */ 2256 /* Remove possible STA entries from other IBSS networks. */
2257 sta_info_flush(local, sdata); 2257 sta_info_flush_delayed(sdata);
2258 2258
2259 if (local->ops->reset_tsf) { 2259 if (local->ops->reset_tsf) {
2260 /* Reset own TSF to allow time synchronization work. */ 2260 /* Reset own TSF to allow time synchronization work. */
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index f91fb4092652..5df9e0cc009f 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -73,6 +73,15 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
73 if (!key->local->ops->set_key) 73 if (!key->local->ops->set_key)
74 return; 74 return;
75 75
76 /*
77 * This makes sure that all pending flushes have
78 * actually completed prior to uploading new key
79 * material to the hardware. That is necessary to
80 * avoid races between flushing STAs and adding
81 * new keys for them.
82 */
83 __ieee80211_run_pending_flush(key->local);
84
76 addr = get_mac_for_key(key); 85 addr = get_mac_for_key(key);
77 86
78 ret = key->local->ops->set_key(local_to_hw(key->local), SET_KEY, 87 ret = key->local->ops->set_key(local_to_hw(key->local), SET_KEY,
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index dfca96e05d69..f5c65e891288 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -644,10 +644,41 @@ static void sta_info_debugfs_add_work(struct work_struct *work)
644} 644}
645#endif 645#endif
646 646
647void __ieee80211_run_pending_flush(struct ieee80211_local *local)
648{
649 struct sta_info *sta;
650 unsigned long flags;
651
652 ASSERT_RTNL();
653
654 spin_lock_irqsave(&local->sta_lock, flags);
655 while (!list_empty(&local->sta_flush_list)) {
656 sta = list_first_entry(&local->sta_flush_list,
657 struct sta_info, list);
658 list_del(&sta->list);
659 spin_unlock_irqrestore(&local->sta_lock, flags);
660 sta_info_destroy(sta);
661 spin_lock_irqsave(&local->sta_lock, flags);
662 }
663 spin_unlock_irqrestore(&local->sta_lock, flags);
664}
665
666static void ieee80211_sta_flush_work(struct work_struct *work)
667{
668 struct ieee80211_local *local =
669 container_of(work, struct ieee80211_local, sta_flush_work);
670
671 rtnl_lock();
672 __ieee80211_run_pending_flush(local);
673 rtnl_unlock();
674}
675
647void sta_info_init(struct ieee80211_local *local) 676void sta_info_init(struct ieee80211_local *local)
648{ 677{
649 spin_lock_init(&local->sta_lock); 678 spin_lock_init(&local->sta_lock);
650 INIT_LIST_HEAD(&local->sta_list); 679 INIT_LIST_HEAD(&local->sta_list);
680 INIT_LIST_HEAD(&local->sta_flush_list);
681 INIT_WORK(&local->sta_flush_work, ieee80211_sta_flush_work);
651 682
652 setup_timer(&local->sta_cleanup, sta_info_cleanup, 683 setup_timer(&local->sta_cleanup, sta_info_cleanup,
653 (unsigned long)local); 684 (unsigned long)local);
@@ -668,7 +699,12 @@ int sta_info_start(struct ieee80211_local *local)
668void sta_info_stop(struct ieee80211_local *local) 699void sta_info_stop(struct ieee80211_local *local)
669{ 700{
670 del_timer(&local->sta_cleanup); 701 del_timer(&local->sta_cleanup);
702 cancel_work_sync(&local->sta_flush_work);
703
704 rtnl_lock();
671 sta_info_flush(local, NULL); 705 sta_info_flush(local, NULL);
706 __ieee80211_run_pending_flush(local);
707 rtnl_unlock();
672} 708}
673 709
674/** 710/**
@@ -688,6 +724,7 @@ int sta_info_flush(struct ieee80211_local *local,
688 unsigned long flags; 724 unsigned long flags;
689 725
690 might_sleep(); 726 might_sleep();
727 ASSERT_RTNL();
691 728
692 spin_lock_irqsave(&local->sta_lock, flags); 729 spin_lock_irqsave(&local->sta_lock, flags);
693 list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { 730 list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
@@ -706,3 +743,36 @@ int sta_info_flush(struct ieee80211_local *local,
706 743
707 return ret; 744 return ret;
708} 745}
746
747/**
748 * sta_info_flush_delayed - flush matching STA entries from the STA table
749 *
750 * This function unlinks all stations for a given interface and queues
751 * them for freeing. Note that the workqueue function scheduled here has
752 * to run before any new keys can be added to the system to avoid set_key()
753 * callback ordering issues.
754 *
755 * @sdata: the interface
756 */
757void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata)
758{
759 struct ieee80211_local *local = sdata->local;
760 struct sta_info *sta, *tmp;
761 unsigned long flags;
762 bool work = false;
763
764 spin_lock_irqsave(&local->sta_lock, flags);
765 list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
766 if (sdata == sta->sdata) {
767 __sta_info_unlink(&sta);
768 if (sta) {
769 list_add_tail(&sta->list,
770 &local->sta_flush_list);
771 work = true;
772 }
773 }
774 }
775 if (work)
776 schedule_work(&local->sta_flush_work);
777 spin_unlock_irqrestore(&local->sta_lock, flags);
778}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 5e39a4164b9b..b09861eb124e 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -357,5 +357,7 @@ int sta_info_start(struct ieee80211_local *local);
357void sta_info_stop(struct ieee80211_local *local); 357void sta_info_stop(struct ieee80211_local *local);
358int sta_info_flush(struct ieee80211_local *local, 358int sta_info_flush(struct ieee80211_local *local,
359 struct ieee80211_sub_if_data *sdata); 359 struct ieee80211_sub_if_data *sdata);
360void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata);
361void __ieee80211_run_pending_flush(struct ieee80211_local *local);
360 362
361#endif /* STA_INFO_H */ 363#endif /* STA_INFO_H */