diff options
-rw-r--r-- | net/mac80211/ieee80211_i.h | 11 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 251 | ||||
-rw-r--r-- | net/mac80211/tx.c | 4 |
3 files changed, 63 insertions, 203 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index eca6063e287c..8e5b892834bc 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -855,18 +855,15 @@ struct ieee80211_local { | |||
855 | 855 | ||
856 | /* Station data */ | 856 | /* Station data */ |
857 | /* | 857 | /* |
858 | * The mutex only protects the list and counter, | 858 | * The mutex only protects the list, hash table and |
859 | * reads are done in RCU. | 859 | * counter, reads are done with RCU. |
860 | * Additionally, the lock protects the hash table, | ||
861 | * the pending list and each BSS's TIM bitmap. | ||
862 | */ | 860 | */ |
863 | struct mutex sta_mtx; | 861 | struct mutex sta_mtx; |
864 | spinlock_t sta_lock; | 862 | spinlock_t tim_lock; |
865 | unsigned long num_sta; | 863 | unsigned long num_sta; |
866 | struct list_head sta_list, sta_pending_list; | 864 | struct list_head sta_list; |
867 | struct sta_info __rcu *sta_hash[STA_HASH_SIZE]; | 865 | struct sta_info __rcu *sta_hash[STA_HASH_SIZE]; |
868 | struct timer_list sta_cleanup; | 866 | struct timer_list sta_cleanup; |
869 | struct work_struct sta_finish_work; | ||
870 | int sta_generation; | 867 | int sta_generation; |
871 | 868 | ||
872 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; | 869 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index aa9293d7f3f0..2db01e9541e7 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -62,14 +62,14 @@ | |||
62 | * freed before they are done using it. | 62 | * freed before they are done using it. |
63 | */ | 63 | */ |
64 | 64 | ||
65 | /* Caller must hold local->sta_lock */ | 65 | /* Caller must hold local->sta_mtx */ |
66 | static int sta_info_hash_del(struct ieee80211_local *local, | 66 | static int sta_info_hash_del(struct ieee80211_local *local, |
67 | struct sta_info *sta) | 67 | struct sta_info *sta) |
68 | { | 68 | { |
69 | struct sta_info *s; | 69 | struct sta_info *s; |
70 | 70 | ||
71 | s = rcu_dereference_protected(local->sta_hash[STA_HASH(sta->sta.addr)], | 71 | s = rcu_dereference_protected(local->sta_hash[STA_HASH(sta->sta.addr)], |
72 | lockdep_is_held(&local->sta_lock)); | 72 | lockdep_is_held(&local->sta_mtx)); |
73 | if (!s) | 73 | if (!s) |
74 | return -ENOENT; | 74 | return -ENOENT; |
75 | if (s == sta) { | 75 | if (s == sta) { |
@@ -81,7 +81,7 @@ static int sta_info_hash_del(struct ieee80211_local *local, | |||
81 | while (rcu_access_pointer(s->hnext) && | 81 | while (rcu_access_pointer(s->hnext) && |
82 | rcu_access_pointer(s->hnext) != sta) | 82 | rcu_access_pointer(s->hnext) != sta) |
83 | s = rcu_dereference_protected(s->hnext, | 83 | s = rcu_dereference_protected(s->hnext, |
84 | lockdep_is_held(&local->sta_lock)); | 84 | lockdep_is_held(&local->sta_mtx)); |
85 | if (rcu_access_pointer(s->hnext)) { | 85 | if (rcu_access_pointer(s->hnext)) { |
86 | RCU_INIT_POINTER(s->hnext, sta->hnext); | 86 | RCU_INIT_POINTER(s->hnext, sta->hnext); |
87 | return 0; | 87 | return 0; |
@@ -98,14 +98,12 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, | |||
98 | struct sta_info *sta; | 98 | struct sta_info *sta; |
99 | 99 | ||
100 | sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], | 100 | sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], |
101 | lockdep_is_held(&local->sta_lock) || | ||
102 | lockdep_is_held(&local->sta_mtx)); | 101 | lockdep_is_held(&local->sta_mtx)); |
103 | while (sta) { | 102 | while (sta) { |
104 | if (sta->sdata == sdata && !sta->dummy && | 103 | if (sta->sdata == sdata && !sta->dummy && |
105 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | 104 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) |
106 | break; | 105 | break; |
107 | sta = rcu_dereference_check(sta->hnext, | 106 | sta = rcu_dereference_check(sta->hnext, |
108 | lockdep_is_held(&local->sta_lock) || | ||
109 | lockdep_is_held(&local->sta_mtx)); | 107 | lockdep_is_held(&local->sta_mtx)); |
110 | } | 108 | } |
111 | return sta; | 109 | return sta; |
@@ -119,14 +117,12 @@ struct sta_info *sta_info_get_rx(struct ieee80211_sub_if_data *sdata, | |||
119 | struct sta_info *sta; | 117 | struct sta_info *sta; |
120 | 118 | ||
121 | sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], | 119 | sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], |
122 | lockdep_is_held(&local->sta_lock) || | ||
123 | lockdep_is_held(&local->sta_mtx)); | 120 | lockdep_is_held(&local->sta_mtx)); |
124 | while (sta) { | 121 | while (sta) { |
125 | if (sta->sdata == sdata && | 122 | if (sta->sdata == sdata && |
126 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | 123 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) |
127 | break; | 124 | break; |
128 | sta = rcu_dereference_check(sta->hnext, | 125 | sta = rcu_dereference_check(sta->hnext, |
129 | lockdep_is_held(&local->sta_lock) || | ||
130 | lockdep_is_held(&local->sta_mtx)); | 126 | lockdep_is_held(&local->sta_mtx)); |
131 | } | 127 | } |
132 | return sta; | 128 | return sta; |
@@ -143,7 +139,6 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, | |||
143 | struct sta_info *sta; | 139 | struct sta_info *sta; |
144 | 140 | ||
145 | sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], | 141 | sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], |
146 | lockdep_is_held(&local->sta_lock) || | ||
147 | lockdep_is_held(&local->sta_mtx)); | 142 | lockdep_is_held(&local->sta_mtx)); |
148 | while (sta) { | 143 | while (sta) { |
149 | if ((sta->sdata == sdata || | 144 | if ((sta->sdata == sdata || |
@@ -152,7 +147,6 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, | |||
152 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | 147 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) |
153 | break; | 148 | break; |
154 | sta = rcu_dereference_check(sta->hnext, | 149 | sta = rcu_dereference_check(sta->hnext, |
155 | lockdep_is_held(&local->sta_lock) || | ||
156 | lockdep_is_held(&local->sta_mtx)); | 150 | lockdep_is_held(&local->sta_mtx)); |
157 | } | 151 | } |
158 | return sta; | 152 | return sta; |
@@ -169,7 +163,6 @@ struct sta_info *sta_info_get_bss_rx(struct ieee80211_sub_if_data *sdata, | |||
169 | struct sta_info *sta; | 163 | struct sta_info *sta; |
170 | 164 | ||
171 | sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], | 165 | sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)], |
172 | lockdep_is_held(&local->sta_lock) || | ||
173 | lockdep_is_held(&local->sta_mtx)); | 166 | lockdep_is_held(&local->sta_mtx)); |
174 | while (sta) { | 167 | while (sta) { |
175 | if ((sta->sdata == sdata || | 168 | if ((sta->sdata == sdata || |
@@ -177,7 +170,6 @@ struct sta_info *sta_info_get_bss_rx(struct ieee80211_sub_if_data *sdata, | |||
177 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) | 170 | memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) |
178 | break; | 171 | break; |
179 | sta = rcu_dereference_check(sta->hnext, | 172 | sta = rcu_dereference_check(sta->hnext, |
180 | lockdep_is_held(&local->sta_lock) || | ||
181 | lockdep_is_held(&local->sta_mtx)); | 173 | lockdep_is_held(&local->sta_mtx)); |
182 | } | 174 | } |
183 | return sta; | 175 | return sta; |
@@ -228,10 +220,11 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) | |||
228 | kfree(sta); | 220 | kfree(sta); |
229 | } | 221 | } |
230 | 222 | ||
231 | /* Caller must hold local->sta_lock */ | 223 | /* Caller must hold local->sta_mtx */ |
232 | static void sta_info_hash_add(struct ieee80211_local *local, | 224 | static void sta_info_hash_add(struct ieee80211_local *local, |
233 | struct sta_info *sta) | 225 | struct sta_info *sta) |
234 | { | 226 | { |
227 | lockdep_assert_held(&local->sta_mtx); | ||
235 | sta->hnext = local->sta_hash[STA_HASH(sta->sta.addr)]; | 228 | sta->hnext = local->sta_hash[STA_HASH(sta->sta.addr)]; |
236 | RCU_INIT_POINTER(local->sta_hash[STA_HASH(sta->sta.addr)], sta); | 229 | RCU_INIT_POINTER(local->sta_hash[STA_HASH(sta->sta.addr)], sta); |
237 | } | 230 | } |
@@ -339,89 +332,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
339 | return sta; | 332 | return sta; |
340 | } | 333 | } |
341 | 334 | ||
342 | static int sta_info_finish_insert(struct sta_info *sta, | ||
343 | bool async, bool dummy_reinsert) | ||
344 | { | ||
345 | struct ieee80211_local *local = sta->local; | ||
346 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
347 | struct station_info sinfo; | ||
348 | unsigned long flags; | ||
349 | int err = 0; | ||
350 | |||
351 | lockdep_assert_held(&local->sta_mtx); | ||
352 | |||
353 | if (!sta->dummy || dummy_reinsert) { | ||
354 | /* notify driver */ | ||
355 | err = drv_sta_add(local, sdata, &sta->sta); | ||
356 | if (err) { | ||
357 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||
358 | return err; | ||
359 | printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to " | ||
360 | "driver (%d) - keeping it anyway.\n", | ||
361 | sdata->name, sta->sta.addr, err); | ||
362 | } else | ||
363 | sta->uploaded = true; | ||
364 | |||
365 | sdata = sta->sdata; | ||
366 | } | ||
367 | |||
368 | if (!dummy_reinsert) { | ||
369 | local->num_sta++; | ||
370 | local->sta_generation++; | ||
371 | smp_mb(); | ||
372 | |||
373 | /* make the station visible */ | ||
374 | spin_lock_irqsave(&local->sta_lock, flags); | ||
375 | sta_info_hash_add(local, sta); | ||
376 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
377 | |||
378 | list_add(&sta->list, &local->sta_list); | ||
379 | } else { | ||
380 | sta->dummy = false; | ||
381 | } | ||
382 | |||
383 | if (!sta->dummy) { | ||
384 | ieee80211_sta_debugfs_add(sta); | ||
385 | rate_control_add_sta_debugfs(sta); | ||
386 | |||
387 | memset(&sinfo, 0, sizeof(sinfo)); | ||
388 | sinfo.filled = 0; | ||
389 | sinfo.generation = local->sta_generation; | ||
390 | cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); | ||
391 | } | ||
392 | |||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | static void sta_info_finish_pending(struct ieee80211_local *local) | ||
397 | { | ||
398 | struct sta_info *sta; | ||
399 | unsigned long flags; | ||
400 | |||
401 | spin_lock_irqsave(&local->sta_lock, flags); | ||
402 | while (!list_empty(&local->sta_pending_list)) { | ||
403 | sta = list_first_entry(&local->sta_pending_list, | ||
404 | struct sta_info, list); | ||
405 | list_del(&sta->list); | ||
406 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
407 | |||
408 | sta_info_finish_insert(sta, true, false); | ||
409 | |||
410 | spin_lock_irqsave(&local->sta_lock, flags); | ||
411 | } | ||
412 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
413 | } | ||
414 | |||
415 | static void sta_info_finish_work(struct work_struct *work) | ||
416 | { | ||
417 | struct ieee80211_local *local = | ||
418 | container_of(work, struct ieee80211_local, sta_finish_work); | ||
419 | |||
420 | mutex_lock(&local->sta_mtx); | ||
421 | sta_info_finish_pending(local); | ||
422 | mutex_unlock(&local->sta_mtx); | ||
423 | } | ||
424 | |||
425 | static int sta_info_insert_check(struct sta_info *sta) | 335 | static int sta_info_insert_check(struct sta_info *sta) |
426 | { | 336 | { |
427 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 337 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
@@ -441,50 +351,15 @@ static int sta_info_insert_check(struct sta_info *sta) | |||
441 | return 0; | 351 | return 0; |
442 | } | 352 | } |
443 | 353 | ||
444 | static int sta_info_insert_ibss(struct sta_info *sta) __acquires(RCU) | ||
445 | { | ||
446 | struct ieee80211_local *local = sta->local; | ||
447 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
448 | unsigned long flags; | ||
449 | |||
450 | spin_lock_irqsave(&local->sta_lock, flags); | ||
451 | /* check if STA exists already */ | ||
452 | if (sta_info_get_bss_rx(sdata, sta->sta.addr)) { | ||
453 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
454 | rcu_read_lock(); | ||
455 | return -EEXIST; | ||
456 | } | ||
457 | |||
458 | local->num_sta++; | ||
459 | local->sta_generation++; | ||
460 | smp_mb(); | ||
461 | sta_info_hash_add(local, sta); | ||
462 | |||
463 | list_add_tail(&sta->list, &local->sta_pending_list); | ||
464 | |||
465 | rcu_read_lock(); | ||
466 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
467 | |||
468 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
469 | wiphy_debug(local->hw.wiphy, "Added IBSS STA %pM\n", | ||
470 | sta->sta.addr); | ||
471 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
472 | |||
473 | ieee80211_queue_work(&local->hw, &local->sta_finish_work); | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | /* | 354 | /* |
479 | * should be called with sta_mtx locked | 355 | * should be called with sta_mtx locked |
480 | * this function replaces the mutex lock | 356 | * this function replaces the mutex lock |
481 | * with a RCU lock | 357 | * with a RCU lock |
482 | */ | 358 | */ |
483 | static int sta_info_insert_non_ibss(struct sta_info *sta) __acquires(RCU) | 359 | static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) |
484 | { | 360 | { |
485 | struct ieee80211_local *local = sta->local; | 361 | struct ieee80211_local *local = sta->local; |
486 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 362 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
487 | unsigned long flags; | ||
488 | struct sta_info *exist_sta; | 363 | struct sta_info *exist_sta; |
489 | bool dummy_reinsert = false; | 364 | bool dummy_reinsert = false; |
490 | int err = 0; | 365 | int err = 0; |
@@ -492,19 +367,8 @@ static int sta_info_insert_non_ibss(struct sta_info *sta) __acquires(RCU) | |||
492 | lockdep_assert_held(&local->sta_mtx); | 367 | lockdep_assert_held(&local->sta_mtx); |
493 | 368 | ||
494 | /* | 369 | /* |
495 | * On first glance, this will look racy, because the code | ||
496 | * in this function, which inserts a station with sleeping, | ||
497 | * unlocks the sta_lock between checking existence in the | ||
498 | * hash table and inserting into it. | ||
499 | * | ||
500 | * However, it is not racy against itself because it keeps | ||
501 | * the mutex locked. | ||
502 | */ | ||
503 | |||
504 | spin_lock_irqsave(&local->sta_lock, flags); | ||
505 | /* | ||
506 | * check if STA exists already. | 370 | * check if STA exists already. |
507 | * only accept a scenario of a second call to sta_info_insert_non_ibss | 371 | * only accept a scenario of a second call to sta_info_insert_finish |
508 | * with a dummy station entry that was inserted earlier | 372 | * with a dummy station entry that was inserted earlier |
509 | * in that case - assume that the dummy station flag should | 373 | * in that case - assume that the dummy station flag should |
510 | * be removed. | 374 | * be removed. |
@@ -514,20 +378,47 @@ static int sta_info_insert_non_ibss(struct sta_info *sta) __acquires(RCU) | |||
514 | if (exist_sta == sta && sta->dummy) { | 378 | if (exist_sta == sta && sta->dummy) { |
515 | dummy_reinsert = true; | 379 | dummy_reinsert = true; |
516 | } else { | 380 | } else { |
517 | spin_unlock_irqrestore(&local->sta_lock, flags); | 381 | err = -EEXIST; |
518 | mutex_unlock(&local->sta_mtx); | 382 | goto out_err; |
519 | rcu_read_lock(); | ||
520 | return -EEXIST; | ||
521 | } | 383 | } |
522 | } | 384 | } |
523 | 385 | ||
524 | spin_unlock_irqrestore(&local->sta_lock, flags); | 386 | if (!sta->dummy || dummy_reinsert) { |
387 | /* notify driver */ | ||
388 | err = drv_sta_add(local, sdata, &sta->sta); | ||
389 | if (err) { | ||
390 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||
391 | goto out_err; | ||
392 | printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to " | ||
393 | "driver (%d) - keeping it anyway.\n", | ||
394 | sdata->name, sta->sta.addr, err); | ||
395 | } else | ||
396 | sta->uploaded = true; | ||
397 | } | ||
525 | 398 | ||
526 | err = sta_info_finish_insert(sta, false, dummy_reinsert); | 399 | if (!dummy_reinsert) { |
527 | if (err) { | 400 | local->num_sta++; |
528 | mutex_unlock(&local->sta_mtx); | 401 | local->sta_generation++; |
529 | rcu_read_lock(); | 402 | smp_mb(); |
530 | return err; | 403 | |
404 | /* make the station visible */ | ||
405 | sta_info_hash_add(local, sta); | ||
406 | |||
407 | list_add(&sta->list, &local->sta_list); | ||
408 | } else { | ||
409 | sta->dummy = false; | ||
410 | } | ||
411 | |||
412 | if (!sta->dummy) { | ||
413 | struct station_info sinfo; | ||
414 | |||
415 | ieee80211_sta_debugfs_add(sta); | ||
416 | rate_control_add_sta_debugfs(sta); | ||
417 | |||
418 | memset(&sinfo, 0, sizeof(sinfo)); | ||
419 | sinfo.filled = 0; | ||
420 | sinfo.generation = local->sta_generation; | ||
421 | cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); | ||
531 | } | 422 | } |
532 | 423 | ||
533 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 424 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
@@ -543,47 +434,28 @@ static int sta_info_insert_non_ibss(struct sta_info *sta) __acquires(RCU) | |||
543 | mesh_accept_plinks_update(sdata); | 434 | mesh_accept_plinks_update(sdata); |
544 | 435 | ||
545 | return 0; | 436 | return 0; |
437 | out_err: | ||
438 | mutex_unlock(&local->sta_mtx); | ||
439 | rcu_read_lock(); | ||
440 | return err; | ||
546 | } | 441 | } |
547 | 442 | ||
548 | int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU) | 443 | int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU) |
549 | { | 444 | { |
550 | struct ieee80211_local *local = sta->local; | 445 | struct ieee80211_local *local = sta->local; |
551 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
552 | int err = 0; | 446 | int err = 0; |
553 | 447 | ||
448 | might_sleep(); | ||
449 | |||
554 | err = sta_info_insert_check(sta); | 450 | err = sta_info_insert_check(sta); |
555 | if (err) { | 451 | if (err) { |
556 | rcu_read_lock(); | 452 | rcu_read_lock(); |
557 | goto out_free; | 453 | goto out_free; |
558 | } | 454 | } |
559 | 455 | ||
560 | /* | ||
561 | * In ad-hoc mode, we sometimes need to insert stations | ||
562 | * from tasklet context from the RX path. To avoid races, | ||
563 | * always do so in that case -- see the comment below. | ||
564 | */ | ||
565 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
566 | err = sta_info_insert_ibss(sta); | ||
567 | if (err) | ||
568 | goto out_free; | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | /* | ||
574 | * It might seem that the function called below is in race against | ||
575 | * the function call above that atomically inserts the station... That, | ||
576 | * however, is not true because the above code can only | ||
577 | * be invoked for IBSS interfaces, and the below code will | ||
578 | * not be -- and the two do not race against each other as | ||
579 | * the hash table also keys off the interface. | ||
580 | */ | ||
581 | |||
582 | might_sleep(); | ||
583 | |||
584 | mutex_lock(&local->sta_mtx); | 456 | mutex_lock(&local->sta_mtx); |
585 | 457 | ||
586 | err = sta_info_insert_non_ibss(sta); | 458 | err = sta_info_insert_finish(sta); |
587 | if (err) | 459 | if (err) |
588 | goto out_free; | 460 | goto out_free; |
589 | 461 | ||
@@ -617,7 +489,7 @@ int sta_info_reinsert(struct sta_info *sta) | |||
617 | 489 | ||
618 | might_sleep(); | 490 | might_sleep(); |
619 | 491 | ||
620 | err = sta_info_insert_non_ibss(sta); | 492 | err = sta_info_insert_finish(sta); |
621 | rcu_read_unlock(); | 493 | rcu_read_unlock(); |
622 | return err; | 494 | return err; |
623 | } | 495 | } |
@@ -704,7 +576,7 @@ void sta_info_recalc_tim(struct sta_info *sta) | |||
704 | } | 576 | } |
705 | 577 | ||
706 | done: | 578 | done: |
707 | spin_lock_irqsave(&local->sta_lock, flags); | 579 | spin_lock_irqsave(&local->tim_lock, flags); |
708 | 580 | ||
709 | if (indicate_tim) | 581 | if (indicate_tim) |
710 | __bss_tim_set(bss, sta->sta.aid); | 582 | __bss_tim_set(bss, sta->sta.aid); |
@@ -717,7 +589,7 @@ void sta_info_recalc_tim(struct sta_info *sta) | |||
717 | local->tim_in_locked_section = false; | 589 | local->tim_in_locked_section = false; |
718 | } | 590 | } |
719 | 591 | ||
720 | spin_unlock_irqrestore(&local->sta_lock, flags); | 592 | spin_unlock_irqrestore(&local->tim_lock, flags); |
721 | } | 593 | } |
722 | 594 | ||
723 | static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb) | 595 | static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb) |
@@ -841,7 +713,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
841 | { | 713 | { |
842 | struct ieee80211_local *local; | 714 | struct ieee80211_local *local; |
843 | struct ieee80211_sub_if_data *sdata; | 715 | struct ieee80211_sub_if_data *sdata; |
844 | unsigned long flags; | ||
845 | int ret, i, ac; | 716 | int ret, i, ac; |
846 | struct tid_ampdu_tx *tid_tx; | 717 | struct tid_ampdu_tx *tid_tx; |
847 | 718 | ||
@@ -862,15 +733,12 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) | |||
862 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); | 733 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); |
863 | ieee80211_sta_tear_down_BA_sessions(sta, true); | 734 | ieee80211_sta_tear_down_BA_sessions(sta, true); |
864 | 735 | ||
865 | spin_lock_irqsave(&local->sta_lock, flags); | ||
866 | ret = sta_info_hash_del(local, sta); | 736 | ret = sta_info_hash_del(local, sta); |
867 | /* this might still be the pending list ... which is fine */ | ||
868 | if (!ret) | ||
869 | list_del(&sta->list); | ||
870 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
871 | if (ret) | 737 | if (ret) |
872 | return ret; | 738 | return ret; |
873 | 739 | ||
740 | list_del(&sta->list); | ||
741 | |||
874 | mutex_lock(&local->key_mtx); | 742 | mutex_lock(&local->key_mtx); |
875 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) | 743 | for (i = 0; i < NUM_DEFAULT_KEYS; i++) |
876 | __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i])); | 744 | __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i])); |
@@ -1025,11 +893,9 @@ static void sta_info_cleanup(unsigned long data) | |||
1025 | 893 | ||
1026 | void sta_info_init(struct ieee80211_local *local) | 894 | void sta_info_init(struct ieee80211_local *local) |
1027 | { | 895 | { |
1028 | spin_lock_init(&local->sta_lock); | 896 | spin_lock_init(&local->tim_lock); |
1029 | mutex_init(&local->sta_mtx); | 897 | mutex_init(&local->sta_mtx); |
1030 | INIT_LIST_HEAD(&local->sta_list); | 898 | INIT_LIST_HEAD(&local->sta_list); |
1031 | INIT_LIST_HEAD(&local->sta_pending_list); | ||
1032 | INIT_WORK(&local->sta_finish_work, sta_info_finish_work); | ||
1033 | 899 | ||
1034 | setup_timer(&local->sta_cleanup, sta_info_cleanup, | 900 | setup_timer(&local->sta_cleanup, sta_info_cleanup, |
1035 | (unsigned long)local); | 901 | (unsigned long)local); |
@@ -1058,9 +924,6 @@ int sta_info_flush(struct ieee80211_local *local, | |||
1058 | might_sleep(); | 924 | might_sleep(); |
1059 | 925 | ||
1060 | mutex_lock(&local->sta_mtx); | 926 | mutex_lock(&local->sta_mtx); |
1061 | |||
1062 | sta_info_finish_pending(local); | ||
1063 | |||
1064 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { | 927 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { |
1065 | if (!sdata || sdata == sta->sdata) | 928 | if (!sdata || sdata == sta->sdata) |
1066 | WARN_ON(__sta_info_destroy(sta)); | 929 | WARN_ON(__sta_info_destroy(sta)); |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 6bbd6cccb4a0..ab033fd00b72 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -2333,9 +2333,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2333 | } else { | 2333 | } else { |
2334 | unsigned long flags; | 2334 | unsigned long flags; |
2335 | 2335 | ||
2336 | spin_lock_irqsave(&local->sta_lock, flags); | 2336 | spin_lock_irqsave(&local->tim_lock, flags); |
2337 | ieee80211_beacon_add_tim(ap, skb, beacon); | 2337 | ieee80211_beacon_add_tim(ap, skb, beacon); |
2338 | spin_unlock_irqrestore(&local->sta_lock, flags); | 2338 | spin_unlock_irqrestore(&local->tim_lock, flags); |
2339 | } | 2339 | } |
2340 | 2340 | ||
2341 | if (tim_offset) | 2341 | if (tim_offset) |