1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include <linux/ieee80211.h>
17#include <net/mac80211.h>
18#include "ieee80211_i.h"
19#include "driver-ops.h"
20#include "wme.h"
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
48 const u8 *da, u16 tid,
49 u8 dialog_token, u16 start_seq_num,
50 u16 agg_size, u16 timeout)
51{
52 struct ieee80211_local *local = sdata->local;
53 struct sk_buff *skb;
54 struct ieee80211_mgmt *mgmt;
55 u16 capab;
56
57 skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
58
59 if (!skb) {
60 printk(KERN_ERR "%s: failed to allocate buffer "
61 "for addba request frame\n", sdata->dev->name);
62 return;
63 }
64 skb_reserve(skb, local->hw.extra_tx_headroom);
65 mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
66 memset(mgmt, 0, 24);
67 memcpy(mgmt->da, da, ETH_ALEN);
68 memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
69 if (sdata->vif.type == NL80211_IFTYPE_AP ||
70 sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
71 memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
72 else if (sdata->vif.type == NL80211_IFTYPE_STATION)
73 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
74
75 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
76 IEEE80211_STYPE_ACTION);
77
78 skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
79
80 mgmt->u.action.category = WLAN_CATEGORY_BACK;
81 mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
82
83 mgmt->u.action.u.addba_req.dialog_token = dialog_token;
84 capab = (u16)(1 << 1);
85 capab |= (u16)(tid << 2);
86 capab |= (u16)(agg_size << 6);
87
88 mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
89
90 mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
91 mgmt->u.action.u.addba_req.start_seq_num =
92 cpu_to_le16(start_seq_num << 4);
93
94 ieee80211_tx_skb(sdata, skb, 1);
95}
96
97void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn)
98{
99 struct ieee80211_local *local = sdata->local;
100 struct sk_buff *skb;
101 struct ieee80211_bar *bar;
102 u16 bar_control = 0;
103
104 skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
105 if (!skb) {
106 printk(KERN_ERR "%s: failed to allocate buffer for "
107 "bar frame\n", sdata->dev->name);
108 return;
109 }
110 skb_reserve(skb, local->hw.extra_tx_headroom);
111 bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar));
112 memset(bar, 0, sizeof(*bar));
113 bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
114 IEEE80211_STYPE_BACK_REQ);
115 memcpy(bar->ra, ra, ETH_ALEN);
116 memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN);
117 bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
118 bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
119 bar_control |= (u16)(tid << 12);
120 bar->control = cpu_to_le16(bar_control);
121 bar->start_seq_num = cpu_to_le16(ssn);
122
123 ieee80211_tx_skb(sdata, skb, 0);
124}
125
126int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
127 enum ieee80211_back_parties initiator)
128{
129 struct ieee80211_local *local = sta->local;
130 int ret;
131 u8 *state;
132
133#ifdef CONFIG_MAC80211_HT_DEBUG
134 printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
135 sta->sta.addr, tid);
136#endif
137
138 state = &sta->ampdu_mlme.tid_state_tx[tid];
139
140 if (*state == HT_AGG_STATE_OPERATIONAL)
141 sta->ampdu_mlme.addba_req_num[tid] = 0;
142
143 *state = HT_AGG_STATE_REQ_STOP_BA_MSK |
144 (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
145
146 ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_STOP,
147 &sta->sta, tid, NULL);
148
149
150 if (WARN_ON(ret)) {
151
152
153
154
155 }
156
157 return ret;
158}
159
160
161
162
163
164
165static void sta_addba_resp_timer_expired(unsigned long data)
166{
167
168
169
170
171 u16 tid = *(u8 *)data;
172 struct sta_info *sta = container_of((void *)data,
173 struct sta_info, timer_to_tid[tid]);
174 u8 *state;
175
176 state = &sta->ampdu_mlme.tid_state_tx[tid];
177
178
179 spin_lock_bh(&sta->lock);
180 if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK)) !=
181 HT_ADDBA_REQUESTED_MSK) {
182 spin_unlock_bh(&sta->lock);
183 *state = HT_AGG_STATE_IDLE;
184#ifdef CONFIG_MAC80211_HT_DEBUG
185 printk(KERN_DEBUG "timer expired on tid %d but we are not "
186 "(or no longer) expecting addBA response there",
187 tid);
188#endif
189 return;
190 }
191
192#ifdef CONFIG_MAC80211_HT_DEBUG
193 printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
194#endif
195
196 ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR);
197 spin_unlock_bh(&sta->lock);
198}
199
200static inline int ieee80211_ac_from_tid(int tid)
201{
202 return ieee802_1d_to_ac[tid & 7];
203}
204
205int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
206{
207 struct ieee80211_local *local = hw_to_local(hw);
208 struct sta_info *sta;
209 struct ieee80211_sub_if_data *sdata;
210 u8 *state;
211 int ret = 0;
212 u16 start_seq_num;
213
214 if (WARN_ON(!local->ops->ampdu_action))
215 return -EINVAL;
216
217 if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
218 return -EINVAL;
219
220#ifdef CONFIG_MAC80211_HT_DEBUG
221 printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
222 ra, tid);
223#endif
224
225 rcu_read_lock();
226
227 sta = sta_info_get(local, ra);
228 if (!sta) {
229#ifdef CONFIG_MAC80211_HT_DEBUG
230 printk(KERN_DEBUG "Could not find the station\n");
231#endif
232 ret = -ENOENT;
233 goto unlock;
234 }
235
236
237
238
239
240
241
242 if (sta->sdata->vif.type != NL80211_IFTYPE_STATION &&
243 sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
244 sta->sdata->vif.type != NL80211_IFTYPE_AP) {
245 ret = -EINVAL;
246 goto unlock;
247 }
248
249 if (test_sta_flags(sta, WLAN_STA_SUSPEND)) {
250#ifdef CONFIG_MAC80211_HT_DEBUG
251 printk(KERN_DEBUG "Suspend in progress. "
252 "Denying BA session request\n");
253#endif
254 ret = -EINVAL;
255 goto unlock;
256 }
257
258 spin_lock_bh(&sta->lock);
259 spin_lock(&local->ampdu_lock);
260
261 sdata = sta->sdata;
262
263
264 if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
265 ret = -EBUSY;
266 goto err_unlock_sta;
267 }
268
269 state = &sta->ampdu_mlme.tid_state_tx[tid];
270
271 if (*state != HT_AGG_STATE_IDLE) {
272#ifdef CONFIG_MAC80211_HT_DEBUG
273 printk(KERN_DEBUG "BA request denied - session is not "
274 "idle on tid %u\n", tid);
275#endif
276 ret = -EAGAIN;
277 goto err_unlock_sta;
278 }
279
280
281
282
283
284
285
286
287 ieee80211_stop_queue_by_reason(
288 &local->hw, ieee80211_ac_from_tid(tid),
289 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
290
291
292 sta->ampdu_mlme.tid_tx[tid] =
293 kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
294 if (!sta->ampdu_mlme.tid_tx[tid]) {
295#ifdef CONFIG_MAC80211_HT_DEBUG
296 if (net_ratelimit())
297 printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
298 tid);
299#endif
300 ret = -ENOMEM;
301 goto err_wake_queue;
302 }
303
304 skb_queue_head_init(&sta->ampdu_mlme.tid_tx[tid]->pending);
305
306
307 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
308 sta_addba_resp_timer_expired;
309 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data =
310 (unsigned long)&sta->timer_to_tid[tid];
311 init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
312
313
314
315 *state |= HT_ADDBA_REQUESTED_MSK;
316
317 start_seq_num = sta->tid_seq[tid];
318
319 ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_START,
320 &sta->sta, tid, &start_seq_num);
321
322 if (ret) {
323#ifdef CONFIG_MAC80211_HT_DEBUG
324 printk(KERN_DEBUG "BA request denied - HW unavailable for"
325 " tid %d\n", tid);
326#endif
327 *state = HT_AGG_STATE_IDLE;
328 goto err_free;
329 }
330
331
332 ieee80211_wake_queue_by_reason(
333 &local->hw, ieee80211_ac_from_tid(tid),
334 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
335
336 spin_unlock(&local->ampdu_lock);
337 spin_unlock_bh(&sta->lock);
338
339
340 sta->ampdu_mlme.dialog_token_allocator++;
341 sta->ampdu_mlme.tid_tx[tid]->dialog_token =
342 sta->ampdu_mlme.dialog_token_allocator;
343 sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
344
345 ieee80211_send_addba_request(sta->sdata, ra, tid,
346 sta->ampdu_mlme.tid_tx[tid]->dialog_token,
347 sta->ampdu_mlme.tid_tx[tid]->ssn,
348 0x40, 5000);
349 sta->ampdu_mlme.addba_req_num[tid]++;
350
351 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
352 jiffies + ADDBA_RESP_INTERVAL;
353 add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
354#ifdef CONFIG_MAC80211_HT_DEBUG
355 printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
356#endif
357 goto unlock;
358
359 err_free:
360 kfree(sta->ampdu_mlme.tid_tx[tid]);
361 sta->ampdu_mlme.tid_tx[tid] = NULL;
362 err_wake_queue:
363 ieee80211_wake_queue_by_reason(
364 &local->hw, ieee80211_ac_from_tid(tid),
365 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
366 err_unlock_sta:
367 spin_unlock(&local->ampdu_lock);
368 spin_unlock_bh(&sta->lock);
369 unlock:
370 rcu_read_unlock();
371 return ret;
372}
373EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
374
375
376
377
378
379
380static void ieee80211_agg_splice_packets(struct ieee80211_local *local,
381 struct sta_info *sta, u16 tid)
382{
383 unsigned long flags;
384 u16 queue = ieee80211_ac_from_tid(tid);
385
386 ieee80211_stop_queue_by_reason(
387 &local->hw, queue,
388 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
389
390 if (!(sta->ampdu_mlme.tid_state_tx[tid] & HT_ADDBA_REQUESTED_MSK))
391 return;
392
393 if (WARN(!sta->ampdu_mlme.tid_tx[tid],
394 "TID %d gone but expected when splicing aggregates from"
395 "the pending queue\n", tid))
396 return;
397
398 if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) {
399 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
400
401 skb_queue_splice_tail_init(
402 &sta->ampdu_mlme.tid_tx[tid]->pending,
403 &local->pending[queue]);
404 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
405 }
406}
407
408static void ieee80211_agg_splice_finish(struct ieee80211_local *local,
409 struct sta_info *sta, u16 tid)
410{
411 u16 queue = ieee80211_ac_from_tid(tid);
412
413 ieee80211_wake_queue_by_reason(
414 &local->hw, queue,
415 IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
416}
417
418
419static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
420 struct sta_info *sta, u16 tid)
421{
422#ifdef CONFIG_MAC80211_HT_DEBUG
423 printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
424#endif
425
426 spin_lock(&local->ampdu_lock);
427 ieee80211_agg_splice_packets(local, sta, tid);
428
429
430
431
432
433
434 ieee80211_agg_splice_finish(local, sta, tid);
435 spin_unlock(&local->ampdu_lock);
436
437 drv_ampdu_action(local, IEEE80211_AMPDU_TX_OPERATIONAL,
438 &sta->sta, tid, NULL);
439}
440
441void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
442{
443 struct ieee80211_local *local = hw_to_local(hw);
444 struct sta_info *sta;
445 u8 *state;
446
447 if (tid >= STA_TID_NUM) {
448#ifdef CONFIG_MAC80211_HT_DEBUG
449 printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
450 tid, STA_TID_NUM);
451#endif
452 return;
453 }
454
455 rcu_read_lock();
456 sta = sta_info_get(local, ra);
457 if (!sta) {
458 rcu_read_unlock();
459#ifdef CONFIG_MAC80211_HT_DEBUG
460 printk(KERN_DEBUG "Could not find station: %pM\n", ra);
461#endif
462 return;
463 }
464
465 state = &sta->ampdu_mlme.tid_state_tx[tid];
466 spin_lock_bh(&sta->lock);
467
468 if (WARN_ON(!(*state & HT_ADDBA_REQUESTED_MSK))) {
469#ifdef CONFIG_MAC80211_HT_DEBUG
470 printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
471 *state);
472#endif
473 spin_unlock_bh(&sta->lock);
474 rcu_read_unlock();
475 return;
476 }
477
478 if (WARN_ON(*state & HT_ADDBA_DRV_READY_MSK))
479 goto out;
480
481 *state |= HT_ADDBA_DRV_READY_MSK;
482
483 if (*state == HT_AGG_STATE_OPERATIONAL)
484 ieee80211_agg_tx_operational(local, sta, tid);
485
486 out:
487 spin_unlock_bh(&sta->lock);
488 rcu_read_unlock();
489}
490EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
491
492void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
493 const u8 *ra, u16 tid)
494{
495 struct ieee80211_local *local = hw_to_local(hw);
496 struct ieee80211_ra_tid *ra_tid;
497 struct sk_buff *skb = dev_alloc_skb(0);
498
499 if (unlikely(!skb)) {
500#ifdef CONFIG_MAC80211_HT_DEBUG
501 if (net_ratelimit())
502 printk(KERN_WARNING "%s: Not enough memory, "
503 "dropping start BA session", skb->dev->name);
504#endif
505 return;
506 }
507 ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
508 memcpy(&ra_tid->ra, ra, ETH_ALEN);
509 ra_tid->tid = tid;
510
511 skb->pkt_type = IEEE80211_ADDBA_MSG;
512 skb_queue_tail(&local->skb_queue, skb);
513 tasklet_schedule(&local->tasklet);
514}
515EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
516
517int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
518 enum ieee80211_back_parties initiator)
519{
520 u8 *state;
521 int ret;
522
523
524 state = &sta->ampdu_mlme.tid_state_tx[tid];
525 spin_lock_bh(&sta->lock);
526
527 if (*state != HT_AGG_STATE_OPERATIONAL) {
528 ret = -ENOENT;
529 goto unlock;
530 }
531
532 ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator);
533
534 unlock:
535 spin_unlock_bh(&sta->lock);
536 return ret;
537}
538
539int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
540 u8 *ra, u16 tid,
541 enum ieee80211_back_parties initiator)
542{
543 struct ieee80211_local *local = hw_to_local(hw);
544 struct sta_info *sta;
545 int ret = 0;
546
547 if (!local->ops->ampdu_action)
548 return -EINVAL;
549
550 if (tid >= STA_TID_NUM)
551 return -EINVAL;
552
553 rcu_read_lock();
554 sta = sta_info_get(local, ra);
555 if (!sta) {
556 rcu_read_unlock();
557 return -ENOENT;
558 }
559
560 ret = __ieee80211_stop_tx_ba_session(sta, tid, initiator);
561 rcu_read_unlock();
562 return ret;
563}
564EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
565
566void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
567{
568 struct ieee80211_local *local = hw_to_local(hw);
569 struct sta_info *sta;
570 u8 *state;
571
572 if (tid >= STA_TID_NUM) {
573#ifdef CONFIG_MAC80211_HT_DEBUG
574 printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
575 tid, STA_TID_NUM);
576#endif
577 return;
578 }
579
580#ifdef CONFIG_MAC80211_HT_DEBUG
581 printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n",
582 ra, tid);
583#endif
584
585 rcu_read_lock();
586 sta = sta_info_get(local, ra);
587 if (!sta) {
588#ifdef CONFIG_MAC80211_HT_DEBUG
589 printk(KERN_DEBUG "Could not find station: %pM\n", ra);
590#endif
591 rcu_read_unlock();
592 return;
593 }
594 state = &sta->ampdu_mlme.tid_state_tx[tid];
595
596
597
598
599
600 if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
601#ifdef CONFIG_MAC80211_HT_DEBUG
602 printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
603#endif
604 rcu_read_unlock();
605 return;
606 }
607
608 if (*state & HT_AGG_STATE_INITIATOR_MSK)
609 ieee80211_send_delba(sta->sdata, ra, tid,
610 WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
611
612 spin_lock_bh(&sta->lock);
613 spin_lock(&local->ampdu_lock);
614
615 ieee80211_agg_splice_packets(local, sta, tid);
616
617 *state = HT_AGG_STATE_IDLE;
618
619 kfree(sta->ampdu_mlme.tid_tx[tid]);
620 sta->ampdu_mlme.tid_tx[tid] = NULL;
621
622 ieee80211_agg_splice_finish(local, sta, tid);
623
624 spin_unlock(&local->ampdu_lock);
625 spin_unlock_bh(&sta->lock);
626
627 rcu_read_unlock();
628}
629EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
630
631void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
632 const u8 *ra, u16 tid)
633{
634 struct ieee80211_local *local = hw_to_local(hw);
635 struct ieee80211_ra_tid *ra_tid;
636 struct sk_buff *skb = dev_alloc_skb(0);
637
638 if (unlikely(!skb)) {
639#ifdef CONFIG_MAC80211_HT_DEBUG
640 if (net_ratelimit())
641 printk(KERN_WARNING "%s: Not enough memory, "
642 "dropping stop BA session", skb->dev->name);
643#endif
644 return;
645 }
646 ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
647 memcpy(&ra_tid->ra, ra, ETH_ALEN);
648 ra_tid->tid = tid;
649
650 skb->pkt_type = IEEE80211_DELBA_MSG;
651 skb_queue_tail(&local->skb_queue, skb);
652 tasklet_schedule(&local->tasklet);
653}
654EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
655
656
657void ieee80211_process_addba_resp(struct ieee80211_local *local,
658 struct sta_info *sta,
659 struct ieee80211_mgmt *mgmt,
660 size_t len)
661{
662 u16 capab, tid;
663 u8 *state;
664
665 capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
666 tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
667
668 state = &sta->ampdu_mlme.tid_state_tx[tid];
669
670 spin_lock_bh(&sta->lock);
671
672 if (!(*state & HT_ADDBA_REQUESTED_MSK))
673 goto out;
674
675 if (mgmt->u.action.u.addba_resp.dialog_token !=
676 sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
677#ifdef CONFIG_MAC80211_HT_DEBUG
678 printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
679#endif
680 goto out;
681 }
682
683 del_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
684
685#ifdef CONFIG_MAC80211_HT_DEBUG
686 printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
687#endif
688
689 if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
690 == WLAN_STATUS_SUCCESS) {
691 u8 curstate = *state;
692
693 *state |= HT_ADDBA_RECEIVED_MSK;
694
695 if (*state != curstate && *state == HT_AGG_STATE_OPERATIONAL)
696 ieee80211_agg_tx_operational(local, sta, tid);
697
698 sta->ampdu_mlme.addba_req_num[tid] = 0;
699 } else {
700 ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR);
701 }
702
703 out:
704 spin_unlock_bh(&sta->lock);
705}
706