diff options
-rw-r--r-- | include/net/mac80211.h | 3 | ||||
-rw-r--r-- | net/mac80211/ieee80211.c | 6 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 11 | ||||
-rw-r--r-- | net/mac80211/ieee80211_iface.c | 2 | ||||
-rw-r--r-- | net/mac80211/ieee80211_sta.c | 20 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 184 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 11 | ||||
-rw-r--r-- | net/mac80211/tx.c | 8 |
8 files changed, 109 insertions, 136 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index c34fd9a6160a..8a086a8ac270 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -626,8 +626,7 @@ struct ieee80211_ops { | |||
626 | * station hwaddr for individual keys. aid of the station is given | 626 | * station hwaddr for individual keys. aid of the station is given |
627 | * to help low-level driver in selecting which key->hw_key_idx to use | 627 | * to help low-level driver in selecting which key->hw_key_idx to use |
628 | * for this key. TX control data will use the hw_key_idx selected by | 628 | * for this key. TX control data will use the hw_key_idx selected by |
629 | * the low-level driver. | 629 | * the low-level driver. */ |
630 | * Must be atomic. */ | ||
631 | int (*set_key)(struct ieee80211_hw *hw, set_key_cmd cmd, | 630 | int (*set_key)(struct ieee80211_hw *hw, set_key_cmd cmd, |
632 | u8 *addr, struct ieee80211_key_conf *key, int aid); | 631 | u8 *addr, struct ieee80211_key_conf *key, int aid); |
633 | 632 | ||
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 1981058907b7..566bdca32b86 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c | |||
@@ -628,8 +628,8 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) | |||
628 | /* Remove STA entry for the old peer */ | 628 | /* Remove STA entry for the old peer */ |
629 | sta = sta_info_get(local, sdata->u.wds.remote_addr); | 629 | sta = sta_info_get(local, sdata->u.wds.remote_addr); |
630 | if (sta) { | 630 | if (sta) { |
631 | sta_info_free(sta); | ||
631 | sta_info_put(sta); | 632 | sta_info_put(sta); |
632 | sta_info_free(sta, 0); | ||
633 | } else { | 633 | } else { |
634 | printk(KERN_DEBUG "%s: could not find STA entry for WDS link " | 634 | printk(KERN_DEBUG "%s: could not find STA entry for WDS link " |
635 | "peer " MAC_FMT "\n", | 635 | "peer " MAC_FMT "\n", |
@@ -776,13 +776,13 @@ static void ieee80211_stat_refresh(unsigned long data) | |||
776 | return; | 776 | return; |
777 | 777 | ||
778 | /* go through all stations */ | 778 | /* go through all stations */ |
779 | spin_lock_bh(&local->sta_lock); | 779 | read_lock_bh(&local->sta_lock); |
780 | list_for_each_entry(sta, &local->sta_list, list) { | 780 | list_for_each_entry(sta, &local->sta_list, list) { |
781 | sta->channel_use = (sta->channel_use_raw / local->stat_time) / | 781 | sta->channel_use = (sta->channel_use_raw / local->stat_time) / |
782 | CHAN_UTIL_PER_10MS; | 782 | CHAN_UTIL_PER_10MS; |
783 | sta->channel_use_raw = 0; | 783 | sta->channel_use_raw = 0; |
784 | } | 784 | } |
785 | spin_unlock_bh(&local->sta_lock); | 785 | read_unlock_bh(&local->sta_lock); |
786 | 786 | ||
787 | /* go through all subinterfaces */ | 787 | /* go through all subinterfaces */ |
788 | read_lock(&local->sub_if_lock); | 788 | read_lock(&local->sub_if_lock); |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ed00552b3418..e76a58678959 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -417,10 +417,9 @@ struct ieee80211_local { | |||
417 | struct sk_buff_head skb_queue_unreliable; | 417 | struct sk_buff_head skb_queue_unreliable; |
418 | 418 | ||
419 | /* Station data structures */ | 419 | /* Station data structures */ |
420 | spinlock_t sta_lock; /* mutex for STA data structures */ | 420 | rwlock_t sta_lock; /* protects STA data structures */ |
421 | int num_sta; /* number of stations in sta_list */ | 421 | int num_sta; /* number of stations in sta_list */ |
422 | struct list_head sta_list; | 422 | struct list_head sta_list; |
423 | struct list_head deleted_sta_list; | ||
424 | struct sta_info *sta_hash[STA_HASH_SIZE]; | 423 | struct sta_info *sta_hash[STA_HASH_SIZE]; |
425 | struct timer_list sta_cleanup; | 424 | struct timer_list sta_cleanup; |
426 | 425 | ||
@@ -669,9 +668,9 @@ static inline void __bss_tim_set(struct ieee80211_if_ap *bss, int aid) | |||
669 | static inline void bss_tim_set(struct ieee80211_local *local, | 668 | static inline void bss_tim_set(struct ieee80211_local *local, |
670 | struct ieee80211_if_ap *bss, int aid) | 669 | struct ieee80211_if_ap *bss, int aid) |
671 | { | 670 | { |
672 | spin_lock_bh(&local->sta_lock); | 671 | read_lock_bh(&local->sta_lock); |
673 | __bss_tim_set(bss, aid); | 672 | __bss_tim_set(bss, aid); |
674 | spin_unlock_bh(&local->sta_lock); | 673 | read_unlock_bh(&local->sta_lock); |
675 | } | 674 | } |
676 | 675 | ||
677 | static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, int aid) | 676 | static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, int aid) |
@@ -686,9 +685,9 @@ static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, int aid) | |||
686 | static inline void bss_tim_clear(struct ieee80211_local *local, | 685 | static inline void bss_tim_clear(struct ieee80211_local *local, |
687 | struct ieee80211_if_ap *bss, int aid) | 686 | struct ieee80211_if_ap *bss, int aid) |
688 | { | 687 | { |
689 | spin_lock_bh(&local->sta_lock); | 688 | read_lock_bh(&local->sta_lock); |
690 | __bss_tim_clear(bss, aid); | 689 | __bss_tim_clear(bss, aid); |
691 | spin_unlock_bh(&local->sta_lock); | 690 | read_unlock_bh(&local->sta_lock); |
692 | } | 691 | } |
693 | 692 | ||
694 | /** | 693 | /** |
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 8532a5ccdd1e..6db67767801d 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c | |||
@@ -272,8 +272,8 @@ void ieee80211_if_reinit(struct net_device *dev) | |||
272 | case IEEE80211_IF_TYPE_WDS: | 272 | case IEEE80211_IF_TYPE_WDS: |
273 | sta = sta_info_get(local, sdata->u.wds.remote_addr); | 273 | sta = sta_info_get(local, sdata->u.wds.remote_addr); |
274 | if (sta) { | 274 | if (sta) { |
275 | sta_info_free(sta); | ||
275 | sta_info_put(sta); | 276 | sta_info_put(sta); |
276 | sta_info_free(sta, 0); | ||
277 | } else { | 277 | } else { |
278 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 278 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
279 | printk(KERN_DEBUG "%s: Someone had deleted my STA " | 279 | printk(KERN_DEBUG "%s: Someone had deleted my STA " |
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 0d99b685df5f..9aee1abae127 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c | |||
@@ -773,7 +773,7 @@ static void ieee80211_associated(struct net_device *dev, | |||
773 | "range\n", | 773 | "range\n", |
774 | dev->name, MAC_ARG(ifsta->bssid)); | 774 | dev->name, MAC_ARG(ifsta->bssid)); |
775 | disassoc = 1; | 775 | disassoc = 1; |
776 | sta_info_free(sta, 0); | 776 | sta_info_free(sta); |
777 | ifsta->probereq_poll = 0; | 777 | ifsta->probereq_poll = 0; |
778 | } else { | 778 | } else { |
779 | ieee80211_send_probe_req(dev, ifsta->bssid, | 779 | ieee80211_send_probe_req(dev, ifsta->bssid, |
@@ -1890,7 +1890,7 @@ static int ieee80211_sta_active_ibss(struct net_device *dev) | |||
1890 | int active = 0; | 1890 | int active = 0; |
1891 | struct sta_info *sta; | 1891 | struct sta_info *sta; |
1892 | 1892 | ||
1893 | spin_lock_bh(&local->sta_lock); | 1893 | read_lock_bh(&local->sta_lock); |
1894 | list_for_each_entry(sta, &local->sta_list, list) { | 1894 | list_for_each_entry(sta, &local->sta_list, list) { |
1895 | if (sta->dev == dev && | 1895 | if (sta->dev == dev && |
1896 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, | 1896 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, |
@@ -1899,7 +1899,7 @@ static int ieee80211_sta_active_ibss(struct net_device *dev) | |||
1899 | break; | 1899 | break; |
1900 | } | 1900 | } |
1901 | } | 1901 | } |
1902 | spin_unlock_bh(&local->sta_lock); | 1902 | read_unlock_bh(&local->sta_lock); |
1903 | 1903 | ||
1904 | return active; | 1904 | return active; |
1905 | } | 1905 | } |
@@ -1909,16 +1909,24 @@ static void ieee80211_sta_expire(struct net_device *dev) | |||
1909 | { | 1909 | { |
1910 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1910 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1911 | struct sta_info *sta, *tmp; | 1911 | struct sta_info *sta, *tmp; |
1912 | LIST_HEAD(tmp_list); | ||
1912 | 1913 | ||
1913 | spin_lock_bh(&local->sta_lock); | 1914 | write_lock_bh(&local->sta_lock); |
1914 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) | 1915 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) |
1915 | if (time_after(jiffies, sta->last_rx + | 1916 | if (time_after(jiffies, sta->last_rx + |
1916 | IEEE80211_IBSS_INACTIVITY_LIMIT)) { | 1917 | IEEE80211_IBSS_INACTIVITY_LIMIT)) { |
1917 | printk(KERN_DEBUG "%s: expiring inactive STA " MAC_FMT | 1918 | printk(KERN_DEBUG "%s: expiring inactive STA " MAC_FMT |
1918 | "\n", dev->name, MAC_ARG(sta->addr)); | 1919 | "\n", dev->name, MAC_ARG(sta->addr)); |
1919 | sta_info_free(sta, 1); | 1920 | __sta_info_get(sta); |
1921 | sta_info_remove(sta); | ||
1922 | list_add(&sta->list, &tmp_list); | ||
1920 | } | 1923 | } |
1921 | spin_unlock_bh(&local->sta_lock); | 1924 | write_unlock_bh(&local->sta_lock); |
1925 | |||
1926 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) { | ||
1927 | sta_info_free(sta); | ||
1928 | sta_info_put(sta); | ||
1929 | } | ||
1922 | } | 1930 | } |
1923 | 1931 | ||
1924 | 1932 | ||
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index ab7b1f067c6e..34245b882c2b 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -32,38 +32,34 @@ static void sta_info_hash_add(struct ieee80211_local *local, | |||
32 | 32 | ||
33 | 33 | ||
34 | /* Caller must hold local->sta_lock */ | 34 | /* Caller must hold local->sta_lock */ |
35 | static void sta_info_hash_del(struct ieee80211_local *local, | 35 | static int sta_info_hash_del(struct ieee80211_local *local, |
36 | struct sta_info *sta) | 36 | struct sta_info *sta) |
37 | { | 37 | { |
38 | struct sta_info *s; | 38 | struct sta_info *s; |
39 | 39 | ||
40 | s = local->sta_hash[STA_HASH(sta->addr)]; | 40 | s = local->sta_hash[STA_HASH(sta->addr)]; |
41 | if (!s) | 41 | if (!s) |
42 | return; | 42 | return -ENOENT; |
43 | if (memcmp(s->addr, sta->addr, ETH_ALEN) == 0) { | 43 | if (s == sta) { |
44 | local->sta_hash[STA_HASH(sta->addr)] = s->hnext; | 44 | local->sta_hash[STA_HASH(sta->addr)] = s->hnext; |
45 | return; | 45 | return 0; |
46 | } | 46 | } |
47 | 47 | ||
48 | while (s->hnext && memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0) | 48 | while (s->hnext && s->hnext != sta) |
49 | s = s->hnext; | 49 | s = s->hnext; |
50 | if (s->hnext) | 50 | if (s->hnext) { |
51 | s->hnext = s->hnext->hnext; | 51 | s->hnext = sta->hnext; |
52 | else | 52 | return 0; |
53 | printk(KERN_ERR "%s: could not remove STA " MAC_FMT " from " | 53 | } |
54 | "hash table\n", local->mdev->name, MAC_ARG(sta->addr)); | ||
55 | } | ||
56 | 54 | ||
57 | static inline void __sta_info_get(struct sta_info *sta) | 55 | return -ENOENT; |
58 | { | ||
59 | kref_get(&sta->kref); | ||
60 | } | 56 | } |
61 | 57 | ||
62 | struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) | 58 | struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) |
63 | { | 59 | { |
64 | struct sta_info *sta; | 60 | struct sta_info *sta; |
65 | 61 | ||
66 | spin_lock_bh(&local->sta_lock); | 62 | read_lock_bh(&local->sta_lock); |
67 | sta = local->sta_hash[STA_HASH(addr)]; | 63 | sta = local->sta_hash[STA_HASH(addr)]; |
68 | while (sta) { | 64 | while (sta) { |
69 | if (memcmp(sta->addr, addr, ETH_ALEN) == 0) { | 65 | if (memcmp(sta->addr, addr, ETH_ALEN) == 0) { |
@@ -72,7 +68,7 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) | |||
72 | } | 68 | } |
73 | sta = sta->hnext; | 69 | sta = sta->hnext; |
74 | } | 70 | } |
75 | spin_unlock_bh(&local->sta_lock); | 71 | read_unlock_bh(&local->sta_lock); |
76 | 72 | ||
77 | return sta; | 73 | return sta; |
78 | } | 74 | } |
@@ -85,7 +81,7 @@ int sta_info_min_txrate_get(struct ieee80211_local *local) | |||
85 | int min_txrate = 9999999; | 81 | int min_txrate = 9999999; |
86 | int i; | 82 | int i; |
87 | 83 | ||
88 | spin_lock_bh(&local->sta_lock); | 84 | read_lock_bh(&local->sta_lock); |
89 | mode = local->oper_hw_mode; | 85 | mode = local->oper_hw_mode; |
90 | for (i = 0; i < STA_HASH_SIZE; i++) { | 86 | for (i = 0; i < STA_HASH_SIZE; i++) { |
91 | sta = local->sta_hash[i]; | 87 | sta = local->sta_hash[i]; |
@@ -95,7 +91,7 @@ int sta_info_min_txrate_get(struct ieee80211_local *local) | |||
95 | sta = sta->hnext; | 91 | sta = sta->hnext; |
96 | } | 92 | } |
97 | } | 93 | } |
98 | spin_unlock_bh(&local->sta_lock); | 94 | read_unlock_bh(&local->sta_lock); |
99 | if (min_txrate == 9999999) | 95 | if (min_txrate == 9999999) |
100 | min_txrate = 0; | 96 | min_txrate = 0; |
101 | 97 | ||
@@ -150,7 +146,6 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, | |||
150 | sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp); | 146 | sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp); |
151 | if (!sta->rate_ctrl_priv) { | 147 | if (!sta->rate_ctrl_priv) { |
152 | rate_control_put(sta->rate_ctrl); | 148 | rate_control_put(sta->rate_ctrl); |
153 | kref_put(&sta->kref, sta_info_release); | ||
154 | kfree(sta); | 149 | kfree(sta); |
155 | return NULL; | 150 | return NULL; |
156 | } | 151 | } |
@@ -162,14 +157,14 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, | |||
162 | skb_queue_head_init(&sta->tx_filtered); | 157 | skb_queue_head_init(&sta->tx_filtered); |
163 | __sta_info_get(sta); /* sta used by caller, decremented by | 158 | __sta_info_get(sta); /* sta used by caller, decremented by |
164 | * sta_info_put() */ | 159 | * sta_info_put() */ |
165 | spin_lock_bh(&local->sta_lock); | 160 | write_lock_bh(&local->sta_lock); |
166 | list_add(&sta->list, &local->sta_list); | 161 | list_add(&sta->list, &local->sta_list); |
167 | local->num_sta++; | 162 | local->num_sta++; |
168 | sta_info_hash_add(local, sta); | 163 | sta_info_hash_add(local, sta); |
169 | spin_unlock_bh(&local->sta_lock); | ||
170 | if (local->ops->sta_table_notification) | 164 | if (local->ops->sta_table_notification) |
171 | local->ops->sta_table_notification(local_to_hw(local), | 165 | local->ops->sta_table_notification(local_to_hw(local), |
172 | local->num_sta); | 166 | local->num_sta); |
167 | write_unlock_bh(&local->sta_lock); | ||
173 | sta->key_idx_compression = HW_KEY_IDX_INVALID; | 168 | sta->key_idx_compression = HW_KEY_IDX_INVALID; |
174 | 169 | ||
175 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 170 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
@@ -178,47 +173,25 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, | |||
178 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 173 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
179 | 174 | ||
180 | #ifdef CONFIG_MAC80211_DEBUGFS | 175 | #ifdef CONFIG_MAC80211_DEBUGFS |
181 | if (!in_interrupt()) { | 176 | /* debugfs entry adding might sleep, so schedule process |
182 | sta->debugfs_registered = 1; | 177 | * context task for adding entry for STAs that do not yet |
183 | ieee80211_sta_debugfs_add(sta); | 178 | * have one. */ |
184 | rate_control_add_sta_debugfs(sta); | 179 | queue_work(local->hw.workqueue, &local->sta_debugfs_add); |
185 | } else { | ||
186 | /* debugfs entry adding might sleep, so schedule process | ||
187 | * context task for adding entry for STAs that do not yet | ||
188 | * have one. */ | ||
189 | queue_work(local->hw.workqueue, &local->sta_debugfs_add); | ||
190 | } | ||
191 | #endif | 180 | #endif |
192 | 181 | ||
193 | return sta; | 182 | return sta; |
194 | } | 183 | } |
195 | 184 | ||
196 | static void finish_sta_info_free(struct ieee80211_local *local, | 185 | /* Caller must hold local->sta_lock */ |
197 | struct sta_info *sta) | 186 | void sta_info_remove(struct sta_info *sta) |
198 | { | ||
199 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
200 | printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n", | ||
201 | local->mdev->name, MAC_ARG(sta->addr)); | ||
202 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
203 | |||
204 | if (sta->key) { | ||
205 | ieee80211_debugfs_key_remove(sta->key); | ||
206 | ieee80211_key_free(sta->key); | ||
207 | sta->key = NULL; | ||
208 | } | ||
209 | |||
210 | rate_control_remove_sta_debugfs(sta); | ||
211 | ieee80211_sta_debugfs_remove(sta); | ||
212 | |||
213 | sta_info_put(sta); | ||
214 | } | ||
215 | |||
216 | static void sta_info_remove(struct sta_info *sta) | ||
217 | { | 187 | { |
218 | struct ieee80211_local *local = sta->local; | 188 | struct ieee80211_local *local = sta->local; |
219 | struct ieee80211_sub_if_data *sdata; | 189 | struct ieee80211_sub_if_data *sdata; |
220 | 190 | ||
221 | sta_info_hash_del(local, sta); | 191 | /* don't do anything if we've been removed already */ |
192 | if (sta_info_hash_del(local, sta)) | ||
193 | return; | ||
194 | |||
222 | list_del(&sta->list); | 195 | list_del(&sta->list); |
223 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | 196 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); |
224 | if (sta->flags & WLAN_STA_PS) { | 197 | if (sta->flags & WLAN_STA_PS) { |
@@ -228,30 +201,29 @@ static void sta_info_remove(struct sta_info *sta) | |||
228 | } | 201 | } |
229 | local->num_sta--; | 202 | local->num_sta--; |
230 | sta_info_remove_aid_ptr(sta); | 203 | sta_info_remove_aid_ptr(sta); |
204 | |||
205 | if (local->ops->sta_table_notification) | ||
206 | local->ops->sta_table_notification(local_to_hw(local), | ||
207 | local->num_sta); | ||
231 | } | 208 | } |
232 | 209 | ||
233 | void sta_info_free(struct sta_info *sta, int locked) | 210 | void sta_info_free(struct sta_info *sta) |
234 | { | 211 | { |
235 | struct sk_buff *skb; | 212 | struct sk_buff *skb; |
236 | struct ieee80211_local *local = sta->local; | 213 | struct ieee80211_local *local = sta->local; |
237 | 214 | ||
238 | if (!locked) { | 215 | might_sleep(); |
239 | spin_lock_bh(&local->sta_lock); | 216 | |
240 | sta_info_remove(sta); | 217 | write_lock_bh(&local->sta_lock); |
241 | spin_unlock_bh(&local->sta_lock); | 218 | sta_info_remove(sta); |
242 | } else { | 219 | write_unlock_bh(&local->sta_lock); |
243 | sta_info_remove(sta); | ||
244 | } | ||
245 | if (local->ops->sta_table_notification) | ||
246 | local->ops->sta_table_notification(local_to_hw(local), | ||
247 | local->num_sta); | ||
248 | 220 | ||
249 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { | 221 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { |
250 | local->total_ps_buffered--; | 222 | local->total_ps_buffered--; |
251 | dev_kfree_skb_any(skb); | 223 | dev_kfree_skb(skb); |
252 | } | 224 | } |
253 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { | 225 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { |
254 | dev_kfree_skb_any(skb); | 226 | dev_kfree_skb(skb); |
255 | } | 227 | } |
256 | 228 | ||
257 | if (sta->key) { | 229 | if (sta->key) { |
@@ -276,13 +248,21 @@ void sta_info_free(struct sta_info *sta, int locked) | |||
276 | sta->key_idx_compression = HW_KEY_IDX_INVALID; | 248 | sta->key_idx_compression = HW_KEY_IDX_INVALID; |
277 | } | 249 | } |
278 | 250 | ||
279 | #ifdef CONFIG_MAC80211_DEBUGFS | 251 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
280 | if (in_atomic()) { | 252 | printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n", |
281 | list_add(&sta->list, &local->deleted_sta_list); | 253 | local->mdev->name, MAC_ARG(sta->addr)); |
282 | queue_work(local->hw.workqueue, &local->sta_debugfs_add); | 254 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
283 | } else | 255 | |
284 | #endif | 256 | if (sta->key) { |
285 | finish_sta_info_free(local, sta); | 257 | ieee80211_debugfs_key_remove(sta->key); |
258 | ieee80211_key_free(sta->key); | ||
259 | sta->key = NULL; | ||
260 | } | ||
261 | |||
262 | rate_control_remove_sta_debugfs(sta); | ||
263 | ieee80211_sta_debugfs_remove(sta); | ||
264 | |||
265 | sta_info_put(sta); | ||
286 | } | 266 | } |
287 | 267 | ||
288 | 268 | ||
@@ -343,13 +323,13 @@ static void sta_info_cleanup(unsigned long data) | |||
343 | struct ieee80211_local *local = (struct ieee80211_local *) data; | 323 | struct ieee80211_local *local = (struct ieee80211_local *) data; |
344 | struct sta_info *sta; | 324 | struct sta_info *sta; |
345 | 325 | ||
346 | spin_lock_bh(&local->sta_lock); | 326 | read_lock_bh(&local->sta_lock); |
347 | list_for_each_entry(sta, &local->sta_list, list) { | 327 | list_for_each_entry(sta, &local->sta_list, list) { |
348 | __sta_info_get(sta); | 328 | __sta_info_get(sta); |
349 | sta_info_cleanup_expire_buffered(local, sta); | 329 | sta_info_cleanup_expire_buffered(local, sta); |
350 | sta_info_put(sta); | 330 | sta_info_put(sta); |
351 | } | 331 | } |
352 | spin_unlock_bh(&local->sta_lock); | 332 | read_unlock_bh(&local->sta_lock); |
353 | 333 | ||
354 | local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL; | 334 | local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL; |
355 | add_timer(&local->sta_cleanup); | 335 | add_timer(&local->sta_cleanup); |
@@ -363,35 +343,20 @@ static void sta_info_debugfs_add_task(struct work_struct *work) | |||
363 | struct sta_info *sta, *tmp; | 343 | struct sta_info *sta, *tmp; |
364 | 344 | ||
365 | while (1) { | 345 | while (1) { |
366 | spin_lock_bh(&local->sta_lock); | ||
367 | if (!list_empty(&local->deleted_sta_list)) { | ||
368 | sta = list_entry(local->deleted_sta_list.next, | ||
369 | struct sta_info, list); | ||
370 | list_del(local->deleted_sta_list.next); | ||
371 | } else | ||
372 | sta = NULL; | ||
373 | spin_unlock_bh(&local->sta_lock); | ||
374 | if (!sta) | ||
375 | break; | ||
376 | finish_sta_info_free(local, sta); | ||
377 | } | ||
378 | |||
379 | while (1) { | ||
380 | sta = NULL; | 346 | sta = NULL; |
381 | spin_lock_bh(&local->sta_lock); | 347 | read_lock_bh(&local->sta_lock); |
382 | list_for_each_entry(tmp, &local->sta_list, list) { | 348 | list_for_each_entry(tmp, &local->sta_list, list) { |
383 | if (!tmp->debugfs_registered) { | 349 | if (!tmp->debugfs.dir) { |
384 | sta = tmp; | 350 | sta = tmp; |
385 | __sta_info_get(sta); | 351 | __sta_info_get(sta); |
386 | break; | 352 | break; |
387 | } | 353 | } |
388 | } | 354 | } |
389 | spin_unlock_bh(&local->sta_lock); | 355 | read_unlock_bh(&local->sta_lock); |
390 | 356 | ||
391 | if (!sta) | 357 | if (!sta) |
392 | break; | 358 | break; |
393 | 359 | ||
394 | sta->debugfs_registered = 1; | ||
395 | ieee80211_sta_debugfs_add(sta); | 360 | ieee80211_sta_debugfs_add(sta); |
396 | rate_control_add_sta_debugfs(sta); | 361 | rate_control_add_sta_debugfs(sta); |
397 | sta_info_put(sta); | 362 | sta_info_put(sta); |
@@ -401,9 +366,8 @@ static void sta_info_debugfs_add_task(struct work_struct *work) | |||
401 | 366 | ||
402 | void sta_info_init(struct ieee80211_local *local) | 367 | void sta_info_init(struct ieee80211_local *local) |
403 | { | 368 | { |
404 | spin_lock_init(&local->sta_lock); | 369 | rwlock_init(&local->sta_lock); |
405 | INIT_LIST_HEAD(&local->sta_list); | 370 | INIT_LIST_HEAD(&local->sta_list); |
406 | INIT_LIST_HEAD(&local->deleted_sta_list); | ||
407 | 371 | ||
408 | init_timer(&local->sta_cleanup); | 372 | init_timer(&local->sta_cleanup); |
409 | local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL; | 373 | local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL; |
@@ -423,17 +387,8 @@ int sta_info_start(struct ieee80211_local *local) | |||
423 | 387 | ||
424 | void sta_info_stop(struct ieee80211_local *local) | 388 | void sta_info_stop(struct ieee80211_local *local) |
425 | { | 389 | { |
426 | struct sta_info *sta, *tmp; | ||
427 | |||
428 | del_timer(&local->sta_cleanup); | 390 | del_timer(&local->sta_cleanup); |
429 | 391 | sta_info_flush(local, NULL); | |
430 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { | ||
431 | /* sta_info_free must be called with 0 as the last | ||
432 | * parameter to ensure all debugfs sta entries are | ||
433 | * unregistered. We don't need locking at this | ||
434 | * point. */ | ||
435 | sta_info_free(sta, 0); | ||
436 | } | ||
437 | } | 392 | } |
438 | 393 | ||
439 | void sta_info_remove_aid_ptr(struct sta_info *sta) | 394 | void sta_info_remove_aid_ptr(struct sta_info *sta) |
@@ -461,10 +416,19 @@ void sta_info_remove_aid_ptr(struct sta_info *sta) | |||
461 | void sta_info_flush(struct ieee80211_local *local, struct net_device *dev) | 416 | void sta_info_flush(struct ieee80211_local *local, struct net_device *dev) |
462 | { | 417 | { |
463 | struct sta_info *sta, *tmp; | 418 | struct sta_info *sta, *tmp; |
419 | LIST_HEAD(tmp_list); | ||
464 | 420 | ||
465 | spin_lock_bh(&local->sta_lock); | 421 | write_lock_bh(&local->sta_lock); |
466 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) | 422 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) |
467 | if (!dev || dev == sta->dev) | 423 | if (!dev || dev == sta->dev) { |
468 | sta_info_free(sta, 1); | 424 | __sta_info_get(sta); |
469 | spin_unlock_bh(&local->sta_lock); | 425 | sta_info_remove(sta); |
426 | list_add_tail(&sta->list, &tmp_list); | ||
427 | } | ||
428 | write_unlock_bh(&local->sta_lock); | ||
429 | |||
430 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) { | ||
431 | sta_info_free(sta); | ||
432 | sta_info_put(sta); | ||
433 | } | ||
470 | } | 434 | } |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index b5591d2f60a4..b5ef72379add 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -98,9 +98,6 @@ struct sta_info { | |||
98 | * filtering; used only if sta->key is not | 98 | * filtering; used only if sta->key is not |
99 | * set */ | 99 | * set */ |
100 | 100 | ||
101 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
102 | int debugfs_registered; | ||
103 | #endif | ||
104 | int assoc_ap; /* whether this is an AP that we are | 101 | int assoc_ap; /* whether this is an AP that we are |
105 | * associated with as a client */ | 102 | * associated with as a client */ |
106 | 103 | ||
@@ -149,12 +146,18 @@ struct sta_info { | |||
149 | */ | 146 | */ |
150 | #define STA_INFO_CLEANUP_INTERVAL (10 * HZ) | 147 | #define STA_INFO_CLEANUP_INTERVAL (10 * HZ) |
151 | 148 | ||
149 | static inline void __sta_info_get(struct sta_info *sta) | ||
150 | { | ||
151 | kref_get(&sta->kref); | ||
152 | } | ||
153 | |||
152 | struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr); | 154 | struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr); |
153 | int sta_info_min_txrate_get(struct ieee80211_local *local); | 155 | int sta_info_min_txrate_get(struct ieee80211_local *local); |
154 | void sta_info_put(struct sta_info *sta); | 156 | void sta_info_put(struct sta_info *sta); |
155 | struct sta_info * sta_info_add(struct ieee80211_local *local, | 157 | struct sta_info * sta_info_add(struct ieee80211_local *local, |
156 | struct net_device *dev, u8 *addr, gfp_t gfp); | 158 | struct net_device *dev, u8 *addr, gfp_t gfp); |
157 | void sta_info_free(struct sta_info *sta, int locked); | 159 | void sta_info_remove(struct sta_info *sta); |
160 | void sta_info_free(struct sta_info *sta); | ||
158 | void sta_info_init(struct ieee80211_local *local); | 161 | void sta_info_init(struct ieee80211_local *local); |
159 | int sta_info_start(struct ieee80211_local *local); | 162 | int sta_info_start(struct ieee80211_local *local); |
160 | void sta_info_stop(struct ieee80211_local *local); | 163 | void sta_info_stop(struct ieee80211_local *local); |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index dc128b412eab..2a1a7d457136 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -306,7 +306,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) | |||
306 | } | 306 | } |
307 | read_unlock(&local->sub_if_lock); | 307 | read_unlock(&local->sub_if_lock); |
308 | 308 | ||
309 | spin_lock_bh(&local->sta_lock); | 309 | read_lock_bh(&local->sta_lock); |
310 | list_for_each_entry(sta, &local->sta_list, list) { | 310 | list_for_each_entry(sta, &local->sta_list, list) { |
311 | skb = skb_dequeue(&sta->ps_tx_buf); | 311 | skb = skb_dequeue(&sta->ps_tx_buf); |
312 | if (skb) { | 312 | if (skb) { |
@@ -315,7 +315,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) | |||
315 | } | 315 | } |
316 | total += skb_queue_len(&sta->ps_tx_buf); | 316 | total += skb_queue_len(&sta->ps_tx_buf); |
317 | } | 317 | } |
318 | spin_unlock_bh(&local->sta_lock); | 318 | read_unlock_bh(&local->sta_lock); |
319 | 319 | ||
320 | local->total_ps_buffered = total; | 320 | local->total_ps_buffered = total; |
321 | printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", | 321 | printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", |
@@ -1629,7 +1629,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, | |||
1629 | 1629 | ||
1630 | /* Generate bitmap for TIM only if there are any STAs in power save | 1630 | /* Generate bitmap for TIM only if there are any STAs in power save |
1631 | * mode. */ | 1631 | * mode. */ |
1632 | spin_lock_bh(&local->sta_lock); | 1632 | read_lock_bh(&local->sta_lock); |
1633 | if (atomic_read(&bss->num_sta_ps) > 0) | 1633 | if (atomic_read(&bss->num_sta_ps) > 0) |
1634 | /* in the hope that this is faster than | 1634 | /* in the hope that this is faster than |
1635 | * checking byte-for-byte */ | 1635 | * checking byte-for-byte */ |
@@ -1680,7 +1680,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, | |||
1680 | *pos++ = aid0; /* Bitmap control */ | 1680 | *pos++ = aid0; /* Bitmap control */ |
1681 | *pos++ = 0; /* Part Virt Bitmap */ | 1681 | *pos++ = 0; /* Part Virt Bitmap */ |
1682 | } | 1682 | } |
1683 | spin_unlock_bh(&local->sta_lock); | 1683 | read_unlock_bh(&local->sta_lock); |
1684 | } | 1684 | } |
1685 | 1685 | ||
1686 | struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id, | 1686 | struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id, |