1
2
3
4
5
6
7
8#include <asm/byteorder.h>
9#include <asm/unaligned.h>
10#include "ieee80211.h"
11#include "rtl819x_BA.h"
12
13
14
15
16
17
18
19static void ActivateBAEntry(struct ieee80211_device *ieee, PBA_RECORD pBA, u16 Time)
20{
21 pBA->bValid = true;
22 if(Time != 0)
23 mod_timer(&pBA->Timer, jiffies + msecs_to_jiffies(Time));
24}
25
26
27
28
29
30
31static void DeActivateBAEntry(struct ieee80211_device *ieee, PBA_RECORD pBA)
32{
33 pBA->bValid = false;
34 del_timer_sync(&pBA->Timer);
35}
36
37
38
39
40
41
42
43static u8 TxTsDeleteBA(struct ieee80211_device *ieee, PTX_TS_RECORD pTxTs)
44{
45 PBA_RECORD pAdmittedBa = &pTxTs->TxAdmittedBARecord;
46 PBA_RECORD pPendingBa = &pTxTs->TxPendingBARecord;
47 u8 bSendDELBA = false;
48
49
50 if (pPendingBa->bValid) {
51 DeActivateBAEntry(ieee, pPendingBa);
52 bSendDELBA = true;
53 }
54
55
56 if (pAdmittedBa->bValid) {
57 DeActivateBAEntry(ieee, pAdmittedBa);
58 bSendDELBA = true;
59 }
60
61 return bSendDELBA;
62}
63
64
65
66
67
68
69
70
71static u8 RxTsDeleteBA(struct ieee80211_device *ieee, PRX_TS_RECORD pRxTs)
72{
73 PBA_RECORD pBa = &pRxTs->RxAdmittedBARecord;
74 u8 bSendDELBA = false;
75
76 if (pBa->bValid) {
77 DeActivateBAEntry(ieee, pBa);
78 bSendDELBA = true;
79 }
80
81 return bSendDELBA;
82}
83
84
85
86
87
88
89
90void ResetBaEntry(PBA_RECORD pBA)
91{
92 pBA->bValid = false;
93 pBA->BaParamSet.shortData = 0;
94 pBA->BaTimeoutValue = 0;
95 pBA->DialogToken = 0;
96 pBA->BaStartSeqCtrl.ShortData = 0;
97}
98
99
100
101
102
103
104
105
106
107
108static struct sk_buff *ieee80211_ADDBA(struct ieee80211_device *ieee, u8 *Dst, PBA_RECORD pBA, u16 StatusCode, u8 type)
109{
110 struct sk_buff *skb = NULL;
111 struct rtl_80211_hdr_3addr *BAReq = NULL;
112 u8 *tag = NULL;
113 u16 len = ieee->tx_headroom + 9;
114
115 IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), frame(%d) sentd to:%pM, ieee->dev:%p\n", __func__, type, Dst, ieee->dev);
116 if (pBA == NULL) {
117 IEEE80211_DEBUG(IEEE80211_DL_ERR, "pBA is NULL\n");
118 return NULL;
119 }
120 skb = dev_alloc_skb(len + sizeof( struct rtl_80211_hdr_3addr));
121 if (!skb) {
122 IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc skb for ADDBA_REQ\n");
123 return NULL;
124 }
125
126 memset(skb->data, 0, sizeof( struct rtl_80211_hdr_3addr));
127 skb_reserve(skb, ieee->tx_headroom);
128
129 BAReq = skb_put(skb, sizeof(struct rtl_80211_hdr_3addr));
130
131 memcpy(BAReq->addr1, Dst, ETH_ALEN);
132 memcpy(BAReq->addr2, ieee->dev->dev_addr, ETH_ALEN);
133
134 memcpy(BAReq->addr3, ieee->current_network.bssid, ETH_ALEN);
135
136 BAReq->frame_ctl = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT);
137
138
139 tag = skb_put(skb, 9);
140 *tag ++= ACT_CAT_BA;
141 *tag ++= type;
142
143 *tag ++= pBA->DialogToken;
144
145 if (ACT_ADDBARSP == type) {
146
147 netdev_info(ieee->dev, "=====>to send ADDBARSP\n");
148
149 put_unaligned_le16(StatusCode, tag);
150 tag += 2;
151 }
152
153
154 put_unaligned_le16(pBA->BaParamSet.shortData, tag);
155 tag += 2;
156
157
158 put_unaligned_le16(pBA->BaTimeoutValue, tag);
159 tag += 2;
160
161 if (ACT_ADDBAREQ == type) {
162
163 memcpy(tag, (u8 *)&(pBA->BaStartSeqCtrl), 2);
164 tag += 2;
165 }
166
167 IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len);
168 return skb;
169
170}
171
172
173
174
175
176
177
178
179
180
181
182static struct sk_buff *ieee80211_DELBA(
183 struct ieee80211_device *ieee,
184 u8 *dst,
185 PBA_RECORD pBA,
186 TR_SELECT TxRxSelect,
187 u16 ReasonCode
188 )
189{
190 DELBA_PARAM_SET DelbaParamSet;
191 struct sk_buff *skb = NULL;
192 struct rtl_80211_hdr_3addr *Delba = NULL;
193 u8 *tag = NULL;
194
195 u16 len = 6 + ieee->tx_headroom;
196
197 if (net_ratelimit())
198 IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA,
199 "========>%s(), ReasonCode(%d) sentd to:%pM\n",
200 __func__, ReasonCode, dst);
201
202 memset(&DelbaParamSet, 0, 2);
203
204 DelbaParamSet.field.Initiator = (TxRxSelect==TX_DIR)?1:0;
205 DelbaParamSet.field.TID = pBA->BaParamSet.field.TID;
206
207 skb = dev_alloc_skb(len + sizeof( struct rtl_80211_hdr_3addr));
208 if (!skb) {
209 IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc skb for ADDBA_REQ\n");
210 return NULL;
211 }
212
213 skb_reserve(skb, ieee->tx_headroom);
214
215 Delba = skb_put(skb, sizeof(struct rtl_80211_hdr_3addr));
216
217 memcpy(Delba->addr1, dst, ETH_ALEN);
218 memcpy(Delba->addr2, ieee->dev->dev_addr, ETH_ALEN);
219 memcpy(Delba->addr3, ieee->current_network.bssid, ETH_ALEN);
220 Delba->frame_ctl = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT);
221
222 tag = skb_put(skb, 6);
223
224 *tag ++= ACT_CAT_BA;
225 *tag ++= ACT_DELBA;
226
227
228
229 put_unaligned_le16(DelbaParamSet.shortData, tag);
230 tag += 2;
231
232
233 put_unaligned_le16(ReasonCode, tag);
234 tag += 2;
235
236 IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len);
237 if (net_ratelimit())
238 IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA,
239 "<=====%s()\n", __func__);
240 return skb;
241}
242
243
244
245
246
247
248
249
250static void ieee80211_send_ADDBAReq(struct ieee80211_device *ieee,
251 u8 *dst, PBA_RECORD pBA)
252{
253 struct sk_buff *skb;
254 skb = ieee80211_ADDBA(ieee, dst, pBA, 0, ACT_ADDBAREQ);
255
256 if (skb) {
257 softmac_mgmt_xmit(skb, ieee);
258
259
260
261 }
262 else {
263 IEEE80211_DEBUG(IEEE80211_DL_ERR, "alloc skb error in function %s()\n", __func__);
264 }
265}
266
267
268
269
270
271
272
273
274
275static void ieee80211_send_ADDBARsp(struct ieee80211_device *ieee, u8 *dst,
276 PBA_RECORD pBA, u16 StatusCode)
277{
278 struct sk_buff *skb;
279 skb = ieee80211_ADDBA(ieee, dst, pBA, StatusCode, ACT_ADDBARSP);
280 if (skb) {
281 softmac_mgmt_xmit(skb, ieee);
282
283 }
284 else {
285 IEEE80211_DEBUG(IEEE80211_DL_ERR, "alloc skb error in function %s()\n", __func__);
286 }
287
288 return;
289
290}
291
292
293
294
295
296
297
298
299
300
301static void ieee80211_send_DELBA(struct ieee80211_device *ieee, u8 *dst,
302 PBA_RECORD pBA, TR_SELECT TxRxSelect,
303 u16 ReasonCode)
304{
305 struct sk_buff *skb;
306 skb = ieee80211_DELBA(ieee, dst, pBA, TxRxSelect, ReasonCode);
307 if (skb) {
308 softmac_mgmt_xmit(skb, ieee);
309
310 }
311 else {
312 IEEE80211_DEBUG(IEEE80211_DL_ERR, "alloc skb error in function %s()\n", __func__);
313 }
314}
315
316
317
318
319
320
321
322int ieee80211_rx_ADDBAReq(struct ieee80211_device *ieee, struct sk_buff *skb)
323{
324 struct rtl_80211_hdr_3addr *req = NULL;
325 u16 rc = 0;
326 u8 *dst = NULL, *pDialogToken = NULL, *tag = NULL;
327 PBA_RECORD pBA = NULL;
328 PBA_PARAM_SET pBaParamSet = NULL;
329 u16 *pBaTimeoutVal = NULL;
330 PSEQUENCE_CONTROL pBaStartSeqCtrl = NULL;
331 PRX_TS_RECORD pTS = NULL;
332
333 if (skb->len < sizeof(struct rtl_80211_hdr_3addr) + 9) {
334 IEEE80211_DEBUG(IEEE80211_DL_ERR,
335 " Invalid skb len in BAREQ(%d / %zu)\n",
336 skb->len,
337 (sizeof(struct rtl_80211_hdr_3addr) + 9));
338 return -1;
339 }
340
341 IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len);
342
343 req = (struct rtl_80211_hdr_3addr *) skb->data;
344 tag = (u8 *)req;
345 dst = &req->addr2[0];
346 tag += sizeof(struct rtl_80211_hdr_3addr);
347 pDialogToken = tag + 2;
348 pBaParamSet = (PBA_PARAM_SET)(tag + 3);
349 pBaTimeoutVal = (u16 *)(tag + 5);
350 pBaStartSeqCtrl = (PSEQUENCE_CONTROL)(req + 7);
351
352 netdev_info(ieee->dev, "====================>rx ADDBAREQ from :%pM\n", dst);
353
354 if ((ieee->current_network.qos_data.active == 0) ||
355 (!ieee->pHTInfo->bCurrentHTSupport))
356
357 {
358 rc = ADDBA_STATUS_REFUSED;
359 IEEE80211_DEBUG(IEEE80211_DL_ERR, "Failed to reply on ADDBA_REQ as some capability is not ready(%d, %d)\n", ieee->current_network.qos_data.active, ieee->pHTInfo->bCurrentHTSupport);
360 goto OnADDBAReq_Fail;
361 }
362
363
364 if (!GetTs(
365 ieee,
366 (PTS_COMMON_INFO *)(&pTS),
367 dst,
368 (u8)(pBaParamSet->field.TID),
369 RX_DIR,
370 true) ) {
371 rc = ADDBA_STATUS_REFUSED;
372 IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS in %s()\n", __func__);
373 goto OnADDBAReq_Fail;
374 }
375 pBA = &pTS->RxAdmittedBARecord;
376
377
378
379
380 if (pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) {
381 rc = ADDBA_STATUS_INVALID_PARAM;
382 IEEE80211_DEBUG(IEEE80211_DL_ERR, "BA Policy is not correct in %s()\n", __func__);
383 goto OnADDBAReq_Fail;
384 }
385
386
387 DeActivateBAEntry(ieee, pBA);
388 pBA->DialogToken = *pDialogToken;
389 pBA->BaParamSet = *pBaParamSet;
390 pBA->BaTimeoutValue = *pBaTimeoutVal;
391 pBA->BaStartSeqCtrl = *pBaStartSeqCtrl;
392
393 if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev))
394 pBA->BaParamSet.field.BufferSize = 1;
395 else
396 pBA->BaParamSet.field.BufferSize = 32;
397 ActivateBAEntry(ieee, pBA, pBA->BaTimeoutValue);
398 ieee80211_send_ADDBARsp(ieee, dst, pBA, ADDBA_STATUS_SUCCESS);
399
400
401 return 0;
402
403OnADDBAReq_Fail:
404 {
405 BA_RECORD BA;
406 BA.BaParamSet = *pBaParamSet;
407 BA.BaTimeoutValue = *pBaTimeoutVal;
408 BA.DialogToken = *pDialogToken;
409 BA.BaParamSet.field.BAPolicy = BA_POLICY_IMMEDIATE;
410 ieee80211_send_ADDBARsp(ieee, dst, &BA, rc);
411 return 0;
412 }
413
414}
415
416
417
418
419
420
421
422int ieee80211_rx_ADDBARsp(struct ieee80211_device *ieee, struct sk_buff *skb)
423{
424 struct rtl_80211_hdr_3addr *rsp = NULL;
425 PBA_RECORD pPendingBA, pAdmittedBA;
426 PTX_TS_RECORD pTS = NULL;
427 u8 *dst = NULL, *pDialogToken = NULL, *tag = NULL;
428 u16 *pStatusCode = NULL, *pBaTimeoutVal = NULL;
429 PBA_PARAM_SET pBaParamSet = NULL;
430 u16 ReasonCode;
431
432 if (skb->len < sizeof(struct rtl_80211_hdr_3addr) + 9) {
433 IEEE80211_DEBUG(IEEE80211_DL_ERR,
434 " Invalid skb len in BARSP(%d / %zu)\n",
435 skb->len,
436 (sizeof(struct rtl_80211_hdr_3addr) + 9));
437 return -1;
438 }
439 rsp = (struct rtl_80211_hdr_3addr *)skb->data;
440 tag = (u8 *)rsp;
441 dst = &rsp->addr2[0];
442 tag += sizeof(struct rtl_80211_hdr_3addr);
443 pDialogToken = tag + 2;
444 pStatusCode = (u16 *)(tag + 3);
445 pBaParamSet = (PBA_PARAM_SET)(tag + 5);
446 pBaTimeoutVal = (u16 *)(tag + 7);
447
448
449
450 if (ieee->current_network.qos_data.active == 0 ||
451 !ieee->pHTInfo->bCurrentHTSupport ||
452 !ieee->pHTInfo->bCurrentAMPDUEnable) {
453 IEEE80211_DEBUG(IEEE80211_DL_ERR, "reject to ADDBA_RSP as some capability is not ready(%d, %d, %d)\n",ieee->current_network.qos_data.active, ieee->pHTInfo->bCurrentHTSupport, ieee->pHTInfo->bCurrentAMPDUEnable);
454 ReasonCode = DELBA_REASON_UNKNOWN_BA;
455 goto OnADDBARsp_Reject;
456 }
457
458
459
460
461
462
463 if (!GetTs(
464 ieee,
465 (PTS_COMMON_INFO *)(&pTS),
466 dst,
467 (u8)(pBaParamSet->field.TID),
468 TX_DIR,
469 false) ) {
470 IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS in %s()\n", __func__);
471 ReasonCode = DELBA_REASON_UNKNOWN_BA;
472 goto OnADDBARsp_Reject;
473 }
474
475 pTS->bAddBaReqInProgress = false;
476 pPendingBA = &pTS->TxPendingBARecord;
477 pAdmittedBA = &pTS->TxAdmittedBARecord;
478
479
480
481
482
483
484 if (pAdmittedBA->bValid) {
485
486 IEEE80211_DEBUG(IEEE80211_DL_BA, "OnADDBARsp(): Recv ADDBA Rsp. Drop because already admit it! \n");
487 return -1;
488 }
489 else if((!pPendingBA->bValid) ||(*pDialogToken != pPendingBA->DialogToken)) {
490 IEEE80211_DEBUG(IEEE80211_DL_ERR, "OnADDBARsp(): Recv ADDBA Rsp. BA invalid, DELBA! \n");
491 ReasonCode = DELBA_REASON_UNKNOWN_BA;
492 goto OnADDBARsp_Reject;
493 }
494 else {
495 IEEE80211_DEBUG(IEEE80211_DL_BA, "OnADDBARsp(): Recv ADDBA Rsp. BA is admitted! Status code:%X\n", *pStatusCode);
496 DeActivateBAEntry(ieee, pPendingBA);
497 }
498
499
500 if(*pStatusCode == ADDBA_STATUS_SUCCESS) {
501
502
503
504
505
506 if (pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) {
507
508 pTS->bAddBaReqDelayed = true;
509 DeActivateBAEntry(ieee, pAdmittedBA);
510 ReasonCode = DELBA_REASON_END_BA;
511 goto OnADDBARsp_Reject;
512 }
513
514
515
516
517
518 pAdmittedBA->DialogToken = *pDialogToken;
519 pAdmittedBA->BaTimeoutValue = *pBaTimeoutVal;
520 pAdmittedBA->BaStartSeqCtrl = pPendingBA->BaStartSeqCtrl;
521 pAdmittedBA->BaParamSet = *pBaParamSet;
522 DeActivateBAEntry(ieee, pAdmittedBA);
523 ActivateBAEntry(ieee, pAdmittedBA, *pBaTimeoutVal);
524 }
525 else {
526
527 pTS->bAddBaReqDelayed = true;
528 }
529
530
531 return 0;
532
533OnADDBARsp_Reject:
534 {
535 BA_RECORD BA;
536 BA.BaParamSet = *pBaParamSet;
537 ieee80211_send_DELBA(ieee, dst, &BA, TX_DIR, ReasonCode);
538 return 0;
539 }
540
541}
542
543
544
545
546
547
548
549int ieee80211_rx_DELBA(struct ieee80211_device *ieee, struct sk_buff *skb)
550{
551 struct rtl_80211_hdr_3addr *delba = NULL;
552 PDELBA_PARAM_SET pDelBaParamSet = NULL;
553 u8 *dst = NULL;
554
555 if (skb->len < sizeof(struct rtl_80211_hdr_3addr) + 6) {
556 IEEE80211_DEBUG(IEEE80211_DL_ERR,
557 " Invalid skb len in DELBA(%d / %zu)\n",
558 skb->len,
559 (sizeof(struct rtl_80211_hdr_3addr) + 6));
560 return -1;
561 }
562
563 if (ieee->current_network.qos_data.active == 0 ||
564 !ieee->pHTInfo->bCurrentHTSupport) {
565 IEEE80211_DEBUG(IEEE80211_DL_ERR, "received DELBA while QOS or HT is not supported(%d, %d)\n",ieee->current_network.qos_data.active, ieee->pHTInfo->bCurrentHTSupport);
566 return -1;
567 }
568
569 IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len);
570 delba = (struct rtl_80211_hdr_3addr *)skb->data;
571 dst = &delba->addr2[0];
572 pDelBaParamSet = (PDELBA_PARAM_SET)&delba->payload[2];
573
574 if(pDelBaParamSet->field.Initiator == 1) {
575 PRX_TS_RECORD pRxTs;
576
577 if (!GetTs(
578 ieee,
579 (PTS_COMMON_INFO *)&pRxTs,
580 dst,
581 (u8)pDelBaParamSet->field.TID,
582 RX_DIR,
583 false) ) {
584 IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS for RXTS in %s()\n", __func__);
585 return -1;
586 }
587
588 RxTsDeleteBA(ieee, pRxTs);
589 }
590 else {
591 PTX_TS_RECORD pTxTs;
592
593 if (!GetTs(
594 ieee,
595 (PTS_COMMON_INFO *)&pTxTs,
596 dst,
597 (u8)pDelBaParamSet->field.TID,
598 TX_DIR,
599 false) ) {
600 IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS for TXTS in %s()\n", __func__);
601 return -1;
602 }
603
604 pTxTs->bUsingBa = false;
605 pTxTs->bAddBaReqInProgress = false;
606 pTxTs->bAddBaReqDelayed = false;
607 del_timer_sync(&pTxTs->TsAddBaTimer);
608
609 TxTsDeleteBA(ieee, pTxTs);
610 }
611 return 0;
612}
613
614
615
616
617void
618TsInitAddBA(
619 struct ieee80211_device *ieee,
620 PTX_TS_RECORD pTS,
621 u8 Policy,
622 u8 bOverwritePending
623 )
624{
625 PBA_RECORD pBA = &pTS->TxPendingBARecord;
626
627 if (pBA->bValid && !bOverwritePending)
628 return;
629
630
631 DeActivateBAEntry(ieee, pBA);
632
633 pBA->DialogToken++;
634 pBA->BaParamSet.field.AMSDU_Support = 0;
635 pBA->BaParamSet.field.BAPolicy = Policy;
636 pBA->BaParamSet.field.TID = pTS->TsCommonInfo.TSpec.f.TSInfo.field.ucTSID;
637
638 pBA->BaParamSet.field.BufferSize = 32;
639 pBA->BaTimeoutValue = 0;
640 pBA->BaStartSeqCtrl.field.SeqNum = (pTS->TxCurSeq + 3) % 4096;
641
642 ActivateBAEntry(ieee, pBA, BA_SETUP_TIMEOUT);
643
644 ieee80211_send_ADDBAReq(ieee, pTS->TsCommonInfo.Addr, pBA);
645}
646
647void
648TsInitDelBA( struct ieee80211_device *ieee, PTS_COMMON_INFO pTsCommonInfo, TR_SELECT TxRxSelect)
649{
650
651 if(TxRxSelect == TX_DIR) {
652 PTX_TS_RECORD pTxTs = (PTX_TS_RECORD)pTsCommonInfo;
653
654 if(TxTsDeleteBA(ieee, pTxTs))
655 ieee80211_send_DELBA(
656 ieee,
657 pTsCommonInfo->Addr,
658 (pTxTs->TxAdmittedBARecord.bValid)?(&pTxTs->TxAdmittedBARecord):(&pTxTs->TxPendingBARecord),
659 TxRxSelect,
660 DELBA_REASON_END_BA);
661 }
662 else if(TxRxSelect == RX_DIR) {
663 PRX_TS_RECORD pRxTs = (PRX_TS_RECORD)pTsCommonInfo;
664 if(RxTsDeleteBA(ieee, pRxTs))
665 ieee80211_send_DELBA(
666 ieee,
667 pTsCommonInfo->Addr,
668 &pRxTs->RxAdmittedBARecord,
669 TxRxSelect,
670 DELBA_REASON_END_BA );
671 }
672}
673
674
675
676
677
678
679void BaSetupTimeOut(struct timer_list *t)
680{
681 PTX_TS_RECORD pTxTs = from_timer(pTxTs, t, TxPendingBARecord.Timer);
682
683 pTxTs->bAddBaReqInProgress = false;
684 pTxTs->bAddBaReqDelayed = true;
685 pTxTs->TxPendingBARecord.bValid = false;
686}
687
688void TxBaInactTimeout(struct timer_list *t)
689{
690 PTX_TS_RECORD pTxTs = from_timer(pTxTs, t, TxAdmittedBARecord.Timer);
691 struct ieee80211_device *ieee = container_of(pTxTs, struct ieee80211_device, TxTsRecord[pTxTs->num]);
692 TxTsDeleteBA(ieee, pTxTs);
693 ieee80211_send_DELBA(
694 ieee,
695 pTxTs->TsCommonInfo.Addr,
696 &pTxTs->TxAdmittedBARecord,
697 TX_DIR,
698 DELBA_REASON_TIMEOUT);
699}
700
701void RxBaInactTimeout(struct timer_list *t)
702{
703 PRX_TS_RECORD pRxTs = from_timer(pRxTs, t, RxAdmittedBARecord.Timer);
704 struct ieee80211_device *ieee = container_of(pRxTs, struct ieee80211_device, RxTsRecord[pRxTs->num]);
705
706 RxTsDeleteBA(ieee, pRxTs);
707 ieee80211_send_DELBA(
708 ieee,
709 pRxTs->TsCommonInfo.Addr,
710 &pRxTs->RxAdmittedBARecord,
711 RX_DIR,
712 DELBA_REASON_TIMEOUT);
713}
714