diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2008-04-11 15:40:35 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-04-16 15:59:57 -0400 |
commit | b16bd15c379410f2aa47837aa4a0de5712856ad5 (patch) | |
tree | fd391bb12b146aaf001ae169a4c98f7088299edd /net | |
parent | 6b914c521687ae6cb8923c7235fd69b7bc027703 (diff) |
mac80211: fix spinlock recursion
When STAs are expired, we need to hold the sta_lock. Using
the same lock for keys too would then mean we'd need another
key free function, and that'll just lead to confusion, so just
use a new spinlock for all key lists.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/ieee80211_i.h | 10 | ||||
-rw-r--r-- | net/mac80211/key.c | 20 | ||||
-rw-r--r-- | net/mac80211/main.c | 2 |
3 files changed, 20 insertions, 12 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c642538e8282..ce566f3e0169 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -600,8 +600,7 @@ struct ieee80211_local { | |||
600 | /* | 600 | /* |
601 | * The lock only protects the list, hash, timer and counter | 601 | * The lock only protects the list, hash, timer and counter |
602 | * against manipulation, reads are done in RCU. Additionally, | 602 | * against manipulation, reads are done in RCU. Additionally, |
603 | * the lock protects each BSS's TIM bitmap, a few items in | 603 | * the lock protects each BSS's TIM bitmap. |
604 | * STA info structures and various key pointers. | ||
605 | */ | 604 | */ |
606 | spinlock_t sta_lock; | 605 | spinlock_t sta_lock; |
607 | unsigned long num_sta; | 606 | unsigned long num_sta; |
@@ -635,6 +634,13 @@ struct ieee80211_local { | |||
635 | 634 | ||
636 | struct list_head interfaces; | 635 | struct list_head interfaces; |
637 | 636 | ||
637 | /* | ||
638 | * Key lock, protects sdata's key_list and sta_info's | ||
639 | * key pointers (write access, they're RCU.) | ||
640 | */ | ||
641 | spinlock_t key_lock; | ||
642 | |||
643 | |||
638 | bool sta_sw_scanning; | 644 | bool sta_sw_scanning; |
639 | bool sta_hw_scanning; | 645 | bool sta_hw_scanning; |
640 | int scan_channel_idx; | 646 | int scan_channel_idx; |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index acf8d0370a37..b98711dcdc54 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -210,9 +210,9 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) | |||
210 | { | 210 | { |
211 | unsigned long flags; | 211 | unsigned long flags; |
212 | 212 | ||
213 | spin_lock_irqsave(&sdata->local->sta_lock, flags); | 213 | spin_lock_irqsave(&sdata->local->key_lock, flags); |
214 | __ieee80211_set_default_key(sdata, idx); | 214 | __ieee80211_set_default_key(sdata, idx); |
215 | spin_unlock_irqrestore(&sdata->local->sta_lock, flags); | 215 | spin_unlock_irqrestore(&sdata->local->key_lock, flags); |
216 | } | 216 | } |
217 | 217 | ||
218 | 218 | ||
@@ -339,7 +339,7 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
339 | } | 339 | } |
340 | } | 340 | } |
341 | 341 | ||
342 | spin_lock_irqsave(&sdata->local->sta_lock, flags); | 342 | spin_lock_irqsave(&sdata->local->key_lock, flags); |
343 | 343 | ||
344 | if (sta) | 344 | if (sta) |
345 | old_key = sta->key; | 345 | old_key = sta->key; |
@@ -348,7 +348,7 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
348 | 348 | ||
349 | __ieee80211_key_replace(sdata, sta, old_key, key); | 349 | __ieee80211_key_replace(sdata, sta, old_key, key); |
350 | 350 | ||
351 | spin_unlock_irqrestore(&sdata->local->sta_lock, flags); | 351 | spin_unlock_irqrestore(&sdata->local->key_lock, flags); |
352 | 352 | ||
353 | /* free old key later */ | 353 | /* free old key later */ |
354 | add_todo(old_key, KEY_FLAG_TODO_DELETE); | 354 | add_todo(old_key, KEY_FLAG_TODO_DELETE); |
@@ -377,9 +377,9 @@ void ieee80211_key_free(struct ieee80211_key *key) | |||
377 | if (!key) | 377 | if (!key) |
378 | return; | 378 | return; |
379 | 379 | ||
380 | spin_lock_irqsave(&key->sdata->local->sta_lock, flags); | 380 | spin_lock_irqsave(&key->sdata->local->key_lock, flags); |
381 | __ieee80211_key_free(key); | 381 | __ieee80211_key_free(key); |
382 | spin_unlock_irqrestore(&key->sdata->local->sta_lock, flags); | 382 | spin_unlock_irqrestore(&key->sdata->local->key_lock, flags); |
383 | } | 383 | } |
384 | 384 | ||
385 | /* | 385 | /* |
@@ -397,10 +397,10 @@ static void ieee80211_todo_for_each_key(struct ieee80211_sub_if_data *sdata, | |||
397 | 397 | ||
398 | might_sleep(); | 398 | might_sleep(); |
399 | 399 | ||
400 | spin_lock_irqsave(&sdata->local->sta_lock, flags); | 400 | spin_lock_irqsave(&sdata->local->key_lock, flags); |
401 | list_for_each_entry(key, &sdata->key_list, list) | 401 | list_for_each_entry(key, &sdata->key_list, list) |
402 | add_todo(key, todo_flags); | 402 | add_todo(key, todo_flags); |
403 | spin_unlock_irqrestore(&sdata->local->sta_lock, flags); | 403 | spin_unlock_irqrestore(&sdata->local->key_lock, flags); |
404 | 404 | ||
405 | ieee80211_key_todo(); | 405 | ieee80211_key_todo(); |
406 | } | 406 | } |
@@ -506,10 +506,10 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | |||
506 | 506 | ||
507 | ieee80211_debugfs_key_remove_default(sdata); | 507 | ieee80211_debugfs_key_remove_default(sdata); |
508 | 508 | ||
509 | spin_lock_irqsave(&sdata->local->sta_lock, flags); | 509 | spin_lock_irqsave(&sdata->local->key_lock, flags); |
510 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) | 510 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) |
511 | __ieee80211_key_free(key); | 511 | __ieee80211_key_free(key); |
512 | spin_unlock_irqrestore(&sdata->local->sta_lock, flags); | 512 | spin_unlock_irqrestore(&sdata->local->key_lock, flags); |
513 | 513 | ||
514 | __ieee80211_key_todo(); | 514 | __ieee80211_key_todo(); |
515 | 515 | ||
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index bfcbcf5353ad..e9a978979d38 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -1587,6 +1587,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
1587 | 1587 | ||
1588 | INIT_LIST_HEAD(&local->interfaces); | 1588 | INIT_LIST_HEAD(&local->interfaces); |
1589 | 1589 | ||
1590 | spin_lock_init(&local->key_lock); | ||
1591 | |||
1590 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work); | 1592 | INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work); |
1591 | 1593 | ||
1592 | sta_info_init(local); | 1594 | sta_info_init(local); |