diff options
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r-- | net/mac80211/sta_info.c | 48 |
1 files changed, 22 insertions, 26 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index cedd73a0c875..5540cbf7c445 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -51,17 +51,15 @@ | |||
51 | * | 51 | * |
52 | * In order to remove a STA info structure, the caller needs to first | 52 | * In order to remove a STA info structure, the caller needs to first |
53 | * unlink it (sta_info_unlink()) from the list and hash tables and | 53 | * unlink it (sta_info_unlink()) from the list and hash tables and |
54 | * then destroy it while holding the RTNL; sta_info_destroy() will wait | 54 | * then destroy it; sta_info_destroy() will wait for an RCU grace period |
55 | * for an RCU grace period to elapse before actually freeing it. Due to | 55 | * to elapse before actually freeing it. Due to the pinning and the |
56 | * the pinning and the possibility of multiple callers trying to remove | 56 | * possibility of multiple callers trying to remove the same STA info at |
57 | * the same STA info at the same time, sta_info_unlink() can clear the | 57 | * the same time, sta_info_unlink() can clear the STA info pointer it is |
58 | * STA info pointer it is passed to indicate that the STA info is owned | 58 | * passed to indicate that the STA info is owned by somebody else now. |
59 | * by somebody else now. | ||
60 | * | 59 | * |
61 | * If sta_info_unlink() did not clear the pointer then the caller owns | 60 | * If sta_info_unlink() did not clear the pointer then the caller owns |
62 | * the STA info structure now and is responsible of destroying it with | 61 | * the STA info structure now and is responsible of destroying it with |
63 | * a call to sta_info_destroy(), not before RCU synchronisation, of | 62 | * a call to sta_info_destroy(). |
64 | * course. Note that sta_info_destroy() must be protected by the RTNL. | ||
65 | * | 63 | * |
66 | * In all other cases, there is no concept of ownership on a STA entry, | 64 | * In all other cases, there is no concept of ownership on a STA entry, |
67 | * each structure is owned by the global hash table/list until it is | 65 | * each structure is owned by the global hash table/list until it is |
@@ -164,7 +162,6 @@ void sta_info_destroy(struct sta_info *sta) | |||
164 | struct sk_buff *skb; | 162 | struct sk_buff *skb; |
165 | int i; | 163 | int i; |
166 | 164 | ||
167 | ASSERT_RTNL(); | ||
168 | might_sleep(); | 165 | might_sleep(); |
169 | 166 | ||
170 | if (!sta) | 167 | if (!sta) |
@@ -180,22 +177,16 @@ void sta_info_destroy(struct sta_info *sta) | |||
180 | mesh_plink_deactivate(sta); | 177 | mesh_plink_deactivate(sta); |
181 | #endif | 178 | #endif |
182 | 179 | ||
183 | if (sta->key) { | 180 | /* |
184 | /* | 181 | * We have only unlinked the key, and actually destroying it |
185 | * NOTE: This will call synchronize_rcu() internally to | 182 | * may mean it is removed from hardware which requires that |
186 | * make sure no key references can be in use. We rely on | 183 | * the key->sta pointer is still valid, so flush the key todo |
187 | * that when we take this branch to make sure nobody can | 184 | * list here. |
188 | * reference this STA struct any longer! | 185 | * |
189 | */ | 186 | * ieee80211_key_todo() will synchronize_rcu() so after this |
190 | ieee80211_key_free(sta->key); | 187 | * nothing can reference this sta struct any more. |
191 | WARN_ON(sta->key); | 188 | */ |
192 | } else { | 189 | ieee80211_key_todo(); |
193 | /* | ||
194 | * Make sure that nobody can reference this STA struct | ||
195 | * any longer. | ||
196 | */ | ||
197 | synchronize_rcu(); | ||
198 | } | ||
199 | 190 | ||
200 | #ifdef CONFIG_MAC80211_MESH | 191 | #ifdef CONFIG_MAC80211_MESH |
201 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | 192 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) |
@@ -439,6 +430,11 @@ void __sta_info_unlink(struct sta_info **sta) | |||
439 | return; | 430 | return; |
440 | } | 431 | } |
441 | 432 | ||
433 | if ((*sta)->key) { | ||
434 | ieee80211_key_free((*sta)->key); | ||
435 | WARN_ON((*sta)->key); | ||
436 | } | ||
437 | |||
442 | list_del(&(*sta)->list); | 438 | list_del(&(*sta)->list); |
443 | 439 | ||
444 | if ((*sta)->flags & WLAN_STA_PS) { | 440 | if ((*sta)->flags & WLAN_STA_PS) { |
@@ -652,7 +648,7 @@ static void sta_info_debugfs_add_work(struct work_struct *work) | |||
652 | } | 648 | } |
653 | #endif | 649 | #endif |
654 | 650 | ||
655 | void __ieee80211_run_pending_flush(struct ieee80211_local *local) | 651 | static void __ieee80211_run_pending_flush(struct ieee80211_local *local) |
656 | { | 652 | { |
657 | struct sta_info *sta; | 653 | struct sta_info *sta; |
658 | unsigned long flags; | 654 | unsigned long flags; |