1/****************************************************************************** 2 * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. 3 * 4 * This program is distributed in the hope that it will be useful, but WITHOUT 5 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 6 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 7 * more details. 8 * 9 * You should have received a copy of the GNU General Public License along with 10 * this program; if not, write to the Free Software Foundation, Inc., 11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA 12 * 13 * The full GNU General Public License is included in this distribution in the 14 * file called LICENSE. 15 * 16 * Contact Information: 17 * wlanfae <wlanfae@realtek.com> 18******************************************************************************/ 19#include <asm/byteorder.h> 20#include <asm/unaligned.h> 21#include "rtllib.h" 22#include "rtl819x_BA.h" 23 24static void ActivateBAEntry(struct rtllib_device *ieee, struct ba_record *pBA, 25 u16 Time) 26{ 27 pBA->bValid = true; 28 if (Time != 0) 29 mod_timer(&pBA->Timer, jiffies + msecs_to_jiffies(Time)); 30} 31 32static void DeActivateBAEntry(struct rtllib_device *ieee, struct ba_record *pBA) 33{ 34 pBA->bValid = false; 35 del_timer_sync(&pBA->Timer); 36} 37 38static u8 TxTsDeleteBA(struct rtllib_device *ieee, struct tx_ts_record *pTxTs) 39{ 40 struct ba_record *pAdmittedBa = &pTxTs->TxAdmittedBARecord; 41 struct ba_record *pPendingBa = &pTxTs->TxPendingBARecord; 42 u8 bSendDELBA = false; 43 44 if (pPendingBa->bValid) { 45 DeActivateBAEntry(ieee, pPendingBa); 46 bSendDELBA = true; 47 } 48 49 if (pAdmittedBa->bValid) { 50 DeActivateBAEntry(ieee, pAdmittedBa); 51 bSendDELBA = true; 52 } 53 return bSendDELBA; 54} 55 56static u8 RxTsDeleteBA(struct rtllib_device *ieee, struct rx_ts_record *pRxTs) 57{ 58 struct ba_record *pBa = &pRxTs->RxAdmittedBARecord; 59 u8 bSendDELBA = false; 60 61 if (pBa->bValid) { 62 DeActivateBAEntry(ieee, pBa); 63 bSendDELBA = true; 64 } 65 66 return bSendDELBA; 67} 68 69void ResetBaEntry(struct ba_record *pBA) 70{ 71 pBA->bValid = false; 72 pBA->BaParamSet.shortData = 0; 73 pBA->BaTimeoutValue = 0; 74 pBA->DialogToken = 0; 75 pBA->BaStartSeqCtrl.ShortData = 0; 76} 77static struct sk_buff *rtllib_ADDBA(struct rtllib_device *ieee, u8 *Dst, 78 struct ba_record *pBA, 79 u16 StatusCode, u8 type) 80{ 81 struct sk_buff *skb = NULL; 82 struct rtllib_hdr_3addr *BAReq = NULL; 83 u8 *tag = NULL; 84 u16 len = ieee->tx_headroom + 9; 85 86 RTLLIB_DEBUG(RTLLIB_DL_TRACE | RTLLIB_DL_BA, 87 "========>%s(), frame(%d) sentd to: %pM, ieee->dev:%p\n", 88 __func__, type, Dst, ieee->dev); 89 if (pBA == NULL) { 90 RTLLIB_DEBUG(RTLLIB_DL_ERR, "pBA is NULL\n"); 91 return NULL; 92 } 93 skb = dev_alloc_skb(len + sizeof(struct rtllib_hdr_3addr)); 94 if (skb == NULL) { 95 RTLLIB_DEBUG(RTLLIB_DL_ERR, "can't alloc skb for ADDBA_REQ\n"); 96 return NULL; 97 } 98 99 memset(skb->data, 0, sizeof(struct rtllib_hdr_3addr)); 100 101 skb_reserve(skb, ieee->tx_headroom); 102 103 BAReq = (struct rtllib_hdr_3addr *)skb_put(skb, 104 sizeof(struct rtllib_hdr_3addr)); 105 106 memcpy(BAReq->addr1, Dst, ETH_ALEN); 107 memcpy(BAReq->addr2, ieee->dev->dev_addr, ETH_ALEN); 108 109 memcpy(BAReq->addr3, ieee->current_network.bssid, ETH_ALEN); 110 BAReq->frame_ctl = cpu_to_le16(RTLLIB_STYPE_MANAGE_ACT); 111 112 tag = (u8 *)skb_put(skb, 9); 113 *tag++ = ACT_CAT_BA; 114 *tag++ = type; 115 *tag++ = pBA->DialogToken; 116 117 if (ACT_ADDBARSP == type) { 118 RT_TRACE(COMP_DBG, "====>to send ADDBARSP\n"); 119 120 put_unaligned_le16(StatusCode, tag); 121 tag += 2; 122 } 123 124 put_unaligned_le16(pBA->BaParamSet.shortData, tag); 125 tag += 2; 126 127 put_unaligned_le16(pBA->BaTimeoutValue, tag); 128 tag += 2; 129 130 if (ACT_ADDBAREQ == type) { 131 memcpy(tag, (u8 *)&(pBA->BaStartSeqCtrl), 2); 132 tag += 2; 133 } 134 135 RTLLIB_DEBUG_DATA(RTLLIB_DL_DATA|RTLLIB_DL_BA, skb->data, skb->len); 136 return skb; 137} 138 139static struct sk_buff *rtllib_DELBA(struct rtllib_device *ieee, u8 *dst, 140 struct ba_record *pBA, 141 enum tr_select TxRxSelect, u16 ReasonCode) 142{ 143 union delba_param_set DelbaParamSet; 144 struct sk_buff *skb = NULL; 145 struct rtllib_hdr_3addr *Delba = NULL; 146 u8 *tag = NULL; 147 u16 len = 6 + ieee->tx_headroom; 148 149 if (net_ratelimit()) 150 RTLLIB_DEBUG(RTLLIB_DL_TRACE | RTLLIB_DL_BA, 151 "========>%s(), ReasonCode(%d) sentd to: %pM\n", 152 __func__, ReasonCode, dst); 153 154 memset(&DelbaParamSet, 0, 2); 155 156 DelbaParamSet.field.Initiator = (TxRxSelect == TX_DIR) ? 1 : 0; 157 DelbaParamSet.field.TID = pBA->BaParamSet.field.TID; 158 159 skb = dev_alloc_skb(len + sizeof(struct rtllib_hdr_3addr)); 160 if (skb == NULL) { 161 RTLLIB_DEBUG(RTLLIB_DL_ERR, "can't alloc skb for ADDBA_REQ\n"); 162 return NULL; 163 } 164 165 skb_reserve(skb, ieee->tx_headroom); 166 167 Delba = (struct rtllib_hdr_3addr *) skb_put(skb, 168 sizeof(struct rtllib_hdr_3addr)); 169 170 memcpy(Delba->addr1, dst, ETH_ALEN); 171 memcpy(Delba->addr2, ieee->dev->dev_addr, ETH_ALEN); 172 memcpy(Delba->addr3, ieee->current_network.bssid, ETH_ALEN); 173 Delba->frame_ctl = cpu_to_le16(RTLLIB_STYPE_MANAGE_ACT); 174 175 tag = (u8 *)skb_put(skb, 6); 176 177 *tag++ = ACT_CAT_BA; 178 *tag++ = ACT_DELBA; 179 180 181 put_unaligned_le16(DelbaParamSet.shortData, tag); 182 tag += 2; 183 184 put_unaligned_le16(ReasonCode, tag); 185 tag += 2; 186 187 RTLLIB_DEBUG_DATA(RTLLIB_DL_DATA|RTLLIB_DL_BA, skb->data, skb->len); 188 if (net_ratelimit()) 189 RTLLIB_DEBUG(RTLLIB_DL_TRACE | RTLLIB_DL_BA, "<=====%s()\n", 190 __func__); 191 return skb; 192} 193 194static void rtllib_send_ADDBAReq(struct rtllib_device *ieee, u8 *dst, 195 struct ba_record *pBA) 196{ 197 struct sk_buff *skb = NULL; 198 199 skb = rtllib_ADDBA(ieee, dst, pBA, 0, ACT_ADDBAREQ); 200 201 if (skb) { 202 RT_TRACE(COMP_DBG, "====>to send ADDBAREQ!!!!!\n"); 203 softmac_mgmt_xmit(skb, ieee); 204 } else { 205 RTLLIB_DEBUG(RTLLIB_DL_ERR, 206 "alloc skb error in function %s()\n", __func__); 207 } 208} 209 210static void rtllib_send_ADDBARsp(struct rtllib_device *ieee, u8 *dst, 211 struct ba_record *pBA, u16 StatusCode) 212{ 213 struct sk_buff *skb = NULL; 214 215 skb = rtllib_ADDBA(ieee, dst, pBA, StatusCode, ACT_ADDBARSP); 216 if (skb) 217 softmac_mgmt_xmit(skb, ieee); 218 else 219 RTLLIB_DEBUG(RTLLIB_DL_ERR, 220 "alloc skb error in function %s()\n", __func__); 221} 222 223static void rtllib_send_DELBA(struct rtllib_device *ieee, u8 *dst, 224 struct ba_record *pBA, enum tr_select TxRxSelect, 225 u16 ReasonCode) 226{ 227 struct sk_buff *skb = NULL; 228 229 skb = rtllib_DELBA(ieee, dst, pBA, TxRxSelect, ReasonCode); 230 if (skb) 231 softmac_mgmt_xmit(skb, ieee); 232 else 233 RTLLIB_DEBUG(RTLLIB_DL_ERR, 234 "alloc skb error in function %s()\n", __func__); 235} 236 237int rtllib_rx_ADDBAReq(struct rtllib_device *ieee, struct sk_buff *skb) 238{ 239 struct rtllib_hdr_3addr *req = NULL; 240 u16 rc = 0; 241 u8 *dst = NULL, *pDialogToken = NULL, *tag = NULL; 242 struct ba_record *pBA = NULL; 243 union ba_param_set *pBaParamSet = NULL; 244 u16 *pBaTimeoutVal = NULL; 245 union sequence_control *pBaStartSeqCtrl = NULL; 246 struct rx_ts_record *pTS = NULL; 247 248 if (skb->len < sizeof(struct rtllib_hdr_3addr) + 9) { 249 RTLLIB_DEBUG(RTLLIB_DL_ERR, 250 " Invalid skb len in BAREQ(%d / %d)\n", 251 (int)skb->len, 252 (int)(sizeof(struct rtllib_hdr_3addr) + 9)); 253 return -1; 254 } 255 256 RTLLIB_DEBUG_DATA(RTLLIB_DL_DATA|RTLLIB_DL_BA, skb->data, skb->len); 257 258 req = (struct rtllib_hdr_3addr *) skb->data; 259 tag = (u8 *)req; 260 dst = (u8 *)(&req->addr2[0]); 261 tag += sizeof(struct rtllib_hdr_3addr); 262 pDialogToken = tag + 2; 263 pBaParamSet = (union ba_param_set *)(tag + 3); 264 pBaTimeoutVal = (u16 *)(tag + 5); 265 pBaStartSeqCtrl = (union sequence_control *)(req + 7); 266 267 RT_TRACE(COMP_DBG, "====>rx ADDBAREQ from : %pM\n", dst); 268 if (ieee->current_network.qos_data.active == 0 || 269 (ieee->pHTInfo->bCurrentHTSupport == false) || 270 (ieee->pHTInfo->IOTAction & HT_IOT_ACT_REJECT_ADDBA_REQ)) { 271 rc = ADDBA_STATUS_REFUSED; 272 RTLLIB_DEBUG(RTLLIB_DL_ERR, 273 "Failed to reply on ADDBA_REQ as some capability is not ready(%d, %d)\n", 274 ieee->current_network.qos_data.active, 275 ieee->pHTInfo->bCurrentHTSupport); 276 goto OnADDBAReq_Fail; 277 } 278 if (!GetTs(ieee, (struct ts_common_info **)(&pTS), dst, 279 (u8)(pBaParamSet->field.TID), RX_DIR, true)) { 280 rc = ADDBA_STATUS_REFUSED; 281 RTLLIB_DEBUG(RTLLIB_DL_ERR, "can't get TS in %s()\n", __func__); 282 goto OnADDBAReq_Fail; 283 } 284 pBA = &pTS->RxAdmittedBARecord; 285 286 if (pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) { 287 rc = ADDBA_STATUS_INVALID_PARAM; 288 RTLLIB_DEBUG(RTLLIB_DL_ERR, 289 "BA Policy is not correct in %s()\n", __func__); 290 goto OnADDBAReq_Fail; 291 } 292 293 rtllib_FlushRxTsPendingPkts(ieee, pTS); 294 295 DeActivateBAEntry(ieee, pBA); 296 pBA->DialogToken = *pDialogToken; 297 pBA->BaParamSet = *pBaParamSet; 298 pBA->BaTimeoutValue = *pBaTimeoutVal; 299 pBA->BaStartSeqCtrl = *pBaStartSeqCtrl; 300 301 if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev) || 302 (ieee->pHTInfo->IOTAction & HT_IOT_ACT_ALLOW_PEER_AGG_ONE_PKT)) 303 pBA->BaParamSet.field.BufferSize = 1; 304 else 305 pBA->BaParamSet.field.BufferSize = 32; 306 307 ActivateBAEntry(ieee, pBA, 0); 308 rtllib_send_ADDBARsp(ieee, dst, pBA, ADDBA_STATUS_SUCCESS); 309 310 return 0; 311 312OnADDBAReq_Fail: 313 { 314 struct ba_record BA; 315 316 BA.BaParamSet = *pBaParamSet; 317 BA.BaTimeoutValue = *pBaTimeoutVal; 318 BA.DialogToken = *pDialogToken; 319 BA.BaParamSet.field.BAPolicy = BA_POLICY_IMMEDIATE; 320 rtllib_send_ADDBARsp(ieee, dst, &BA, rc); 321 return 0; 322 } 323} 324 325int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb) 326{ 327 struct rtllib_hdr_3addr *rsp = NULL; 328 struct ba_record *pPendingBA, *pAdmittedBA; 329 struct tx_ts_record *pTS = NULL; 330 u8 *dst = NULL, *pDialogToken = NULL, *tag = NULL; 331 u16 *pStatusCode = NULL, *pBaTimeoutVal = NULL; 332 union ba_param_set *pBaParamSet = NULL; 333 u16 ReasonCode; 334 335 if (skb->len < sizeof(struct rtllib_hdr_3addr) + 9) { 336 RTLLIB_DEBUG(RTLLIB_DL_ERR, 337 "Invalid skb len in BARSP(%d / %d)\n", 338 (int)skb->len, 339 (int)(sizeof(struct rtllib_hdr_3addr) + 9)); 340 return -1; 341 } 342 rsp = (struct rtllib_hdr_3addr *)skb->data; 343 tag = (u8 *)rsp; 344 dst = (u8 *)(&rsp->addr2[0]); 345 tag += sizeof(struct rtllib_hdr_3addr); 346 pDialogToken = tag + 2; 347 pStatusCode = (u16 *)(tag + 3); 348 pBaParamSet = (union ba_param_set *)(tag + 5); 349 pBaTimeoutVal = (u16 *)(tag + 7); 350 351 RT_TRACE(COMP_DBG, "====>rx ADDBARSP from : %pM\n", dst); 352 if (ieee->current_network.qos_data.active == 0 || 353 ieee->pHTInfo->bCurrentHTSupport == false || 354 ieee->pHTInfo->bCurrentAMPDUEnable == false) { 355 RTLLIB_DEBUG(RTLLIB_DL_ERR, 356 "reject to ADDBA_RSP as some capability is not ready(%d, %d, %d)\n", 357 ieee->current_network.qos_data.active, 358 ieee->pHTInfo->bCurrentHTSupport, 359 ieee->pHTInfo->bCurrentAMPDUEnable); 360 ReasonCode = DELBA_REASON_UNKNOWN_BA; 361 goto OnADDBARsp_Reject; 362 } 363 364 365 if (!GetTs(ieee, (struct ts_common_info **)(&pTS), dst, 366 (u8)(pBaParamSet->field.TID), TX_DIR, false)) { 367 RTLLIB_DEBUG(RTLLIB_DL_ERR, "can't get TS in %s()\n", __func__); 368 ReasonCode = DELBA_REASON_UNKNOWN_BA; 369 goto OnADDBARsp_Reject; 370 } 371 372 pTS->bAddBaReqInProgress = false; 373 pPendingBA = &pTS->TxPendingBARecord; 374 pAdmittedBA = &pTS->TxAdmittedBARecord; 375 376 377 if (pAdmittedBA->bValid == true) { 378 RTLLIB_DEBUG(RTLLIB_DL_BA, 379 "OnADDBARsp(): Recv ADDBA Rsp. Drop because already admit it!\n"); 380 return -1; 381 } else if ((pPendingBA->bValid == false) || 382 (*pDialogToken != pPendingBA->DialogToken)) { 383 RTLLIB_DEBUG(RTLLIB_DL_ERR, 384 "OnADDBARsp(): Recv ADDBA Rsp. BA invalid, DELBA!\n"); 385 ReasonCode = DELBA_REASON_UNKNOWN_BA; 386 goto OnADDBARsp_Reject; 387 } else { 388 RTLLIB_DEBUG(RTLLIB_DL_BA, 389 "OnADDBARsp(): Recv ADDBA Rsp. BA is admitted! Status code:%X\n", 390 *pStatusCode); 391 DeActivateBAEntry(ieee, pPendingBA); 392 } 393 394 395 if (*pStatusCode == ADDBA_STATUS_SUCCESS) { 396 if (pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) { 397 pTS->bAddBaReqDelayed = true; 398 DeActivateBAEntry(ieee, pAdmittedBA); 399 ReasonCode = DELBA_REASON_END_BA; 400 goto OnADDBARsp_Reject; 401 } 402 403 404 pAdmittedBA->DialogToken = *pDialogToken; 405 pAdmittedBA->BaTimeoutValue = *pBaTimeoutVal; 406 pAdmittedBA->BaStartSeqCtrl = pPendingBA->BaStartSeqCtrl; 407 pAdmittedBA->BaParamSet = *pBaParamSet; 408 DeActivateBAEntry(ieee, pAdmittedBA); 409 ActivateBAEntry(ieee, pAdmittedBA, *pBaTimeoutVal); 410 } else { 411 pTS->bAddBaReqDelayed = true; 412 pTS->bDisable_AddBa = true; 413 ReasonCode = DELBA_REASON_END_BA; 414 goto OnADDBARsp_Reject; 415 } 416 417 return 0; 418 419OnADDBARsp_Reject: 420 { 421 struct ba_record BA; 422 423 BA.BaParamSet = *pBaParamSet; 424 rtllib_send_DELBA(ieee, dst, &BA, TX_DIR, ReasonCode); 425 return 0; 426 } 427} 428 429int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb) 430{ 431 struct rtllib_hdr_3addr *delba = NULL; 432 union delba_param_set *pDelBaParamSet = NULL; 433 u16 *pReasonCode = NULL; 434 u8 *dst = NULL; 435 436 if (skb->len < sizeof(struct rtllib_hdr_3addr) + 6) { 437 RTLLIB_DEBUG(RTLLIB_DL_ERR, 438 "Invalid skb len in DELBA(%d / %d)\n", 439 (int)skb->len, 440 (int)(sizeof(struct rtllib_hdr_3addr) + 6)); 441 return -1; 442 } 443 444 if (ieee->current_network.qos_data.active == 0 || 445 ieee->pHTInfo->bCurrentHTSupport == false) { 446 RTLLIB_DEBUG(RTLLIB_DL_ERR, 447 "received DELBA while QOS or HT is not supported(%d, %d)\n", 448 ieee->current_network. qos_data.active, 449 ieee->pHTInfo->bCurrentHTSupport); 450 return -1; 451 } 452 453 RTLLIB_DEBUG_DATA(RTLLIB_DL_DATA|RTLLIB_DL_BA, skb->data, skb->len); 454 delba = (struct rtllib_hdr_3addr *)skb->data; 455 dst = (u8 *)(&delba->addr2[0]); 456 delba += sizeof(struct rtllib_hdr_3addr); 457 pDelBaParamSet = (union delba_param_set *)(delba+2); 458 pReasonCode = (u16 *)(delba+4); 459 460 if (pDelBaParamSet->field.Initiator == 1) { 461 struct rx_ts_record *pRxTs; 462 463 if (!GetTs(ieee, (struct ts_common_info **)&pRxTs, dst, 464 (u8)pDelBaParamSet->field.TID, RX_DIR, false)) { 465 RTLLIB_DEBUG(RTLLIB_DL_ERR, 466 "can't get TS for RXTS in %s().dst: %pM TID:%d\n", 467 __func__, dst, 468 (u8)pDelBaParamSet->field.TID); 469 return -1; 470 } 471 472 RxTsDeleteBA(ieee, pRxTs); 473 } else { 474 struct tx_ts_record *pTxTs; 475 476 if (!GetTs(ieee, (struct ts_common_info **)&pTxTs, dst, 477 (u8)pDelBaParamSet->field.TID, TX_DIR, false)) { 478 RTLLIB_DEBUG(RTLLIB_DL_ERR, 479 "can't get TS for TXTS in %s()\n", 480 __func__); 481 return -1; 482 } 483 484 pTxTs->bUsingBa = false; 485 pTxTs->bAddBaReqInProgress = false; 486 pTxTs->bAddBaReqDelayed = false; 487 del_timer_sync(&pTxTs->TsAddBaTimer); 488 TxTsDeleteBA(ieee, pTxTs); 489 } 490 return 0; 491} 492 493void TsInitAddBA(struct rtllib_device *ieee, struct tx_ts_record *pTS, 494 u8 Policy, u8 bOverwritePending) 495{ 496 struct ba_record *pBA = &pTS->TxPendingBARecord; 497 498 if (pBA->bValid == true && bOverwritePending == false) 499 return; 500 501 DeActivateBAEntry(ieee, pBA); 502 503 pBA->DialogToken++; 504 pBA->BaParamSet.field.AMSDU_Support = 0; 505 pBA->BaParamSet.field.BAPolicy = Policy; 506 pBA->BaParamSet.field.TID = 507 pTS->TsCommonInfo.TSpec.f.TSInfo.field.ucTSID; 508 pBA->BaParamSet.field.BufferSize = 32; 509 pBA->BaTimeoutValue = 0; 510 pBA->BaStartSeqCtrl.field.SeqNum = (pTS->TxCurSeq + 3) % 4096; 511 512 ActivateBAEntry(ieee, pBA, BA_SETUP_TIMEOUT); 513 514 rtllib_send_ADDBAReq(ieee, pTS->TsCommonInfo.Addr, pBA); 515} 516 517void TsInitDelBA(struct rtllib_device *ieee, 518 struct ts_common_info *pTsCommonInfo, 519 enum tr_select TxRxSelect) 520{ 521 if (TxRxSelect == TX_DIR) { 522 struct tx_ts_record *pTxTs = 523 (struct tx_ts_record *)pTsCommonInfo; 524 525 if (TxTsDeleteBA(ieee, pTxTs)) 526 rtllib_send_DELBA(ieee, pTsCommonInfo->Addr, 527 (pTxTs->TxAdmittedBARecord.bValid) ? 528 (&pTxTs->TxAdmittedBARecord) : 529 (&pTxTs->TxPendingBARecord), 530 TxRxSelect, DELBA_REASON_END_BA); 531 } else if (TxRxSelect == RX_DIR) { 532 struct rx_ts_record *pRxTs = 533 (struct rx_ts_record *)pTsCommonInfo; 534 if (RxTsDeleteBA(ieee, pRxTs)) 535 rtllib_send_DELBA(ieee, pTsCommonInfo->Addr, 536 &pRxTs->RxAdmittedBARecord, 537 TxRxSelect, DELBA_REASON_END_BA); 538 } 539} 540 541void BaSetupTimeOut(unsigned long data) 542{ 543 struct tx_ts_record *pTxTs = (struct tx_ts_record *)data; 544 545 pTxTs->bAddBaReqInProgress = false; 546 pTxTs->bAddBaReqDelayed = true; 547 pTxTs->TxPendingBARecord.bValid = false; 548} 549 550void TxBaInactTimeout(unsigned long data) 551{ 552 struct tx_ts_record *pTxTs = (struct tx_ts_record *)data; 553 struct rtllib_device *ieee = container_of(pTxTs, struct rtllib_device, 554 TxTsRecord[pTxTs->num]); 555 TxTsDeleteBA(ieee, pTxTs); 556 rtllib_send_DELBA(ieee, pTxTs->TsCommonInfo.Addr, 557 &pTxTs->TxAdmittedBARecord, TX_DIR, 558 DELBA_REASON_TIMEOUT); 559} 560 561void RxBaInactTimeout(unsigned long data) 562{ 563 struct rx_ts_record *pRxTs = (struct rx_ts_record *)data; 564 struct rtllib_device *ieee = container_of(pRxTs, struct rtllib_device, 565 RxTsRecord[pRxTs->num]); 566 567 RxTsDeleteBA(ieee, pRxTs); 568 rtllib_send_DELBA(ieee, pRxTs->TsCommonInfo.Addr, 569 &pRxTs->RxAdmittedBARecord, RX_DIR, 570 DELBA_REASON_TIMEOUT); 571} 572