]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - net/mac80211/agg-tx.c
mac80211: hardware should not deny going back to legacy
[mirror_ubuntu-artful-kernel.git] / net / mac80211 / agg-tx.c
CommitLineData
b8695a8f
JB
1/*
2 * HT handling
3 *
4 * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
5 * Copyright 2002-2005, Instant802 Networks, Inc.
6 * Copyright 2005-2006, Devicescape Software, Inc.
7 * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
8 * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
9 * Copyright 2007-2009, Intel Corporation
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 */
15
16#include <linux/ieee80211.h>
17#include <net/mac80211.h>
18#include "ieee80211_i.h"
19#include "wme.h"
20
21static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
22 const u8 *da, u16 tid,
23 u8 dialog_token, u16 start_seq_num,
24 u16 agg_size, u16 timeout)
25{
26 struct ieee80211_local *local = sdata->local;
27 struct ieee80211_if_sta *ifsta = &sdata->u.sta;
28 struct sk_buff *skb;
29 struct ieee80211_mgmt *mgmt;
30 u16 capab;
31
32 skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
33
34 if (!skb) {
35 printk(KERN_ERR "%s: failed to allocate buffer "
36 "for addba request frame\n", sdata->dev->name);
37 return;
38 }
39 skb_reserve(skb, local->hw.extra_tx_headroom);
40 mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
41 memset(mgmt, 0, 24);
42 memcpy(mgmt->da, da, ETH_ALEN);
43 memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
8abd3f9b
JB
44 if (sdata->vif.type == NL80211_IFTYPE_AP ||
45 sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
b8695a8f
JB
46 memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
47 else
48 memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
49
50 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
51 IEEE80211_STYPE_ACTION);
52
53 skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
54
55 mgmt->u.action.category = WLAN_CATEGORY_BACK;
56 mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
57
58 mgmt->u.action.u.addba_req.dialog_token = dialog_token;
59 capab = (u16)(1 << 1); /* bit 1 aggregation policy */
60 capab |= (u16)(tid << 2); /* bit 5:2 TID number */
61 capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */
62
63 mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
64
65 mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
66 mgmt->u.action.u.addba_req.start_seq_num =
67 cpu_to_le16(start_seq_num << 4);
68
69 ieee80211_tx_skb(sdata, skb, 1);
70}
71
72void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn)
73{
74 struct ieee80211_local *local = sdata->local;
75 struct sk_buff *skb;
76 struct ieee80211_bar *bar;
77 u16 bar_control = 0;
78
79 skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
80 if (!skb) {
81 printk(KERN_ERR "%s: failed to allocate buffer for "
82 "bar frame\n", sdata->dev->name);
83 return;
84 }
85 skb_reserve(skb, local->hw.extra_tx_headroom);
86 bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar));
87 memset(bar, 0, sizeof(*bar));
88 bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
89 IEEE80211_STYPE_BACK_REQ);
90 memcpy(bar->ra, ra, ETH_ALEN);
91 memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN);
92 bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
93 bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
94 bar_control |= (u16)(tid << 12);
95 bar->control = cpu_to_le16(bar_control);
96 bar->start_seq_num = cpu_to_le16(ssn);
97
98 ieee80211_tx_skb(sdata, skb, 0);
99}
100
101/*
102 * After sending add Block Ack request we activated a timer until
103 * add Block Ack response will arrive from the recipient.
104 * If this timer expires sta_addba_resp_timer_expired will be executed.
105 */
106static void sta_addba_resp_timer_expired(unsigned long data)
107{
108 /* not an elegant detour, but there is no choice as the timer passes
109 * only one argument, and both sta_info and TID are needed, so init
110 * flow in sta_info_create gives the TID as data, while the timer_to_id
111 * array gives the sta through container_of */
112 u16 tid = *(u8 *)data;
113 struct sta_info *temp_sta = container_of((void *)data,
114 struct sta_info, timer_to_tid[tid]);
115
116 struct ieee80211_local *local = temp_sta->local;
117 struct ieee80211_hw *hw = &local->hw;
118 struct sta_info *sta;
119 u8 *state;
120
121 rcu_read_lock();
122
123 sta = sta_info_get(local, temp_sta->sta.addr);
124 if (!sta) {
125 rcu_read_unlock();
126 return;
127 }
128
129 state = &sta->ampdu_mlme.tid_state_tx[tid];
130 /* check if the TID waits for addBA response */
131 spin_lock_bh(&sta->lock);
132 if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
133 spin_unlock_bh(&sta->lock);
134 *state = HT_AGG_STATE_IDLE;
135#ifdef CONFIG_MAC80211_HT_DEBUG
136 printk(KERN_DEBUG "timer expired on tid %d but we are not "
137 "expecting addBA response there", tid);
138#endif
139 goto timer_expired_exit;
140 }
141
142#ifdef CONFIG_MAC80211_HT_DEBUG
143 printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
144#endif
145
146 /* go through the state check in stop_BA_session */
147 *state = HT_AGG_STATE_OPERATIONAL;
148 spin_unlock_bh(&sta->lock);
149 ieee80211_stop_tx_ba_session(hw, temp_sta->sta.addr, tid,
150 WLAN_BACK_INITIATOR);
151
152timer_expired_exit:
153 rcu_read_unlock();
154}
155
156int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
157{
158 struct ieee80211_local *local = hw_to_local(hw);
159 struct sta_info *sta;
160 struct ieee80211_sub_if_data *sdata;
161 u16 start_seq_num;
162 u8 *state;
163 int ret = 0;
164
165 if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
166 return -EINVAL;
167
168#ifdef CONFIG_MAC80211_HT_DEBUG
169 printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
170 ra, tid);
171#endif /* CONFIG_MAC80211_HT_DEBUG */
172
173 rcu_read_lock();
174
175 sta = sta_info_get(local, ra);
176 if (!sta) {
177#ifdef CONFIG_MAC80211_HT_DEBUG
178 printk(KERN_DEBUG "Could not find the station\n");
179#endif
180 ret = -ENOENT;
181 goto exit;
182 }
183
8abd3f9b
JB
184 /*
185 * The aggregation code is not prepared to handle
186 * anything but STA/AP due to the BSSID handling.
187 * IBSS could work in the code but isn't supported
188 * by drivers or the standard.
189 */
190 if (sta->sdata->vif.type != NL80211_IFTYPE_STATION &&
191 sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
192 sta->sdata->vif.type != NL80211_IFTYPE_AP) {
193 ret = -EINVAL;
194 goto exit;
195 }
196
b8695a8f
JB
197 spin_lock_bh(&sta->lock);
198
199 /* we have tried too many times, receiver does not want A-MPDU */
200 if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
201 ret = -EBUSY;
202 goto err_unlock_sta;
203 }
204
205 state = &sta->ampdu_mlme.tid_state_tx[tid];
206 /* check if the TID is not in aggregation flow already */
207 if (*state != HT_AGG_STATE_IDLE) {
208#ifdef CONFIG_MAC80211_HT_DEBUG
209 printk(KERN_DEBUG "BA request denied - session is not "
210 "idle on tid %u\n", tid);
211#endif /* CONFIG_MAC80211_HT_DEBUG */
212 ret = -EAGAIN;
213 goto err_unlock_sta;
214 }
215
216 /* prepare A-MPDU MLME for Tx aggregation */
217 sta->ampdu_mlme.tid_tx[tid] =
218 kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
219 if (!sta->ampdu_mlme.tid_tx[tid]) {
220#ifdef CONFIG_MAC80211_HT_DEBUG
221 if (net_ratelimit())
222 printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
223 tid);
224#endif
225 ret = -ENOMEM;
226 goto err_unlock_sta;
227 }
228 /* Tx timer */
229 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
230 sta_addba_resp_timer_expired;
231 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data =
232 (unsigned long)&sta->timer_to_tid[tid];
233 init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
234
235 if (hw->ampdu_queues) {
236 /* create a new queue for this aggregation */
237 ret = ieee80211_ht_agg_queue_add(local, sta, tid);
238
239 /* case no queue is available to aggregation
240 * don't switch to aggregation */
241 if (ret) {
242#ifdef CONFIG_MAC80211_HT_DEBUG
243 printk(KERN_DEBUG "BA request denied - "
244 "queue unavailable for tid %d\n", tid);
245#endif /* CONFIG_MAC80211_HT_DEBUG */
246 goto err_unlock_queue;
247 }
248 }
249 sdata = sta->sdata;
250
251 /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
252 * call back right away, it must see that the flow has begun */
253 *state |= HT_ADDBA_REQUESTED_MSK;
254
255 /* This is slightly racy because the queue isn't stopped */
256 start_seq_num = sta->tid_seq[tid];
257
258 if (local->ops->ampdu_action)
259 ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
260 &sta->sta, tid, &start_seq_num);
261
262 if (ret) {
263 /* No need to requeue the packets in the agg queue, since we
264 * held the tx lock: no packet could be enqueued to the newly
265 * allocated queue */
266 if (hw->ampdu_queues)
267 ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
268#ifdef CONFIG_MAC80211_HT_DEBUG
269 printk(KERN_DEBUG "BA request denied - HW unavailable for"
270 " tid %d\n", tid);
271#endif /* CONFIG_MAC80211_HT_DEBUG */
272 *state = HT_AGG_STATE_IDLE;
273 goto err_unlock_queue;
274 }
275
276 /* Will put all the packets in the new SW queue */
277 if (hw->ampdu_queues)
278 ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
279 spin_unlock_bh(&sta->lock);
280
281 /* send an addBA request */
282 sta->ampdu_mlme.dialog_token_allocator++;
283 sta->ampdu_mlme.tid_tx[tid]->dialog_token =
284 sta->ampdu_mlme.dialog_token_allocator;
285 sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
286
287
288 ieee80211_send_addba_request(sta->sdata, ra, tid,
289 sta->ampdu_mlme.tid_tx[tid]->dialog_token,
290 sta->ampdu_mlme.tid_tx[tid]->ssn,
291 0x40, 5000);
292 /* activate the timer for the recipient's addBA response */
293 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
294 jiffies + ADDBA_RESP_INTERVAL;
295 add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
296#ifdef CONFIG_MAC80211_HT_DEBUG
297 printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
298#endif
299 goto exit;
300
301err_unlock_queue:
302 kfree(sta->ampdu_mlme.tid_tx[tid]);
303 sta->ampdu_mlme.tid_tx[tid] = NULL;
304 ret = -EBUSY;
305err_unlock_sta:
306 spin_unlock_bh(&sta->lock);
307exit:
308 rcu_read_unlock();
309 return ret;
310}
311EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
312
313void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
314{
315 struct ieee80211_local *local = hw_to_local(hw);
316 struct sta_info *sta;
317 u8 *state;
318
319 if (tid >= STA_TID_NUM) {
320#ifdef CONFIG_MAC80211_HT_DEBUG
321 printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
322 tid, STA_TID_NUM);
323#endif
324 return;
325 }
326
327 rcu_read_lock();
328 sta = sta_info_get(local, ra);
329 if (!sta) {
330 rcu_read_unlock();
331#ifdef CONFIG_MAC80211_HT_DEBUG
332 printk(KERN_DEBUG "Could not find station: %pM\n", ra);
333#endif
334 return;
335 }
336
337 state = &sta->ampdu_mlme.tid_state_tx[tid];
338 spin_lock_bh(&sta->lock);
339
340 if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
341#ifdef CONFIG_MAC80211_HT_DEBUG
342 printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
343 *state);
344#endif
345 spin_unlock_bh(&sta->lock);
346 rcu_read_unlock();
347 return;
348 }
349
350 WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK);
351
352 *state |= HT_ADDBA_DRV_READY_MSK;
353
354 if (*state == HT_AGG_STATE_OPERATIONAL) {
355#ifdef CONFIG_MAC80211_HT_DEBUG
356 printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
357#endif
358 if (hw->ampdu_queues)
359 ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
360 }
361 spin_unlock_bh(&sta->lock);
362 rcu_read_unlock();
363}
364EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
365
366
367int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
368 u8 *ra, u16 tid,
369 enum ieee80211_back_parties initiator)
370{
371 struct ieee80211_local *local = hw_to_local(hw);
372 struct sta_info *sta;
373 u8 *state;
374 int ret = 0;
375
376 if (tid >= STA_TID_NUM)
377 return -EINVAL;
378
379 rcu_read_lock();
380 sta = sta_info_get(local, ra);
381 if (!sta) {
382 rcu_read_unlock();
383 return -ENOENT;
384 }
385
386 /* check if the TID is in aggregation */
387 state = &sta->ampdu_mlme.tid_state_tx[tid];
388 spin_lock_bh(&sta->lock);
389
390 if (*state != HT_AGG_STATE_OPERATIONAL) {
391 ret = -ENOENT;
392 goto stop_BA_exit;
393 }
394
395#ifdef CONFIG_MAC80211_HT_DEBUG
396 printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
397 ra, tid);
398#endif /* CONFIG_MAC80211_HT_DEBUG */
399
400 if (hw->ampdu_queues)
401 ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]);
402
403 *state = HT_AGG_STATE_REQ_STOP_BA_MSK |
404 (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
405
406 if (local->ops->ampdu_action)
407 ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP,
408 &sta->sta, tid, NULL);
409
955d3fe3
JB
410 /* HW shall not deny going back to legacy */
411 if (WARN_ON(ret)) {
b8695a8f
JB
412 *state = HT_AGG_STATE_OPERATIONAL;
413 if (hw->ampdu_queues)
414 ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
415 goto stop_BA_exit;
416 }
417
418stop_BA_exit:
419 spin_unlock_bh(&sta->lock);
420 rcu_read_unlock();
421 return ret;
422}
423EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
424
425void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
426{
427 struct ieee80211_local *local = hw_to_local(hw);
428 struct sta_info *sta;
429 u8 *state;
430 int agg_queue;
431
432 if (tid >= STA_TID_NUM) {
433#ifdef CONFIG_MAC80211_HT_DEBUG
434 printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
435 tid, STA_TID_NUM);
436#endif
437 return;
438 }
439
440#ifdef CONFIG_MAC80211_HT_DEBUG
441 printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n",
442 ra, tid);
443#endif /* CONFIG_MAC80211_HT_DEBUG */
444
445 rcu_read_lock();
446 sta = sta_info_get(local, ra);
447 if (!sta) {
448#ifdef CONFIG_MAC80211_HT_DEBUG
449 printk(KERN_DEBUG "Could not find station: %pM\n", ra);
450#endif
451 rcu_read_unlock();
452 return;
453 }
454 state = &sta->ampdu_mlme.tid_state_tx[tid];
455
456 /* NOTE: no need to use sta->lock in this state check, as
457 * ieee80211_stop_tx_ba_session will let only one stop call to
458 * pass through per sta/tid
459 */
460 if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
461#ifdef CONFIG_MAC80211_HT_DEBUG
462 printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
463#endif
464 rcu_read_unlock();
465 return;
466 }
467
468 if (*state & HT_AGG_STATE_INITIATOR_MSK)
469 ieee80211_send_delba(sta->sdata, ra, tid,
470 WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
471
472 if (hw->ampdu_queues) {
473 agg_queue = sta->tid_to_tx_q[tid];
474 ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
475
476 /* We just requeued the all the frames that were in the
477 * removed queue, and since we might miss a softirq we do
478 * netif_schedule_queue. ieee80211_wake_queue is not used
479 * here as this queue is not necessarily stopped
480 */
481 netif_schedule_queue(netdev_get_tx_queue(local->mdev,
482 agg_queue));
483 }
484 spin_lock_bh(&sta->lock);
485 *state = HT_AGG_STATE_IDLE;
486 sta->ampdu_mlme.addba_req_num[tid] = 0;
487 kfree(sta->ampdu_mlme.tid_tx[tid]);
488 sta->ampdu_mlme.tid_tx[tid] = NULL;
489 spin_unlock_bh(&sta->lock);
490
491 rcu_read_unlock();
492}
493EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
494
495void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
496 const u8 *ra, u16 tid)
497{
498 struct ieee80211_local *local = hw_to_local(hw);
499 struct ieee80211_ra_tid *ra_tid;
500 struct sk_buff *skb = dev_alloc_skb(0);
501
502 if (unlikely(!skb)) {
503#ifdef CONFIG_MAC80211_HT_DEBUG
504 if (net_ratelimit())
505 printk(KERN_WARNING "%s: Not enough memory, "
506 "dropping start BA session", skb->dev->name);
507#endif
508 return;
509 }
510 ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
511 memcpy(&ra_tid->ra, ra, ETH_ALEN);
512 ra_tid->tid = tid;
513
514 skb->pkt_type = IEEE80211_ADDBA_MSG;
515 skb_queue_tail(&local->skb_queue, skb);
516 tasklet_schedule(&local->tasklet);
517}
518EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
519
520void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
521 const u8 *ra, u16 tid)
522{
523 struct ieee80211_local *local = hw_to_local(hw);
524 struct ieee80211_ra_tid *ra_tid;
525 struct sk_buff *skb = dev_alloc_skb(0);
526
527 if (unlikely(!skb)) {
528#ifdef CONFIG_MAC80211_HT_DEBUG
529 if (net_ratelimit())
530 printk(KERN_WARNING "%s: Not enough memory, "
531 "dropping stop BA session", skb->dev->name);
532#endif
533 return;
534 }
535 ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
536 memcpy(&ra_tid->ra, ra, ETH_ALEN);
537 ra_tid->tid = tid;
538
539 skb->pkt_type = IEEE80211_DELBA_MSG;
540 skb_queue_tail(&local->skb_queue, skb);
541 tasklet_schedule(&local->tasklet);
542}
543EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
544
545void ieee80211_process_addba_resp(struct ieee80211_local *local,
546 struct sta_info *sta,
547 struct ieee80211_mgmt *mgmt,
548 size_t len)
549{
550 struct ieee80211_hw *hw = &local->hw;
551 u16 capab;
552 u16 tid, start_seq_num;
553 u8 *state;
554
555 capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
556 tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
557
558 state = &sta->ampdu_mlme.tid_state_tx[tid];
559
560 spin_lock_bh(&sta->lock);
561
562 if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
563 spin_unlock_bh(&sta->lock);
564 return;
565 }
566
567 if (mgmt->u.action.u.addba_resp.dialog_token !=
568 sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
569 spin_unlock_bh(&sta->lock);
570#ifdef CONFIG_MAC80211_HT_DEBUG
571 printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
572#endif /* CONFIG_MAC80211_HT_DEBUG */
573 return;
574 }
575
576 del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
577#ifdef CONFIG_MAC80211_HT_DEBUG
578 printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
579#endif /* CONFIG_MAC80211_HT_DEBUG */
580 if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
581 == WLAN_STATUS_SUCCESS) {
582 *state |= HT_ADDBA_RECEIVED_MSK;
583 sta->ampdu_mlme.addba_req_num[tid] = 0;
584
585 if (*state == HT_AGG_STATE_OPERATIONAL &&
586 local->hw.ampdu_queues)
587 ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
588
589 if (local->ops->ampdu_action) {
590 (void)local->ops->ampdu_action(hw,
591 IEEE80211_AMPDU_TX_RESUME,
592 &sta->sta, tid, &start_seq_num);
593 }
594#ifdef CONFIG_MAC80211_HT_DEBUG
595 printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid);
596#endif /* CONFIG_MAC80211_HT_DEBUG */
597 spin_unlock_bh(&sta->lock);
598 } else {
599 sta->ampdu_mlme.addba_req_num[tid]++;
600 /* this will allow the state check in stop_BA_session */
601 *state = HT_AGG_STATE_OPERATIONAL;
602 spin_unlock_bh(&sta->lock);
603 ieee80211_stop_tx_ba_session(hw, sta->sta.addr, tid,
604 WLAN_BACK_INITIATOR);
605 }
606}