diff options
-rw-r--r-- | net/mac80211/agg-tx.c | 177 | ||||
-rw-r--r-- | net/mac80211/debugfs_sta.c | 5 | ||||
-rw-r--r-- | net/mac80211/ht.c | 2 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 1 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 1 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 6 | ||||
-rw-r--r-- | net/mac80211/tx.c | 5 |
7 files changed, 139 insertions, 58 deletions
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 7f2042d37904..ee8bfe18b488 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -146,6 +146,13 @@ static int ___ieee80211_stop_tx_ba_session( | |||
146 | if (WARN_ON(!tid_tx)) | 146 | if (WARN_ON(!tid_tx)) |
147 | return -ENOENT; | 147 | return -ENOENT; |
148 | 148 | ||
149 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { | ||
150 | /* not even started yet! */ | ||
151 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); | ||
152 | call_rcu(&tid_tx->rcu_head, kfree_tid_tx); | ||
153 | return 0; | ||
154 | } | ||
155 | |||
149 | #ifdef CONFIG_MAC80211_HT_DEBUG | 156 | #ifdef CONFIG_MAC80211_HT_DEBUG |
150 | printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n", | 157 | printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n", |
151 | sta->sta.addr, tid); | 158 | sta->sta.addr, tid); |
@@ -255,6 +262,94 @@ ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid) | |||
255 | __release(agg_queue); | 262 | __release(agg_queue); |
256 | } | 263 | } |
257 | 264 | ||
265 | static void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) | ||
266 | { | ||
267 | struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid]; | ||
268 | struct ieee80211_local *local = sta->local; | ||
269 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
270 | u16 start_seq_num; | ||
271 | int ret; | ||
272 | |||
273 | /* | ||
274 | * While we're asking the driver about the aggregation, | ||
275 | * stop the AC queue so that we don't have to worry | ||
276 | * about frames that came in while we were doing that, | ||
277 | * which would require us to put them to the AC pending | ||
278 | * afterwards which just makes the code more complex. | ||
279 | */ | ||
280 | ieee80211_stop_queue_agg(local, tid); | ||
281 | |||
282 | clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state); | ||
283 | |||
284 | /* | ||
285 | * This might be off by one due to a race that we can't | ||
286 | * really prevent here without synchronize_net() which | ||
287 | * can't be called now. | ||
288 | */ | ||
289 | start_seq_num = sta->tid_seq[tid] >> 4; | ||
290 | |||
291 | ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, | ||
292 | &sta->sta, tid, &start_seq_num); | ||
293 | if (ret) { | ||
294 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
295 | printk(KERN_DEBUG "BA request denied - HW unavailable for" | ||
296 | " tid %d\n", tid); | ||
297 | #endif | ||
298 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); | ||
299 | ieee80211_wake_queue_agg(local, tid); | ||
300 | call_rcu(&tid_tx->rcu_head, kfree_tid_tx); | ||
301 | return; | ||
302 | } | ||
303 | |||
304 | /* we can take packets again now */ | ||
305 | ieee80211_wake_queue_agg(local, tid); | ||
306 | |||
307 | /* activate the timer for the recipient's addBA response */ | ||
308 | mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL); | ||
309 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
310 | printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); | ||
311 | #endif | ||
312 | |||
313 | sta->ampdu_mlme.addba_req_num[tid]++; | ||
314 | |||
315 | /* send AddBA request */ | ||
316 | ieee80211_send_addba_request(sdata, sta->sta.addr, tid, | ||
317 | tid_tx->dialog_token, start_seq_num, | ||
318 | 0x40, 5000); | ||
319 | } | ||
320 | |||
321 | void ieee80211_tx_ba_session_work(struct work_struct *work) | ||
322 | { | ||
323 | struct sta_info *sta = | ||
324 | container_of(work, struct sta_info, ampdu_mlme.work); | ||
325 | struct tid_ampdu_tx *tid_tx; | ||
326 | int tid; | ||
327 | |||
328 | /* | ||
329 | * When this flag is set, new sessions should be | ||
330 | * blocked, and existing sessions will be torn | ||
331 | * down by the code that set the flag, so this | ||
332 | * need not run. | ||
333 | */ | ||
334 | if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) | ||
335 | return; | ||
336 | |||
337 | spin_lock_bh(&sta->lock); | ||
338 | for (tid = 0; tid < STA_TID_NUM; tid++) { | ||
339 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | ||
340 | if (!tid_tx) | ||
341 | continue; | ||
342 | |||
343 | if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) | ||
344 | ieee80211_tx_ba_session_handle_start(sta, tid); | ||
345 | else if (test_and_clear_bit(HT_AGG_STATE_WANT_STOP, | ||
346 | &tid_tx->state)) | ||
347 | ___ieee80211_stop_tx_ba_session(sta, tid, | ||
348 | WLAN_BACK_INITIATOR); | ||
349 | } | ||
350 | spin_unlock_bh(&sta->lock); | ||
351 | } | ||
352 | |||
258 | int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | 353 | int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) |
259 | { | 354 | { |
260 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | 355 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); |
@@ -262,7 +357,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
262 | struct ieee80211_local *local = sdata->local; | 357 | struct ieee80211_local *local = sdata->local; |
263 | struct tid_ampdu_tx *tid_tx; | 358 | struct tid_ampdu_tx *tid_tx; |
264 | int ret = 0; | 359 | int ret = 0; |
265 | u16 start_seq_num; | ||
266 | 360 | ||
267 | trace_api_start_tx_ba_session(pubsta, tid); | 361 | trace_api_start_tx_ba_session(pubsta, tid); |
268 | 362 | ||
@@ -316,15 +410,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
316 | goto err_unlock_sta; | 410 | goto err_unlock_sta; |
317 | } | 411 | } |
318 | 412 | ||
319 | /* | ||
320 | * While we're asking the driver about the aggregation, | ||
321 | * stop the AC queue so that we don't have to worry | ||
322 | * about frames that came in while we were doing that, | ||
323 | * which would require us to put them to the AC pending | ||
324 | * afterwards which just makes the code more complex. | ||
325 | */ | ||
326 | ieee80211_stop_queue_agg(local, tid); | ||
327 | |||
328 | /* prepare A-MPDU MLME for Tx aggregation */ | 413 | /* prepare A-MPDU MLME for Tx aggregation */ |
329 | tid_tx = kzalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); | 414 | tid_tx = kzalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); |
330 | if (!tid_tx) { | 415 | if (!tid_tx) { |
@@ -334,59 +419,27 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
334 | tid); | 419 | tid); |
335 | #endif | 420 | #endif |
336 | ret = -ENOMEM; | 421 | ret = -ENOMEM; |
337 | goto err_wake_queue; | 422 | goto err_unlock_sta; |
338 | } | 423 | } |
339 | 424 | ||
340 | skb_queue_head_init(&tid_tx->pending); | 425 | skb_queue_head_init(&tid_tx->pending); |
426 | __set_bit(HT_AGG_STATE_WANT_START, &tid_tx->state); | ||
341 | 427 | ||
342 | /* Tx timer */ | 428 | /* Tx timer */ |
343 | tid_tx->addba_resp_timer.function = sta_addba_resp_timer_expired; | 429 | tid_tx->addba_resp_timer.function = sta_addba_resp_timer_expired; |
344 | tid_tx->addba_resp_timer.data = (unsigned long)&sta->timer_to_tid[tid]; | 430 | tid_tx->addba_resp_timer.data = (unsigned long)&sta->timer_to_tid[tid]; |
345 | init_timer(&tid_tx->addba_resp_timer); | 431 | init_timer(&tid_tx->addba_resp_timer); |
346 | 432 | ||
347 | start_seq_num = sta->tid_seq[tid] >> 4; | 433 | /* assign a dialog token */ |
348 | |||
349 | ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, | ||
350 | pubsta, tid, &start_seq_num); | ||
351 | if (ret) { | ||
352 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
353 | printk(KERN_DEBUG "BA request denied - HW unavailable for" | ||
354 | " tid %d\n", tid); | ||
355 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
356 | goto err_free; | ||
357 | } | ||
358 | |||
359 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); | ||
360 | |||
361 | /* Driver vetoed or OKed, but we can take packets again now */ | ||
362 | ieee80211_wake_queue_agg(local, tid); | ||
363 | |||
364 | /* activate the timer for the recipient's addBA response */ | ||
365 | tid_tx->addba_resp_timer.expires = jiffies + ADDBA_RESP_INTERVAL; | ||
366 | add_timer(&tid_tx->addba_resp_timer); | ||
367 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
368 | printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); | ||
369 | #endif | ||
370 | |||
371 | /* prepare tid data */ | ||
372 | sta->ampdu_mlme.dialog_token_allocator++; | 434 | sta->ampdu_mlme.dialog_token_allocator++; |
373 | tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator; | 435 | tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator; |
374 | tid_tx->ssn = start_seq_num; | ||
375 | |||
376 | sta->ampdu_mlme.addba_req_num[tid]++; | ||
377 | 436 | ||
378 | spin_unlock_bh(&sta->lock); | 437 | /* finally, assign it to the array */ |
438 | rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); | ||
379 | 439 | ||
380 | /* send AddBA request */ | 440 | ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work); |
381 | ieee80211_send_addba_request(sdata, pubsta->addr, tid, | ||
382 | tid_tx->dialog_token, tid_tx->ssn, | ||
383 | 0x40, 5000); | ||
384 | return 0; | ||
385 | 441 | ||
386 | err_free: | 442 | /* this flow continues off the work */ |
387 | kfree(tid_tx); | ||
388 | err_wake_queue: | ||
389 | ieee80211_wake_queue_agg(local, tid); | ||
390 | err_unlock_sta: | 443 | err_unlock_sta: |
391 | spin_unlock_bh(&sta->lock); | 444 | spin_unlock_bh(&sta->lock); |
392 | return ret; | 445 | return ret; |
@@ -534,8 +587,7 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
534 | spin_lock_bh(&sta->lock); | 587 | spin_lock_bh(&sta->lock); |
535 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | 588 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; |
536 | 589 | ||
537 | /* check if the TID is in aggregation */ | 590 | if (!tid_tx) { |
538 | if (!tid_tx || !test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) { | ||
539 | ret = -ENOENT; | 591 | ret = -ENOENT; |
540 | goto unlock; | 592 | goto unlock; |
541 | } | 593 | } |
@@ -552,6 +604,8 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
552 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | 604 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); |
553 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 605 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
554 | struct ieee80211_local *local = sdata->local; | 606 | struct ieee80211_local *local = sdata->local; |
607 | struct tid_ampdu_tx *tid_tx; | ||
608 | int ret = 0; | ||
555 | 609 | ||
556 | trace_api_stop_tx_ba_session(pubsta, tid); | 610 | trace_api_stop_tx_ba_session(pubsta, tid); |
557 | 611 | ||
@@ -561,7 +615,26 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
561 | if (tid >= STA_TID_NUM) | 615 | if (tid >= STA_TID_NUM) |
562 | return -EINVAL; | 616 | return -EINVAL; |
563 | 617 | ||
564 | return __ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR); | 618 | spin_lock_bh(&sta->lock); |
619 | tid_tx = sta->ampdu_mlme.tid_tx[tid]; | ||
620 | |||
621 | if (!tid_tx) { | ||
622 | ret = -ENOENT; | ||
623 | goto unlock; | ||
624 | } | ||
625 | |||
626 | if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { | ||
627 | /* already in progress stopping it */ | ||
628 | ret = 0; | ||
629 | goto unlock; | ||
630 | } | ||
631 | |||
632 | set_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state); | ||
633 | ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work); | ||
634 | |||
635 | unlock: | ||
636 | spin_unlock_bh(&sta->lock); | ||
637 | return ret; | ||
565 | } | 638 | } |
566 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); | 639 | EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); |
567 | 640 | ||
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 8a74ffb36ad4..76839d4dfaac 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -121,7 +121,7 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, | |||
121 | p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n", | 121 | p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n", |
122 | sta->ampdu_mlme.dialog_token_allocator + 1); | 122 | sta->ampdu_mlme.dialog_token_allocator + 1); |
123 | p += scnprintf(p, sizeof(buf) + buf - p, | 123 | p += scnprintf(p, sizeof(buf) + buf - p, |
124 | "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tSSN\tpending\n"); | 124 | "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tpending\n"); |
125 | for (i = 0; i < STA_TID_NUM; i++) { | 125 | for (i = 0; i < STA_TID_NUM; i++) { |
126 | p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i); | 126 | p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i); |
127 | p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", | 127 | p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", |
@@ -138,9 +138,6 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, | |||
138 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", | 138 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", |
139 | sta->ampdu_mlme.tid_tx[i] ? | 139 | sta->ampdu_mlme.tid_tx[i] ? |
140 | sta->ampdu_mlme.tid_tx[i]->dialog_token : 0); | 140 | sta->ampdu_mlme.tid_tx[i]->dialog_token : 0); |
141 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x", | ||
142 | sta->ampdu_mlme.tid_tx[i] ? | ||
143 | sta->ampdu_mlme.tid_tx[i]->ssn : 0); | ||
144 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%03d", | 141 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%03d", |
145 | sta->ampdu_mlme.tid_tx[i] ? | 142 | sta->ampdu_mlme.tid_tx[i] ? |
146 | skb_queue_len(&sta->ampdu_mlme.tid_tx[i]->pending) : 0); | 143 | skb_queue_len(&sta->ampdu_mlme.tid_tx[i]->pending) : 0); |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 1af173ed2d5e..4dfba7808a24 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -105,6 +105,8 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta) | |||
105 | { | 105 | { |
106 | int i; | 106 | int i; |
107 | 107 | ||
108 | cancel_work_sync(&sta->ampdu_mlme.work); | ||
109 | |||
108 | for (i = 0; i < STA_TID_NUM; i++) { | 110 | for (i = 0; i < STA_TID_NUM; i++) { |
109 | __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR); | 111 | __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR); |
110 | __ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT, | 112 | __ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT, |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8a91b5d83870..aec84c36c4c1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -1115,6 +1115,7 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
1115 | enum ieee80211_back_parties initiator); | 1115 | enum ieee80211_back_parties initiator); |
1116 | void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid); | 1116 | void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid); |
1117 | void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid); | 1117 | void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid); |
1118 | void ieee80211_tx_ba_session_work(struct work_struct *work); | ||
1118 | 1119 | ||
1119 | /* Spectrum management */ | 1120 | /* Spectrum management */ |
1120 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | 1121 | void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 06d8e00a2537..8aa8558ba21e 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -235,6 +235,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
235 | spin_lock_init(&sta->lock); | 235 | spin_lock_init(&sta->lock); |
236 | spin_lock_init(&sta->flaglock); | 236 | spin_lock_init(&sta->flaglock); |
237 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); | 237 | INIT_WORK(&sta->drv_unblock_wk, sta_unblock); |
238 | INIT_WORK(&sta->ampdu_mlme.work, ieee80211_tx_ba_session_work); | ||
238 | 239 | ||
239 | memcpy(sta->sta.addr, addr, ETH_ALEN); | 240 | memcpy(sta->sta.addr, addr, ETH_ALEN); |
240 | sta->local = local; | 241 | sta->local = local; |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 05278e6288c9..040cbb0ac3af 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -67,6 +67,8 @@ enum ieee80211_sta_info_flags { | |||
67 | #define HT_AGG_STATE_RESPONSE_RECEIVED 1 | 67 | #define HT_AGG_STATE_RESPONSE_RECEIVED 1 |
68 | #define HT_AGG_STATE_OPERATIONAL 2 | 68 | #define HT_AGG_STATE_OPERATIONAL 2 |
69 | #define HT_AGG_STATE_STOPPING 3 | 69 | #define HT_AGG_STATE_STOPPING 3 |
70 | #define HT_AGG_STATE_WANT_START 4 | ||
71 | #define HT_AGG_STATE_WANT_STOP 5 | ||
70 | 72 | ||
71 | /** | 73 | /** |
72 | * struct tid_ampdu_tx - TID aggregation information (Tx). | 74 | * struct tid_ampdu_tx - TID aggregation information (Tx). |
@@ -74,7 +76,6 @@ enum ieee80211_sta_info_flags { | |||
74 | * @rcu_head: rcu head for freeing structure | 76 | * @rcu_head: rcu head for freeing structure |
75 | * @addba_resp_timer: timer for peer's response to addba request | 77 | * @addba_resp_timer: timer for peer's response to addba request |
76 | * @pending: pending frames queue -- use sta's spinlock to protect | 78 | * @pending: pending frames queue -- use sta's spinlock to protect |
77 | * @ssn: Starting Sequence Number expected to be aggregated. | ||
78 | * @dialog_token: dialog token for aggregation session | 79 | * @dialog_token: dialog token for aggregation session |
79 | * @state: session state (see above) | 80 | * @state: session state (see above) |
80 | * @stop_initiator: initiator of a session stop | 81 | * @stop_initiator: initiator of a session stop |
@@ -92,7 +93,6 @@ struct tid_ampdu_tx { | |||
92 | struct timer_list addba_resp_timer; | 93 | struct timer_list addba_resp_timer; |
93 | struct sk_buff_head pending; | 94 | struct sk_buff_head pending; |
94 | unsigned long state; | 95 | unsigned long state; |
95 | u16 ssn; | ||
96 | u8 dialog_token; | 96 | u8 dialog_token; |
97 | u8 stop_initiator; | 97 | u8 stop_initiator; |
98 | }; | 98 | }; |
@@ -139,11 +139,13 @@ struct tid_ampdu_rx { | |||
139 | * @tid_tx: aggregation info for Tx per TID | 139 | * @tid_tx: aggregation info for Tx per TID |
140 | * @addba_req_num: number of times addBA request has been sent. | 140 | * @addba_req_num: number of times addBA request has been sent. |
141 | * @dialog_token_allocator: dialog token enumerator for each new session; | 141 | * @dialog_token_allocator: dialog token enumerator for each new session; |
142 | * @work: work struct for starting/stopping aggregation | ||
142 | */ | 143 | */ |
143 | struct sta_ampdu_mlme { | 144 | struct sta_ampdu_mlme { |
144 | /* rx */ | 145 | /* rx */ |
145 | struct tid_ampdu_rx *tid_rx[STA_TID_NUM]; | 146 | struct tid_ampdu_rx *tid_rx[STA_TID_NUM]; |
146 | /* tx */ | 147 | /* tx */ |
148 | struct work_struct work; | ||
147 | struct tid_ampdu_tx *tid_tx[STA_TID_NUM]; | 149 | struct tid_ampdu_tx *tid_tx[STA_TID_NUM]; |
148 | u8 addba_req_num[STA_TID_NUM]; | 150 | u8 addba_req_num[STA_TID_NUM]; |
149 | u8 dialog_token_allocator; | 151 | u8 dialog_token_allocator; |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7bf1f9c9ea34..698d4718b1a4 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1102,6 +1102,11 @@ static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx, | |||
1102 | 1102 | ||
1103 | if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) { | 1103 | if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) { |
1104 | info->flags |= IEEE80211_TX_CTL_AMPDU; | 1104 | info->flags |= IEEE80211_TX_CTL_AMPDU; |
1105 | } else if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { | ||
1106 | /* | ||
1107 | * nothing -- this aggregation session is being started | ||
1108 | * but that might still fail with the driver | ||
1109 | */ | ||
1105 | } else { | 1110 | } else { |
1106 | spin_lock(&tx->sta->lock); | 1111 | spin_lock(&tx->sta->lock); |
1107 | /* | 1112 | /* |