aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
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 */