diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/chan.c | 6 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 10 | ||||
-rw-r--r-- | net/mac80211/mesh_ps.c | 1 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 24 | ||||
-rw-r--r-- | net/mac80211/rx.c | 7 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 67 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 7 | ||||
-rw-r--r-- | net/mac80211/tx.c | 15 | ||||
-rw-r--r-- | net/mac80211/util.c | 48 | ||||
-rw-r--r-- | net/mac80211/wme.c | 5 |
10 files changed, 128 insertions, 62 deletions
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index f43613a97dd6..0c1ecfdf9a12 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -100,6 +100,12 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, | |||
100 | } | 100 | } |
101 | max_bw = max(max_bw, width); | 101 | max_bw = max(max_bw, width); |
102 | } | 102 | } |
103 | |||
104 | /* use the configured bandwidth in case of monitor interface */ | ||
105 | sdata = rcu_dereference(local->monitor_sdata); | ||
106 | if (sdata && rcu_access_pointer(sdata->vif.chanctx_conf) == conf) | ||
107 | max_bw = max(max_bw, conf->def.width); | ||
108 | |||
103 | rcu_read_unlock(); | 109 | rcu_read_unlock(); |
104 | 110 | ||
105 | return max_bw; | 111 | return max_bw; |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 3701930c6649..5e44e3179e02 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -1692,14 +1692,8 @@ void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, | |||
1692 | void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue); | 1692 | void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue); |
1693 | void ieee80211_add_pending_skb(struct ieee80211_local *local, | 1693 | void ieee80211_add_pending_skb(struct ieee80211_local *local, |
1694 | struct sk_buff *skb); | 1694 | struct sk_buff *skb); |
1695 | void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, | 1695 | void ieee80211_add_pending_skbs(struct ieee80211_local *local, |
1696 | struct sk_buff_head *skbs, | 1696 | struct sk_buff_head *skbs); |
1697 | void (*fn)(void *data), void *data); | ||
1698 | static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local, | ||
1699 | struct sk_buff_head *skbs) | ||
1700 | { | ||
1701 | ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL); | ||
1702 | } | ||
1703 | void ieee80211_flush_queues(struct ieee80211_local *local, | 1697 | void ieee80211_flush_queues(struct ieee80211_local *local, |
1704 | struct ieee80211_sub_if_data *sdata); | 1698 | struct ieee80211_sub_if_data *sdata); |
1705 | 1699 | ||
diff --git a/net/mac80211/mesh_ps.c b/net/mac80211/mesh_ps.c index 2802f9d9279d..ad8b377b4b9f 100644 --- a/net/mac80211/mesh_ps.c +++ b/net/mac80211/mesh_ps.c | |||
@@ -36,6 +36,7 @@ static struct sk_buff *mps_qos_null_get(struct sta_info *sta) | |||
36 | sdata->vif.addr); | 36 | sdata->vif.addr); |
37 | nullfunc->frame_control = fc; | 37 | nullfunc->frame_control = fc; |
38 | nullfunc->duration_id = 0; | 38 | nullfunc->duration_id = 0; |
39 | nullfunc->seq_ctrl = 0; | ||
39 | /* no address resolution for this frame -> set addr 1 immediately */ | 40 | /* no address resolution for this frame -> set addr 1 immediately */ |
40 | memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN); | 41 | memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN); |
41 | memset(skb_put(skb, 2), 0, 2); /* append QoS control field */ | 42 | memset(skb_put(skb, 2), 0, 2); /* append QoS control field */ |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index fc1d82465b3c..245dce969b31 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -222,6 +222,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
222 | switch (vht_oper->chan_width) { | 222 | switch (vht_oper->chan_width) { |
223 | case IEEE80211_VHT_CHANWIDTH_USE_HT: | 223 | case IEEE80211_VHT_CHANWIDTH_USE_HT: |
224 | vht_chandef.width = chandef->width; | 224 | vht_chandef.width = chandef->width; |
225 | vht_chandef.center_freq1 = chandef->center_freq1; | ||
225 | break; | 226 | break; |
226 | case IEEE80211_VHT_CHANWIDTH_80MHZ: | 227 | case IEEE80211_VHT_CHANWIDTH_80MHZ: |
227 | vht_chandef.width = NL80211_CHAN_WIDTH_80; | 228 | vht_chandef.width = NL80211_CHAN_WIDTH_80; |
@@ -271,6 +272,28 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata, | |||
271 | ret = 0; | 272 | ret = 0; |
272 | 273 | ||
273 | out: | 274 | out: |
275 | /* | ||
276 | * When tracking the current AP, don't do any further checks if the | ||
277 | * new chandef is identical to the one we're currently using for the | ||
278 | * connection. This keeps us from playing ping-pong with regulatory, | ||
279 | * without it the following can happen (for example): | ||
280 | * - connect to an AP with 80 MHz, world regdom allows 80 MHz | ||
281 | * - AP advertises regdom US | ||
282 | * - CRDA loads regdom US with 80 MHz prohibited (old database) | ||
283 | * - the code below detects an unsupported channel, downgrades, and | ||
284 | * we disconnect from the AP in the caller | ||
285 | * - disconnect causes CRDA to reload world regdomain and the game | ||
286 | * starts anew. | ||
287 | * (see https://bugzilla.kernel.org/show_bug.cgi?id=70881) | ||
288 | * | ||
289 | * It seems possible that there are still scenarios with CSA or real | ||
290 | * bandwidth changes where a this could happen, but those cases are | ||
291 | * less common and wouldn't completely prevent using the AP. | ||
292 | */ | ||
293 | if (tracking && | ||
294 | cfg80211_chandef_identical(chandef, &sdata->vif.bss_conf.chandef)) | ||
295 | return ret; | ||
296 | |||
274 | /* don't print the message below for VHT mismatch if VHT is disabled */ | 297 | /* don't print the message below for VHT mismatch if VHT is disabled */ |
275 | if (ret & IEEE80211_STA_DISABLE_VHT) | 298 | if (ret & IEEE80211_STA_DISABLE_VHT) |
276 | vht_chandef = *chandef; | 299 | vht_chandef = *chandef; |
@@ -3753,6 +3776,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, | |||
3753 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | 3776 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); |
3754 | if (WARN_ON(!chanctx_conf)) { | 3777 | if (WARN_ON(!chanctx_conf)) { |
3755 | rcu_read_unlock(); | 3778 | rcu_read_unlock(); |
3779 | sta_info_free(local, new_sta); | ||
3756 | return -EINVAL; | 3780 | return -EINVAL; |
3757 | } | 3781 | } |
3758 | rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def); | 3782 | rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def); |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c24ca0d0f469..3e57f96c9666 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1128,6 +1128,13 @@ static void sta_ps_end(struct sta_info *sta) | |||
1128 | sta->sta.addr, sta->sta.aid); | 1128 | sta->sta.addr, sta->sta.aid); |
1129 | 1129 | ||
1130 | if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { | 1130 | if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { |
1131 | /* | ||
1132 | * Clear the flag only if the other one is still set | ||
1133 | * so that the TX path won't start TX'ing new frames | ||
1134 | * directly ... In the case that the driver flag isn't | ||
1135 | * set ieee80211_sta_ps_deliver_wakeup() will clear it. | ||
1136 | */ | ||
1137 | clear_sta_flag(sta, WLAN_STA_PS_STA); | ||
1131 | ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n", | 1138 | ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n", |
1132 | sta->sta.addr, sta->sta.aid); | 1139 | sta->sta.addr, sta->sta.aid); |
1133 | return; | 1140 | return; |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index decd30c1e290..137a192e64bc 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, |
@@ -1188,6 +1206,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, | |||
1188 | memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN); | 1206 | memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN); |
1189 | memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); | 1207 | memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); |
1190 | memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN); | 1208 | memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN); |
1209 | nullfunc->seq_ctrl = 0; | ||
1191 | 1210 | ||
1192 | skb->priority = tid; | 1211 | skb->priority = tid; |
1193 | skb_set_queue_mapping(skb, ieee802_1d_to_ac[tid]); | 1212 | skb_set_queue_mapping(skb, ieee802_1d_to_ac[tid]); |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index d77ff7090630..d3a6d8208f2f 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -267,6 +267,7 @@ struct ieee80211_tx_latency_stat { | |||
267 | * @drv_unblock_wk: used for driver PS unblocking | 267 | * @drv_unblock_wk: used for driver PS unblocking |
268 | * @listen_interval: listen interval of this station, when we're acting as AP | 268 | * @listen_interval: listen interval of this station, when we're acting as AP |
269 | * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly | 269 | * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly |
270 | * @ps_lock: used for powersave (when mac80211 is the AP) related locking | ||
270 | * @ps_tx_buf: buffers (per AC) of frames to transmit to this station | 271 | * @ps_tx_buf: buffers (per AC) of frames to transmit to this station |
271 | * when it leaves power saving state or polls | 272 | * when it leaves power saving state or polls |
272 | * @tx_filtered: buffers (per AC) of frames we already tried to | 273 | * @tx_filtered: buffers (per AC) of frames we already tried to |
@@ -356,10 +357,8 @@ struct sta_info { | |||
356 | /* use the accessors defined below */ | 357 | /* use the accessors defined below */ |
357 | unsigned long _flags; | 358 | unsigned long _flags; |
358 | 359 | ||
359 | /* | 360 | /* STA powersave lock and frame queues */ |
360 | * STA powersave frame queues, no more than the internal | 361 | spinlock_t ps_lock; |
361 | * locking required. | ||
362 | */ | ||
363 | struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS]; | 362 | struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS]; |
364 | struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS]; | 363 | struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS]; |
365 | unsigned long driver_buffered_tids; | 364 | unsigned long driver_buffered_tids; |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 97a02d3f7d87..4080c615636f 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -478,6 +478,20 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) | |||
478 | sta->sta.addr, sta->sta.aid, ac); | 478 | sta->sta.addr, sta->sta.aid, ac); |
479 | if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) | 479 | if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) |
480 | purge_old_ps_buffers(tx->local); | 480 | purge_old_ps_buffers(tx->local); |
481 | |||
482 | /* sync with ieee80211_sta_ps_deliver_wakeup */ | ||
483 | spin_lock(&sta->ps_lock); | ||
484 | /* | ||
485 | * STA woke up the meantime and all the frames on ps_tx_buf have | ||
486 | * been queued to pending queue. No reordering can happen, go | ||
487 | * ahead and Tx the packet. | ||
488 | */ | ||
489 | if (!test_sta_flag(sta, WLAN_STA_PS_STA) && | ||
490 | !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { | ||
491 | spin_unlock(&sta->ps_lock); | ||
492 | return TX_CONTINUE; | ||
493 | } | ||
494 | |||
481 | if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) { | 495 | if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) { |
482 | struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]); | 496 | struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]); |
483 | ps_dbg(tx->sdata, | 497 | ps_dbg(tx->sdata, |
@@ -492,6 +506,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) | |||
492 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; | 506 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
493 | info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS; | 507 | info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS; |
494 | skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb); | 508 | skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb); |
509 | spin_unlock(&sta->ps_lock); | ||
495 | 510 | ||
496 | if (!timer_pending(&local->sta_cleanup)) | 511 | if (!timer_pending(&local->sta_cleanup)) |
497 | mod_timer(&local->sta_cleanup, | 512 | mod_timer(&local->sta_cleanup, |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 676dc0967f37..b8700d417a9c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -435,9 +435,8 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, | |||
435 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 435 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
436 | } | 436 | } |
437 | 437 | ||
438 | void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, | 438 | void ieee80211_add_pending_skbs(struct ieee80211_local *local, |
439 | struct sk_buff_head *skbs, | 439 | struct sk_buff_head *skbs) |
440 | void (*fn)(void *data), void *data) | ||
441 | { | 440 | { |
442 | struct ieee80211_hw *hw = &local->hw; | 441 | struct ieee80211_hw *hw = &local->hw; |
443 | struct sk_buff *skb; | 442 | struct sk_buff *skb; |
@@ -461,9 +460,6 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, | |||
461 | __skb_queue_tail(&local->pending[queue], skb); | 460 | __skb_queue_tail(&local->pending[queue], skb); |
462 | } | 461 | } |
463 | 462 | ||
464 | if (fn) | ||
465 | fn(data); | ||
466 | |||
467 | for (i = 0; i < hw->queues; i++) | 463 | for (i = 0; i < hw->queues; i++) |
468 | __ieee80211_wake_queue(hw, i, | 464 | __ieee80211_wake_queue(hw, i, |
469 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 465 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); |
@@ -1741,6 +1737,26 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1741 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | 1737 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); |
1742 | 1738 | ||
1743 | /* | 1739 | /* |
1740 | * Reconfigure sched scan if it was interrupted by FW restart or | ||
1741 | * suspend. | ||
1742 | */ | ||
1743 | mutex_lock(&local->mtx); | ||
1744 | sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata, | ||
1745 | lockdep_is_held(&local->mtx)); | ||
1746 | if (sched_scan_sdata && local->sched_scan_req) | ||
1747 | /* | ||
1748 | * Sched scan stopped, but we don't want to report it. Instead, | ||
1749 | * we're trying to reschedule. | ||
1750 | */ | ||
1751 | if (__ieee80211_request_sched_scan_start(sched_scan_sdata, | ||
1752 | local->sched_scan_req)) | ||
1753 | sched_scan_stopped = true; | ||
1754 | mutex_unlock(&local->mtx); | ||
1755 | |||
1756 | if (sched_scan_stopped) | ||
1757 | cfg80211_sched_scan_stopped(local->hw.wiphy); | ||
1758 | |||
1759 | /* | ||
1744 | * If this is for hw restart things are still running. | 1760 | * If this is for hw restart things are still running. |
1745 | * We may want to change that later, however. | 1761 | * We may want to change that later, however. |
1746 | */ | 1762 | */ |
@@ -1768,26 +1784,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1768 | WARN_ON(1); | 1784 | WARN_ON(1); |
1769 | #endif | 1785 | #endif |
1770 | 1786 | ||
1771 | /* | ||
1772 | * Reconfigure sched scan if it was interrupted by FW restart or | ||
1773 | * suspend. | ||
1774 | */ | ||
1775 | mutex_lock(&local->mtx); | ||
1776 | sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata, | ||
1777 | lockdep_is_held(&local->mtx)); | ||
1778 | if (sched_scan_sdata && local->sched_scan_req) | ||
1779 | /* | ||
1780 | * Sched scan stopped, but we don't want to report it. Instead, | ||
1781 | * we're trying to reschedule. | ||
1782 | */ | ||
1783 | if (__ieee80211_request_sched_scan_start(sched_scan_sdata, | ||
1784 | local->sched_scan_req)) | ||
1785 | sched_scan_stopped = true; | ||
1786 | mutex_unlock(&local->mtx); | ||
1787 | |||
1788 | if (sched_scan_stopped) | ||
1789 | cfg80211_sched_scan_stopped(local->hw.wiphy); | ||
1790 | |||
1791 | return 0; | 1787 | return 0; |
1792 | } | 1788 | } |
1793 | 1789 | ||
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 21211c60ca98..d51422c778de 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -154,6 +154,11 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, | |||
154 | return IEEE80211_AC_BE; | 154 | return IEEE80211_AC_BE; |
155 | } | 155 | } |
156 | 156 | ||
157 | if (skb->protocol == sdata->control_port_protocol) { | ||
158 | skb->priority = 7; | ||
159 | return ieee80211_downgrade_queue(sdata, skb); | ||
160 | } | ||
161 | |||
157 | /* use the data classifier to determine what 802.1d tag the | 162 | /* use the data classifier to determine what 802.1d tag the |
158 | * data frame has */ | 163 | * data frame has */ |
159 | rcu_read_lock(); | 164 | rcu_read_lock(); |