1 /******************************************************************************
2 * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
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
9 * The full GNU General Public License is included in this distribution in the
10 * file called LICENSE.
12 * Contact Information:
14 ******************************************************************************/
15 #include <asm/byteorder.h>
16 #include <asm/unaligned.h>
17 #include <linux/etherdevice.h>
19 #include "rtl819x_BA.h"
21 static void ActivateBAEntry(struct rtllib_device *ieee, struct ba_record *pBA,
26 mod_timer(&pBA->Timer, jiffies + msecs_to_jiffies(Time));
29 static void DeActivateBAEntry(struct rtllib_device *ieee, struct ba_record *pBA)
32 del_timer_sync(&pBA->Timer);
35 static u8 TxTsDeleteBA(struct rtllib_device *ieee, struct tx_ts_record *pTxTs)
37 struct ba_record *pAdmittedBa = &pTxTs->TxAdmittedBARecord;
38 struct ba_record *pPendingBa = &pTxTs->TxPendingBARecord;
39 u8 bSendDELBA = false;
41 if (pPendingBa->bValid) {
42 DeActivateBAEntry(ieee, pPendingBa);
46 if (pAdmittedBa->bValid) {
47 DeActivateBAEntry(ieee, pAdmittedBa);
53 static u8 RxTsDeleteBA(struct rtllib_device *ieee, struct rx_ts_record *pRxTs)
55 struct ba_record *pBa = &pRxTs->RxAdmittedBARecord;
56 u8 bSendDELBA = false;
59 DeActivateBAEntry(ieee, pBa);
66 void ResetBaEntry(struct ba_record *pBA)
69 pBA->BaParamSet.shortData = 0;
70 pBA->BaTimeoutValue = 0;
72 pBA->BaStartSeqCtrl.ShortData = 0;
74 static struct sk_buff *rtllib_ADDBA(struct rtllib_device *ieee, u8 *Dst,
75 struct ba_record *pBA,
76 u16 StatusCode, u8 type)
78 struct sk_buff *skb = NULL;
79 struct rtllib_hdr_3addr *BAReq = NULL;
81 u16 len = ieee->tx_headroom + 9;
83 netdev_dbg(ieee->dev, "%s(): frame(%d) sentd to: %pM, ieee->dev:%p\n",
84 __func__, type, Dst, ieee->dev);
87 netdev_warn(ieee->dev, "pBA is NULL\n");
90 skb = dev_alloc_skb(len + sizeof(struct rtllib_hdr_3addr));
94 memset(skb->data, 0, sizeof(struct rtllib_hdr_3addr));
96 skb_reserve(skb, ieee->tx_headroom);
98 BAReq = skb_put(skb, sizeof(struct rtllib_hdr_3addr));
100 ether_addr_copy(BAReq->addr1, Dst);
101 ether_addr_copy(BAReq->addr2, ieee->dev->dev_addr);
103 ether_addr_copy(BAReq->addr3, ieee->current_network.bssid);
104 BAReq->frame_ctl = cpu_to_le16(RTLLIB_STYPE_MANAGE_ACT);
106 tag = skb_put(skb, 9);
109 *tag++ = pBA->DialogToken;
111 if (type == ACT_ADDBARSP) {
112 RT_TRACE(COMP_DBG, "====>to send ADDBARSP\n");
114 put_unaligned_le16(StatusCode, tag);
118 put_unaligned_le16(pBA->BaParamSet.shortData, tag);
121 put_unaligned_le16(pBA->BaTimeoutValue, tag);
124 if (type == ACT_ADDBAREQ) {
125 memcpy(tag, (u8 *)&(pBA->BaStartSeqCtrl), 2);
130 print_hex_dump_bytes("rtllib_ADDBA(): ", DUMP_PREFIX_NONE, skb->data,
136 static struct sk_buff *rtllib_DELBA(struct rtllib_device *ieee, u8 *dst,
137 struct ba_record *pBA,
138 enum tr_select TxRxSelect, u16 ReasonCode)
140 union delba_param_set DelbaParamSet;
141 struct sk_buff *skb = NULL;
142 struct rtllib_hdr_3addr *Delba = NULL;
144 u16 len = 6 + ieee->tx_headroom;
147 netdev_dbg(ieee->dev, "%s(): ReasonCode(%d) sentd to: %pM\n",
148 __func__, ReasonCode, dst);
150 memset(&DelbaParamSet, 0, 2);
152 DelbaParamSet.field.Initiator = (TxRxSelect == TX_DIR) ? 1 : 0;
153 DelbaParamSet.field.TID = pBA->BaParamSet.field.TID;
155 skb = dev_alloc_skb(len + sizeof(struct rtllib_hdr_3addr));
159 skb_reserve(skb, ieee->tx_headroom);
161 Delba = skb_put(skb, sizeof(struct rtllib_hdr_3addr));
163 ether_addr_copy(Delba->addr1, dst);
164 ether_addr_copy(Delba->addr2, ieee->dev->dev_addr);
165 ether_addr_copy(Delba->addr3, ieee->current_network.bssid);
166 Delba->frame_ctl = cpu_to_le16(RTLLIB_STYPE_MANAGE_ACT);
168 tag = skb_put(skb, 6);
174 put_unaligned_le16(DelbaParamSet.shortData, tag);
177 put_unaligned_le16(ReasonCode, tag);
181 print_hex_dump_bytes("rtllib_DELBA(): ", DUMP_PREFIX_NONE, skb->data,
187 static void rtllib_send_ADDBAReq(struct rtllib_device *ieee, u8 *dst,
188 struct ba_record *pBA)
192 skb = rtllib_ADDBA(ieee, dst, pBA, 0, ACT_ADDBAREQ);
195 RT_TRACE(COMP_DBG, "====>to send ADDBAREQ!!!!!\n");
196 softmac_mgmt_xmit(skb, ieee);
198 netdev_dbg(ieee->dev, "Failed to generate ADDBAReq packet.\n");
202 static void rtllib_send_ADDBARsp(struct rtllib_device *ieee, u8 *dst,
203 struct ba_record *pBA, u16 StatusCode)
207 skb = rtllib_ADDBA(ieee, dst, pBA, StatusCode, ACT_ADDBARSP);
209 softmac_mgmt_xmit(skb, ieee);
211 netdev_dbg(ieee->dev, "Failed to generate ADDBARsp packet.\n");
214 static void rtllib_send_DELBA(struct rtllib_device *ieee, u8 *dst,
215 struct ba_record *pBA, enum tr_select TxRxSelect,
220 skb = rtllib_DELBA(ieee, dst, pBA, TxRxSelect, ReasonCode);
222 softmac_mgmt_xmit(skb, ieee);
224 netdev_dbg(ieee->dev, "Failed to generate DELBA packet.\n");
227 int rtllib_rx_ADDBAReq(struct rtllib_device *ieee, struct sk_buff *skb)
229 struct rtllib_hdr_3addr *req = NULL;
231 u8 *dst = NULL, *pDialogToken = NULL, *tag = NULL;
232 struct ba_record *pBA = NULL;
233 union ba_param_set *pBaParamSet = NULL;
234 u16 *pBaTimeoutVal = NULL;
235 union sequence_control *pBaStartSeqCtrl = NULL;
236 struct rx_ts_record *pTS = NULL;
238 if (skb->len < sizeof(struct rtllib_hdr_3addr) + 9) {
239 netdev_warn(ieee->dev, "Invalid skb len in BAREQ(%d / %d)\n",
241 (int)(sizeof(struct rtllib_hdr_3addr) + 9));
246 print_hex_dump_bytes("rtllib_rx_ADDBAReq(): ", DUMP_PREFIX_NONE,
247 skb->data, skb->len);
250 req = (struct rtllib_hdr_3addr *) skb->data;
252 dst = (u8 *)(&req->addr2[0]);
253 tag += sizeof(struct rtllib_hdr_3addr);
254 pDialogToken = tag + 2;
255 pBaParamSet = (union ba_param_set *)(tag + 3);
256 pBaTimeoutVal = (u16 *)(tag + 5);
257 pBaStartSeqCtrl = (union sequence_control *)(req + 7);
259 RT_TRACE(COMP_DBG, "====>rx ADDBAREQ from : %pM\n", dst);
260 if (!ieee->current_network.qos_data.active ||
261 !ieee->pHTInfo->bCurrentHTSupport ||
262 (ieee->pHTInfo->IOTAction & HT_IOT_ACT_REJECT_ADDBA_REQ)) {
263 rc = ADDBA_STATUS_REFUSED;
264 netdev_warn(ieee->dev,
265 "Failed to reply on ADDBA_REQ as some capability is not ready(%d, %d)\n",
266 ieee->current_network.qos_data.active,
267 ieee->pHTInfo->bCurrentHTSupport);
268 goto OnADDBAReq_Fail;
270 if (!GetTs(ieee, (struct ts_common_info **)(&pTS), dst,
271 (u8)(pBaParamSet->field.TID), RX_DIR, true)) {
272 rc = ADDBA_STATUS_REFUSED;
273 netdev_warn(ieee->dev, "%s(): can't get TS\n", __func__);
274 goto OnADDBAReq_Fail;
276 pBA = &pTS->RxAdmittedBARecord;
278 if (pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) {
279 rc = ADDBA_STATUS_INVALID_PARAM;
280 netdev_warn(ieee->dev, "%s(): BA Policy is not correct\n",
282 goto OnADDBAReq_Fail;
285 rtllib_FlushRxTsPendingPkts(ieee, pTS);
287 DeActivateBAEntry(ieee, pBA);
288 pBA->DialogToken = *pDialogToken;
289 pBA->BaParamSet = *pBaParamSet;
290 pBA->BaTimeoutValue = *pBaTimeoutVal;
291 pBA->BaStartSeqCtrl = *pBaStartSeqCtrl;
293 if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev) ||
294 (ieee->pHTInfo->IOTAction & HT_IOT_ACT_ALLOW_PEER_AGG_ONE_PKT))
295 pBA->BaParamSet.field.BufferSize = 1;
297 pBA->BaParamSet.field.BufferSize = 32;
299 ActivateBAEntry(ieee, pBA, 0);
300 rtllib_send_ADDBARsp(ieee, dst, pBA, ADDBA_STATUS_SUCCESS);
308 BA.BaParamSet = *pBaParamSet;
309 BA.BaTimeoutValue = *pBaTimeoutVal;
310 BA.DialogToken = *pDialogToken;
311 BA.BaParamSet.field.BAPolicy = BA_POLICY_IMMEDIATE;
312 rtllib_send_ADDBARsp(ieee, dst, &BA, rc);
317 int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb)
319 struct rtllib_hdr_3addr *rsp = NULL;
320 struct ba_record *pPendingBA, *pAdmittedBA;
321 struct tx_ts_record *pTS = NULL;
322 u8 *dst = NULL, *pDialogToken = NULL, *tag = NULL;
323 u16 *pStatusCode = NULL, *pBaTimeoutVal = NULL;
324 union ba_param_set *pBaParamSet = NULL;
327 if (skb->len < sizeof(struct rtllib_hdr_3addr) + 9) {
328 netdev_warn(ieee->dev, "Invalid skb len in BARSP(%d / %d)\n",
330 (int)(sizeof(struct rtllib_hdr_3addr) + 9));
333 rsp = (struct rtllib_hdr_3addr *)skb->data;
335 dst = (u8 *)(&rsp->addr2[0]);
336 tag += sizeof(struct rtllib_hdr_3addr);
337 pDialogToken = tag + 2;
338 pStatusCode = (u16 *)(tag + 3);
339 pBaParamSet = (union ba_param_set *)(tag + 5);
340 pBaTimeoutVal = (u16 *)(tag + 7);
342 RT_TRACE(COMP_DBG, "====>rx ADDBARSP from : %pM\n", dst);
343 if (!ieee->current_network.qos_data.active ||
344 !ieee->pHTInfo->bCurrentHTSupport ||
345 !ieee->pHTInfo->bCurrentAMPDUEnable) {
346 netdev_warn(ieee->dev,
347 "reject to ADDBA_RSP as some capability is not ready(%d, %d, %d)\n",
348 ieee->current_network.qos_data.active,
349 ieee->pHTInfo->bCurrentHTSupport,
350 ieee->pHTInfo->bCurrentAMPDUEnable);
351 ReasonCode = DELBA_REASON_UNKNOWN_BA;
352 goto OnADDBARsp_Reject;
356 if (!GetTs(ieee, (struct ts_common_info **)(&pTS), dst,
357 (u8)(pBaParamSet->field.TID), TX_DIR, false)) {
358 netdev_warn(ieee->dev, "%s(): can't get TS\n", __func__);
359 ReasonCode = DELBA_REASON_UNKNOWN_BA;
360 goto OnADDBARsp_Reject;
363 pTS->bAddBaReqInProgress = false;
364 pPendingBA = &pTS->TxPendingBARecord;
365 pAdmittedBA = &pTS->TxAdmittedBARecord;
368 if (pAdmittedBA->bValid) {
369 netdev_dbg(ieee->dev, "%s(): ADDBA response already admitted\n",
372 } else if (!pPendingBA->bValid ||
373 (*pDialogToken != pPendingBA->DialogToken)) {
374 netdev_warn(ieee->dev,
375 "%s(): ADDBA Rsp. BA invalid, DELBA!\n",
377 ReasonCode = DELBA_REASON_UNKNOWN_BA;
378 goto OnADDBARsp_Reject;
380 netdev_dbg(ieee->dev,
381 "%s(): Recv ADDBA Rsp. BA is admitted! Status code:%X\n",
382 __func__, *pStatusCode);
383 DeActivateBAEntry(ieee, pPendingBA);
387 if (*pStatusCode == ADDBA_STATUS_SUCCESS) {
388 if (pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) {
389 pTS->bAddBaReqDelayed = true;
390 DeActivateBAEntry(ieee, pAdmittedBA);
391 ReasonCode = DELBA_REASON_END_BA;
392 goto OnADDBARsp_Reject;
396 pAdmittedBA->DialogToken = *pDialogToken;
397 pAdmittedBA->BaTimeoutValue = *pBaTimeoutVal;
398 pAdmittedBA->BaStartSeqCtrl = pPendingBA->BaStartSeqCtrl;
399 pAdmittedBA->BaParamSet = *pBaParamSet;
400 DeActivateBAEntry(ieee, pAdmittedBA);
401 ActivateBAEntry(ieee, pAdmittedBA, *pBaTimeoutVal);
403 pTS->bAddBaReqDelayed = true;
404 pTS->bDisable_AddBa = true;
405 ReasonCode = DELBA_REASON_END_BA;
406 goto OnADDBARsp_Reject;
415 BA.BaParamSet = *pBaParamSet;
416 rtllib_send_DELBA(ieee, dst, &BA, TX_DIR, ReasonCode);
421 int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb)
423 struct rtllib_hdr_3addr *delba = NULL;
424 union delba_param_set *pDelBaParamSet = NULL;
427 if (skb->len < sizeof(struct rtllib_hdr_3addr) + 6) {
428 netdev_warn(ieee->dev, "Invalid skb len in DELBA(%d / %d)\n",
430 (int)(sizeof(struct rtllib_hdr_3addr) + 6));
434 if (!ieee->current_network.qos_data.active ||
435 !ieee->pHTInfo->bCurrentHTSupport) {
436 netdev_warn(ieee->dev,
437 "received DELBA while QOS or HT is not supported(%d, %d)\n",
438 ieee->current_network. qos_data.active,
439 ieee->pHTInfo->bCurrentHTSupport);
444 print_hex_dump_bytes("rtllib_rx_DELBA(): ", DUMP_PREFIX_NONE, skb->data,
447 delba = (struct rtllib_hdr_3addr *)skb->data;
448 dst = (u8 *)(&delba->addr2[0]);
449 pDelBaParamSet = (union delba_param_set *)&delba->payload[2];
451 if (pDelBaParamSet->field.Initiator == 1) {
452 struct rx_ts_record *pRxTs;
454 if (!GetTs(ieee, (struct ts_common_info **)&pRxTs, dst,
455 (u8)pDelBaParamSet->field.TID, RX_DIR, false)) {
456 netdev_warn(ieee->dev,
457 "%s(): can't get TS for RXTS. dst:%pM TID:%d\n",
459 (u8)pDelBaParamSet->field.TID);
463 RxTsDeleteBA(ieee, pRxTs);
465 struct tx_ts_record *pTxTs;
467 if (!GetTs(ieee, (struct ts_common_info **)&pTxTs, dst,
468 (u8)pDelBaParamSet->field.TID, TX_DIR, false)) {
469 netdev_warn(ieee->dev, "%s(): can't get TS for TXTS\n",
474 pTxTs->bUsingBa = false;
475 pTxTs->bAddBaReqInProgress = false;
476 pTxTs->bAddBaReqDelayed = false;
477 del_timer_sync(&pTxTs->TsAddBaTimer);
478 TxTsDeleteBA(ieee, pTxTs);
483 void TsInitAddBA(struct rtllib_device *ieee, struct tx_ts_record *pTS,
484 u8 Policy, u8 bOverwritePending)
486 struct ba_record *pBA = &pTS->TxPendingBARecord;
488 if (pBA->bValid && !bOverwritePending)
491 DeActivateBAEntry(ieee, pBA);
494 pBA->BaParamSet.field.AMSDU_Support = 0;
495 pBA->BaParamSet.field.BAPolicy = Policy;
496 pBA->BaParamSet.field.TID =
497 pTS->TsCommonInfo.TSpec.f.TSInfo.field.ucTSID;
498 pBA->BaParamSet.field.BufferSize = 32;
499 pBA->BaTimeoutValue = 0;
500 pBA->BaStartSeqCtrl.field.SeqNum = (pTS->TxCurSeq + 3) % 4096;
502 ActivateBAEntry(ieee, pBA, BA_SETUP_TIMEOUT);
504 rtllib_send_ADDBAReq(ieee, pTS->TsCommonInfo.Addr, pBA);
507 void TsInitDelBA(struct rtllib_device *ieee,
508 struct ts_common_info *pTsCommonInfo,
509 enum tr_select TxRxSelect)
511 if (TxRxSelect == TX_DIR) {
512 struct tx_ts_record *pTxTs =
513 (struct tx_ts_record *)pTsCommonInfo;
515 if (TxTsDeleteBA(ieee, pTxTs))
516 rtllib_send_DELBA(ieee, pTsCommonInfo->Addr,
517 (pTxTs->TxAdmittedBARecord.bValid) ?
518 (&pTxTs->TxAdmittedBARecord) :
519 (&pTxTs->TxPendingBARecord),
520 TxRxSelect, DELBA_REASON_END_BA);
521 } else if (TxRxSelect == RX_DIR) {
522 struct rx_ts_record *pRxTs =
523 (struct rx_ts_record *)pTsCommonInfo;
524 if (RxTsDeleteBA(ieee, pRxTs))
525 rtllib_send_DELBA(ieee, pTsCommonInfo->Addr,
526 &pRxTs->RxAdmittedBARecord,
527 TxRxSelect, DELBA_REASON_END_BA);
531 void BaSetupTimeOut(struct timer_list *t)
533 struct tx_ts_record *pTxTs = from_timer(pTxTs, t,
534 TxPendingBARecord.Timer);
536 pTxTs->bAddBaReqInProgress = false;
537 pTxTs->bAddBaReqDelayed = true;
538 pTxTs->TxPendingBARecord.bValid = false;
541 void TxBaInactTimeout(struct timer_list *t)
543 struct tx_ts_record *pTxTs = from_timer(pTxTs, t,
544 TxAdmittedBARecord.Timer);
545 struct rtllib_device *ieee = container_of(pTxTs, struct rtllib_device,
546 TxTsRecord[pTxTs->num]);
547 TxTsDeleteBA(ieee, pTxTs);
548 rtllib_send_DELBA(ieee, pTxTs->TsCommonInfo.Addr,
549 &pTxTs->TxAdmittedBARecord, TX_DIR,
550 DELBA_REASON_TIMEOUT);
553 void RxBaInactTimeout(struct timer_list *t)
555 struct rx_ts_record *pRxTs = from_timer(pRxTs, t,
556 RxAdmittedBARecord.Timer);
557 struct rtllib_device *ieee = container_of(pRxTs, struct rtllib_device,
558 RxTsRecord[pRxTs->num]);
560 RxTsDeleteBA(ieee, pRxTs);
561 rtllib_send_DELBA(ieee, pRxTs->TsCommonInfo.Addr,
562 &pRxTs->RxAdmittedBARecord, RX_DIR,
563 DELBA_REASON_TIMEOUT);