blob: c91b32a3f0e7106b0ac5ff82ce824ca5bac1b241 [file] [log] [blame]
Johannes Bergb8695a82009-02-10 21:25:46 +01001/*
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);
Johannes Berg8abd3f92009-02-10 21:25:47 +010044 if (sdata->vif.type == NL80211_IFTYPE_AP ||
45 sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
Johannes Bergb8695a82009-02-10 21:25:46 +010046 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
Johannes Berg8abd3f92009-02-10 21:25:47 +0100184 /*
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
Johannes Bergb8695a82009-02-10 21:25:46 +0100197 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
410 /* case HW denied going back to legacy */
411 if (ret) {
412 WARN_ON(ret != -EBUSY);
413 *state = HT_AGG_STATE_OPERATIONAL;
414 if (hw->ampdu_queues)
415 ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
416 goto stop_BA_exit;
417 }
418
419stop_BA_exit:
420 spin_unlock_bh(&sta->lock);
421 rcu_read_unlock();
422 return ret;
423}
424EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
425
426void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
427{
428 struct ieee80211_local *local = hw_to_local(hw);
429 struct sta_info *sta;
430 u8 *state;
431 int agg_queue;
432
433 if (tid >= STA_TID_NUM) {
434#ifdef CONFIG_MAC80211_HT_DEBUG
435 printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
436 tid, STA_TID_NUM);
437#endif
438 return;
439 }
440
441#ifdef CONFIG_MAC80211_HT_DEBUG
442 printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n",
443 ra, tid);
444#endif /* CONFIG_MAC80211_HT_DEBUG */
445
446 rcu_read_lock();
447 sta = sta_info_get(local, ra);
448 if (!sta) {
449#ifdef CONFIG_MAC80211_HT_DEBUG
450 printk(KERN_DEBUG "Could not find station: %pM\n", ra);
451#endif
452 rcu_read_unlock();
453 return;
454 }
455 state = &sta->ampdu_mlme.tid_state_tx[tid];
456
457 /* NOTE: no need to use sta->lock in this state check, as
458 * ieee80211_stop_tx_ba_session will let only one stop call to
459 * pass through per sta/tid
460 */
461 if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
462#ifdef CONFIG_MAC80211_HT_DEBUG
463 printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
464#endif
465 rcu_read_unlock();
466 return;
467 }
468
469 if (*state & HT_AGG_STATE_INITIATOR_MSK)
470 ieee80211_send_delba(sta->sdata, ra, tid,
471 WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
472
473 if (hw->ampdu_queues) {
474 agg_queue = sta->tid_to_tx_q[tid];
475 ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
476
477 /* We just requeued the all the frames that were in the
478 * removed queue, and since we might miss a softirq we do
479 * netif_schedule_queue. ieee80211_wake_queue is not used
480 * here as this queue is not necessarily stopped
481 */
482 netif_schedule_queue(netdev_get_tx_queue(local->mdev,
483 agg_queue));
484 }
485 spin_lock_bh(&sta->lock);
486 *state = HT_AGG_STATE_IDLE;
487 sta->ampdu_mlme.addba_req_num[tid] = 0;
488 kfree(sta->ampdu_mlme.tid_tx[tid]);
489 sta->ampdu_mlme.tid_tx[tid] = NULL;
490 spin_unlock_bh(&sta->lock);
491
492 rcu_read_unlock();
493}
494EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
495
496void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
497 const u8 *ra, u16 tid)
498{
499 struct ieee80211_local *local = hw_to_local(hw);
500 struct ieee80211_ra_tid *ra_tid;
501 struct sk_buff *skb = dev_alloc_skb(0);
502
503 if (unlikely(!skb)) {
504#ifdef CONFIG_MAC80211_HT_DEBUG
505 if (net_ratelimit())
506 printk(KERN_WARNING "%s: Not enough memory, "
507 "dropping start BA session", skb->dev->name);
508#endif
509 return;
510 }
511 ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
512 memcpy(&ra_tid->ra, ra, ETH_ALEN);
513 ra_tid->tid = tid;
514
515 skb->pkt_type = IEEE80211_ADDBA_MSG;
516 skb_queue_tail(&local->skb_queue, skb);
517 tasklet_schedule(&local->tasklet);
518}
519EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
520
521void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
522 const u8 *ra, u16 tid)
523{
524 struct ieee80211_local *local = hw_to_local(hw);
525 struct ieee80211_ra_tid *ra_tid;
526 struct sk_buff *skb = dev_alloc_skb(0);
527
528 if (unlikely(!skb)) {
529#ifdef CONFIG_MAC80211_HT_DEBUG
530 if (net_ratelimit())
531 printk(KERN_WARNING "%s: Not enough memory, "
532 "dropping stop BA session", skb->dev->name);
533#endif
534 return;
535 }
536 ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
537 memcpy(&ra_tid->ra, ra, ETH_ALEN);
538 ra_tid->tid = tid;
539
540 skb->pkt_type = IEEE80211_DELBA_MSG;
541 skb_queue_tail(&local->skb_queue, skb);
542 tasklet_schedule(&local->tasklet);
543}
544EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
545
546void ieee80211_process_addba_resp(struct ieee80211_local *local,
547 struct sta_info *sta,
548 struct ieee80211_mgmt *mgmt,
549 size_t len)
550{
551 struct ieee80211_hw *hw = &local->hw;
552 u16 capab;
553 u16 tid, start_seq_num;
554 u8 *state;
555
556 capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
557 tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
558
559 state = &sta->ampdu_mlme.tid_state_tx[tid];
560
561 spin_lock_bh(&sta->lock);
562
563 if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
564 spin_unlock_bh(&sta->lock);
565 return;
566 }
567
568 if (mgmt->u.action.u.addba_resp.dialog_token !=
569 sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
570 spin_unlock_bh(&sta->lock);
571#ifdef CONFIG_MAC80211_HT_DEBUG
572 printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
573#endif /* CONFIG_MAC80211_HT_DEBUG */
574 return;
575 }
576
577 del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
578#ifdef CONFIG_MAC80211_HT_DEBUG
579 printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
580#endif /* CONFIG_MAC80211_HT_DEBUG */
581 if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
582 == WLAN_STATUS_SUCCESS) {
583 *state |= HT_ADDBA_RECEIVED_MSK;
584 sta->ampdu_mlme.addba_req_num[tid] = 0;
585
586 if (*state == HT_AGG_STATE_OPERATIONAL &&
587 local->hw.ampdu_queues)
588 ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
589
590 if (local->ops->ampdu_action) {
591 (void)local->ops->ampdu_action(hw,
592 IEEE80211_AMPDU_TX_RESUME,
593 &sta->sta, tid, &start_seq_num);
594 }
595#ifdef CONFIG_MAC80211_HT_DEBUG
596 printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid);
597#endif /* CONFIG_MAC80211_HT_DEBUG */
598 spin_unlock_bh(&sta->lock);
599 } else {
600 sta->ampdu_mlme.addba_req_num[tid]++;
601 /* this will allow the state check in stop_BA_session */
602 *state = HT_AGG_STATE_OPERATIONAL;
603 spin_unlock_bh(&sta->lock);
604 ieee80211_stop_tx_ba_session(hw, sta->sta.addr, tid,
605 WLAN_BACK_INITIATOR);
606 }
607}