diff options
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r-- | net/mac80211/sta_info.c | 66 |
1 files changed, 42 insertions, 24 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index decd30c1e290..a023b432143b 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -91,7 +91,7 @@ static int sta_info_hash_del(struct ieee80211_local *local, | |||
91 | return -ENOENT; | 91 | return -ENOENT; |
92 | } | 92 | } |
93 | 93 | ||
94 | static void cleanup_single_sta(struct sta_info *sta) | 94 | static void __cleanup_single_sta(struct sta_info *sta) |
95 | { | 95 | { |
96 | int ac, i; | 96 | int ac, i; |
97 | struct tid_ampdu_tx *tid_tx; | 97 | struct tid_ampdu_tx *tid_tx; |
@@ -99,7 +99,8 @@ static void cleanup_single_sta(struct sta_info *sta) | |||
99 | struct ieee80211_local *local = sdata->local; | 99 | struct ieee80211_local *local = sdata->local; |
100 | struct ps_data *ps; | 100 | struct ps_data *ps; |
101 | 101 | ||
102 | if (test_sta_flag(sta, WLAN_STA_PS_STA)) { | 102 | if (test_sta_flag(sta, WLAN_STA_PS_STA) || |
103 | test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { | ||
103 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || | 104 | if (sta->sdata->vif.type == NL80211_IFTYPE_AP || |
104 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 105 | sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
105 | ps = &sdata->bss->ps; | 106 | ps = &sdata->bss->ps; |
@@ -109,6 +110,7 @@ static void cleanup_single_sta(struct sta_info *sta) | |||
109 | return; | 110 | return; |
110 | 111 | ||
111 | clear_sta_flag(sta, WLAN_STA_PS_STA); | 112 | clear_sta_flag(sta, WLAN_STA_PS_STA); |
113 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
112 | 114 | ||
113 | atomic_dec(&ps->num_sta_ps); | 115 | atomic_dec(&ps->num_sta_ps); |
114 | sta_info_recalc_tim(sta); | 116 | sta_info_recalc_tim(sta); |
@@ -139,7 +141,14 @@ static void cleanup_single_sta(struct sta_info *sta) | |||
139 | ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending); | 141 | ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending); |
140 | kfree(tid_tx); | 142 | kfree(tid_tx); |
141 | } | 143 | } |
144 | } | ||
142 | 145 | ||
146 | static void cleanup_single_sta(struct sta_info *sta) | ||
147 | { | ||
148 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
149 | struct ieee80211_local *local = sdata->local; | ||
150 | |||
151 | __cleanup_single_sta(sta); | ||
143 | sta_info_free(local, sta); | 152 | sta_info_free(local, sta); |
144 | } | 153 | } |
145 | 154 | ||
@@ -330,6 +339,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
330 | rcu_read_unlock(); | 339 | rcu_read_unlock(); |
331 | 340 | ||
332 | spin_lock_init(&sta->lock); | 341 | spin_lock_init(&sta->lock); |
342 | spin_lock_init(&sta->ps_lock); | ||
333 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); | 343 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); |
334 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); | 344 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); |
335 | mutex_init(&sta->ampdu_mlme.mtx); | 345 | mutex_init(&sta->ampdu_mlme.mtx); |
@@ -487,21 +497,26 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) | |||
487 | goto out_err; | 497 | goto out_err; |
488 | } | 498 | } |
489 | 499 | ||
490 | /* notify driver */ | ||
491 | err = sta_info_insert_drv_state(local, sdata, sta); | ||
492 | if (err) | ||
493 | goto out_err; | ||
494 | |||
495 | local->num_sta++; | 500 | local->num_sta++; |
496 | local->sta_generation++; | 501 | local->sta_generation++; |
497 | smp_mb(); | 502 | smp_mb(); |
498 | 503 | ||
504 | /* simplify things and don't accept BA sessions yet */ | ||
505 | set_sta_flag(sta, WLAN_STA_BLOCK_BA); | ||
506 | |||
499 | /* make the station visible */ | 507 | /* make the station visible */ |
500 | sta_info_hash_add(local, sta); | 508 | sta_info_hash_add(local, sta); |
501 | 509 | ||
502 | list_add_rcu(&sta->list, &local->sta_list); | 510 | list_add_rcu(&sta->list, &local->sta_list); |
503 | 511 | ||
512 | /* notify driver */ | ||
513 | err = sta_info_insert_drv_state(local, sdata, sta); | ||
514 | if (err) | ||
515 | goto out_remove; | ||
516 | |||
504 | set_sta_flag(sta, WLAN_STA_INSERTED); | 517 | set_sta_flag(sta, WLAN_STA_INSERTED); |
518 | /* accept BA sessions now */ | ||
519 | clear_sta_flag(sta, WLAN_STA_BLOCK_BA); | ||
505 | 520 | ||
506 | ieee80211_recalc_min_chandef(sdata); | 521 | ieee80211_recalc_min_chandef(sdata); |
507 | ieee80211_sta_debugfs_add(sta); | 522 | ieee80211_sta_debugfs_add(sta); |
@@ -522,6 +537,12 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) | |||
522 | mesh_accept_plinks_update(sdata); | 537 | mesh_accept_plinks_update(sdata); |
523 | 538 | ||
524 | return 0; | 539 | return 0; |
540 | out_remove: | ||
541 | sta_info_hash_del(local, sta); | ||
542 | list_del_rcu(&sta->list); | ||
543 | local->num_sta--; | ||
544 | synchronize_net(); | ||
545 | __cleanup_single_sta(sta); | ||
525 | out_err: | 546 | out_err: |
526 | mutex_unlock(&local->sta_mtx); | 547 | mutex_unlock(&local->sta_mtx); |
527 | rcu_read_lock(); | 548 | rcu_read_lock(); |
@@ -1071,10 +1092,14 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, | |||
1071 | } | 1092 | } |
1072 | EXPORT_SYMBOL(ieee80211_find_sta); | 1093 | EXPORT_SYMBOL(ieee80211_find_sta); |
1073 | 1094 | ||
1074 | static void clear_sta_ps_flags(void *_sta) | 1095 | /* powersave support code */ |
1096 | void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | ||
1075 | { | 1097 | { |
1076 | struct sta_info *sta = _sta; | ||
1077 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 1098 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
1099 | struct ieee80211_local *local = sdata->local; | ||
1100 | struct sk_buff_head pending; | ||
1101 | int filtered = 0, buffered = 0, ac; | ||
1102 | unsigned long flags; | ||
1078 | struct ps_data *ps; | 1103 | struct ps_data *ps; |
1079 | 1104 | ||
1080 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 1105 | if (sdata->vif.type == NL80211_IFTYPE_AP || |
@@ -1085,20 +1110,6 @@ static void clear_sta_ps_flags(void *_sta) | |||
1085 | else | 1110 | else |
1086 | return; | 1111 | return; |
1087 | 1112 | ||
1088 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
1089 | if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA)) | ||
1090 | atomic_dec(&ps->num_sta_ps); | ||
1091 | } | ||
1092 | |||
1093 | /* powersave support code */ | ||
1094 | void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | ||
1095 | { | ||
1096 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
1097 | struct ieee80211_local *local = sdata->local; | ||
1098 | struct sk_buff_head pending; | ||
1099 | int filtered = 0, buffered = 0, ac; | ||
1100 | unsigned long flags; | ||
1101 | |||
1102 | clear_sta_flag(sta, WLAN_STA_SP); | 1113 | clear_sta_flag(sta, WLAN_STA_SP); |
1103 | 1114 | ||
1104 | BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1); | 1115 | BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1); |
@@ -1109,6 +1120,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
1109 | 1120 | ||
1110 | skb_queue_head_init(&pending); | 1121 | skb_queue_head_init(&pending); |
1111 | 1122 | ||
1123 | /* sync with ieee80211_tx_h_unicast_ps_buf */ | ||
1124 | spin_lock(&sta->ps_lock); | ||
1112 | /* Send all buffered frames to the station */ | 1125 | /* Send all buffered frames to the station */ |
1113 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 1126 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { |
1114 | int count = skb_queue_len(&pending), tmp; | 1127 | int count = skb_queue_len(&pending), tmp; |
@@ -1127,7 +1140,12 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
1127 | buffered += tmp - count; | 1140 | buffered += tmp - count; |
1128 | } | 1141 | } |
1129 | 1142 | ||
1130 | ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta); | 1143 | ieee80211_add_pending_skbs(local, &pending); |
1144 | clear_sta_flag(sta, WLAN_STA_PS_DRIVER); | ||
1145 | clear_sta_flag(sta, WLAN_STA_PS_STA); | ||
1146 | spin_unlock(&sta->ps_lock); | ||
1147 | |||
1148 | atomic_dec(&ps->num_sta_ps); | ||
1131 | 1149 | ||
1132 | /* This station just woke up and isn't aware of our SMPS state */ | 1150 | /* This station just woke up and isn't aware of our SMPS state */ |
1133 | if (!ieee80211_smps_is_restrictive(sta->known_smps_mode, | 1151 | if (!ieee80211_smps_is_restrictive(sta->known_smps_mode, |