• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/staging/rtl8192su/ieee80211/
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 "ieee80211.h"
20#include "rtl819x_BA.h"
21
22/********************************************************************************************************************
23 *function:  Activate BA entry. And if Time is nozero, start timer.
24 *   input:  PBA_RECORD 		pBA  //BA entry to be enabled
25 *   	     u16 			Time //indicate time delay.
26 *  output:  none
27********************************************************************************************************************/
28void ActivateBAEntry(struct ieee80211_device* ieee, PBA_RECORD pBA, u16 Time)
29{
30	pBA->bValid = true;
31	if(Time != 0)
32		mod_timer(&pBA->Timer, jiffies + MSECS(Time));
33}
34
35/********************************************************************************************************************
36 *function:  deactivate BA entry, including its timer.
37 *   input:  PBA_RECORD 		pBA  //BA entry to be disabled
38 *  output:  none
39********************************************************************************************************************/
40void DeActivateBAEntry( struct ieee80211_device* ieee, PBA_RECORD pBA)
41{
42	pBA->bValid = false;
43	del_timer_sync(&pBA->Timer);
44}
45u8 TxTsDeleteBA( struct ieee80211_device* ieee, PTX_TS_RECORD	pTxTs)
46{
47	PBA_RECORD		pAdmittedBa = &pTxTs->TxAdmittedBARecord;  //These two BA entries must exist in TS structure
48	PBA_RECORD		pPendingBa = &pTxTs->TxPendingBARecord;
49	u8			bSendDELBA = false;
50
51	// Delete pending BA
52	if(pPendingBa->bValid)
53	{
54		DeActivateBAEntry(ieee, pPendingBa);
55		bSendDELBA = true;
56	}
57
58	// Delete admitted BA
59	if(pAdmittedBa->bValid)
60	{
61		DeActivateBAEntry(ieee, pAdmittedBa);
62		bSendDELBA = true;
63	}
64
65	return bSendDELBA;
66}
67
68u8 RxTsDeleteBA( struct ieee80211_device* ieee, PRX_TS_RECORD	pRxTs)
69{
70	PBA_RECORD		pBa = &pRxTs->RxAdmittedBARecord;
71	u8			bSendDELBA = false;
72
73	if(pBa->bValid)
74	{
75		DeActivateBAEntry(ieee, pBa);
76		bSendDELBA = true;
77	}
78
79	return bSendDELBA;
80}
81
82/********************************************************************************************************************
83 *function: reset BA entry
84 *   input:
85 *   	     PBA_RECORD		pBA //entry to be reset
86 *  output:  none
87********************************************************************************************************************/
88void ResetBaEntry( PBA_RECORD pBA)
89{
90	pBA->bValid			= false;
91	pBA->BaParamSet.shortData	= 0;
92	pBA->BaTimeoutValue		= 0;
93	pBA->DialogToken		= 0;
94	pBA->BaStartSeqCtrl.ShortData	= 0;
95}
96//These functions need porting here or not?
97/*******************************************************************************************************************************
98 *function:  construct ADDBAREQ and ADDBARSP frame here together.
99 *   input:  u8* 		Dst 	//ADDBA frame's destination
100 *   	     PBA_RECORD 	pBA	//BA_RECORD entry which stores the necessary information for BA.
101 *   	     u16 		StatusCode  //status code in RSP and I will use it to indicate whether it's RSP or REQ(will I?)
102 *   	     u8			type	//indicate whether it's RSP(ACT_ADDBARSP) ow REQ(ACT_ADDBAREQ)
103 *  output:  none
104 *  return:  sk_buff* 		skb     //return constructed skb to xmit
105*******************************************************************************************************************************/
106static struct sk_buff* ieee80211_ADDBA(struct ieee80211_device* ieee, u8* Dst, PBA_RECORD pBA, u16 StatusCode, u8 type)
107{
108	struct sk_buff *skb = NULL;
109	 struct ieee80211_hdr_3addr* BAReq = NULL;
110	u8* tag = NULL;
111	u16 tmp = 0;
112	u16 len = ieee->tx_headroom + 9;
113	IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), frame(%d) sentd to:%pM, ieee->dev:%p\n", __FUNCTION__, type, Dst, ieee->dev);
114	if (pBA == NULL||ieee == NULL)
115	{
116		IEEE80211_DEBUG(IEEE80211_DL_ERR, "pBA(%p) is NULL or ieee(%p) is NULL\n", pBA, ieee);
117		return NULL;
118	}
119	skb = dev_alloc_skb(len + sizeof( struct ieee80211_hdr_3addr));
120	if (skb == NULL)
121	{
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 ieee80211_hdr_3addr));  	//I wonder whether it's necessary. Apparently kernel will not do it when alloc a skb.
127	skb_reserve(skb, ieee->tx_headroom);
128
129	BAReq = ( struct ieee80211_hdr_3addr *) skb_put(skb,sizeof( struct ieee80211_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_control = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame
137
138	tag = (u8*)skb_put(skb, 9);
139	*tag ++= ACT_CAT_BA;
140	*tag ++= type;
141	// Dialog Token
142	*tag ++= pBA->DialogToken;
143
144	if (ACT_ADDBARSP == type)
145	{
146		// Status Code
147		printk("=====>to send ADDBARSP\n");
148		tmp = cpu_to_le16(StatusCode);
149		memcpy(tag, (u8*)&tmp, 2);
150		tag += 2;
151	}
152	// BA Parameter Set
153	tmp = cpu_to_le16(pBA->BaParamSet.shortData);
154	memcpy(tag, (u8*)&tmp, 2);
155	tag += 2;
156	// BA Timeout Value
157	tmp = cpu_to_le16(pBA->BaTimeoutValue);
158	memcpy(tag, (u8*)&tmp, 2);
159	tag += 2;
160
161	if (ACT_ADDBAREQ == type)
162	{
163	// BA Start SeqCtrl
164		memcpy(tag,(u8*)&(pBA->BaStartSeqCtrl), 2);
165		tag += 2;
166	}
167
168	IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len);
169	return skb;
170}
171
172/********************************************************************************************************************
173 *function:  construct DELBA frame
174 *   input:  u8* 		dst 	//DELBA frame's destination
175 *   	     PBA_RECORD 	pBA	//BA_RECORD entry which stores the necessary information for BA
176 *   	     TR_SELECT	        TxRxSelect  //TX RX direction
177 *   	     u16 		ReasonCode  //status code.
178 *  output:  none
179 *  return:  sk_buff* 		skb     //return constructed skb to xmit
180********************************************************************************************************************/
181static struct sk_buff* ieee80211_DELBA(
182	struct ieee80211_device* ieee,
183	u8*		         dst,
184	PBA_RECORD		 pBA,
185	TR_SELECT		 TxRxSelect,
186	u16			 ReasonCode
187	)
188{
189	DELBA_PARAM_SET	DelbaParamSet;
190	struct sk_buff *skb = NULL;
191	 struct ieee80211_hdr_3addr* Delba = NULL;
192	u8* tag = NULL;
193	u16 tmp = 0;
194	u16 len = 6 + ieee->tx_headroom;
195
196	if (net_ratelimit())
197	IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), ReasonCode(%d) sentd to:%pM\n", __FUNCTION__, ReasonCode, dst);
198
199	memset(&DelbaParamSet, 0, 2);
200
201	DelbaParamSet.field.Initiator	= (TxRxSelect==TX_DIR)?1:0;
202	DelbaParamSet.field.TID	= pBA->BaParamSet.field.TID;
203
204	skb = dev_alloc_skb(len + sizeof( struct ieee80211_hdr_3addr));
205	if (skb == NULL)
206	{
207		IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc skb for ADDBA_REQ\n");
208		return NULL;
209	}
210	skb_reserve(skb, ieee->tx_headroom);
211
212	Delba = ( struct ieee80211_hdr_3addr *) skb_put(skb,sizeof( struct ieee80211_hdr_3addr));
213
214	memcpy(Delba->addr1, dst, ETH_ALEN);
215	memcpy(Delba->addr2, ieee->dev->dev_addr, ETH_ALEN);
216	memcpy(Delba->addr3, ieee->current_network.bssid, ETH_ALEN);
217	Delba->frame_control = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame
218
219	tag = (u8*)skb_put(skb, 6);
220
221	*tag ++= ACT_CAT_BA;
222	*tag ++= ACT_DELBA;
223
224	// DELBA Parameter Set
225	tmp = cpu_to_le16(DelbaParamSet.shortData);
226	memcpy(tag, (u8*)&tmp, 2);
227	tag += 2;
228	// Reason Code
229	tmp = cpu_to_le16(ReasonCode);
230	memcpy(tag, (u8*)&tmp, 2);
231	tag += 2;
232
233	IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len);
234	if (net_ratelimit())
235	IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "<=====%s()\n", __FUNCTION__);
236	return skb;
237}
238
239/********************************************************************************************************************
240 *function: send ADDBAReq frame out
241 *   input:  u8* 		dst 	//ADDBAReq frame's destination
242 *   	     PBA_RECORD 	pBA	//BA_RECORD entry which stores the necessary information for BA
243 *  output:  none
244 *  notice: If any possible, please hide pBA in ieee. And temporarily use Manage Queue as softmac_mgmt_xmit() usually does
245********************************************************************************************************************/
246void ieee80211_send_ADDBAReq(struct ieee80211_device* ieee, u8*	dst, PBA_RECORD	pBA)
247{
248	struct sk_buff *skb = NULL;
249	skb = ieee80211_ADDBA(ieee, dst, pBA, 0, ACT_ADDBAREQ); //construct ACT_ADDBAREQ frames so set statuscode zero.
250
251	if (skb)
252	{
253		softmac_mgmt_xmit(skb, ieee);
254	}
255	else
256	{
257		IEEE80211_DEBUG(IEEE80211_DL_ERR, "alloc skb error in function %s()\n", __FUNCTION__);
258	}
259	return;
260}
261
262/********************************************************************************************************************
263 *function: send ADDBARSP frame out
264 *   input:  u8* 		dst 	//DELBA frame's destination
265 *   	     PBA_RECORD 	pBA	//BA_RECORD entry which stores the necessary information for BA
266 *   	     u16		StatusCode //RSP StatusCode
267 *  output:  none
268 *  notice: If any possible, please hide pBA in ieee. And temporarily use Manage Queue as softmac_mgmt_xmit() usually does
269********************************************************************************************************************/
270void ieee80211_send_ADDBARsp(struct ieee80211_device* ieee, u8* dst, PBA_RECORD pBA, u16 StatusCode)
271{
272	struct sk_buff *skb = NULL;
273	skb = ieee80211_ADDBA(ieee, dst, pBA, StatusCode, ACT_ADDBARSP); //construct ACT_ADDBARSP frames
274	if (skb)
275	{
276		softmac_mgmt_xmit(skb, ieee);
277	}
278	else
279	{
280		IEEE80211_DEBUG(IEEE80211_DL_ERR, "alloc skb error in function %s()\n", __FUNCTION__);
281	}
282
283	return;
284
285}
286/********************************************************************************************************************
287 *function: send ADDBARSP frame out
288 *   input:  u8* 		dst 	//DELBA frame's destination
289 *   	     PBA_RECORD 	pBA	//BA_RECORD entry which stores the necessary information for BA
290 *   	     TR_SELECT          TxRxSelect //TX or RX
291 *   	     u16		ReasonCode //DEL ReasonCode
292 *  output:  none
293 *  notice: If any possible, please hide pBA in ieee. And temporarily use Manage Queue as softmac_mgmt_xmit() usually does
294********************************************************************************************************************/
295
296void ieee80211_send_DELBA(struct ieee80211_device* ieee, u8* dst, PBA_RECORD pBA, TR_SELECT TxRxSelect, u16 ReasonCode)
297{
298	struct sk_buff *skb = NULL;
299	skb = ieee80211_DELBA(ieee, dst, pBA, TxRxSelect, ReasonCode); //construct ACT_ADDBARSP frames
300	if (skb)
301	{
302		softmac_mgmt_xmit(skb, ieee);
303	}
304	else
305	{
306		IEEE80211_DEBUG(IEEE80211_DL_ERR, "alloc skb error in function %s()\n", __FUNCTION__);
307	}
308	return ;
309}
310
311/********************************************************************************************************************
312 *function: RX ADDBAReq
313 *   input:  struct sk_buff *   skb	//incoming ADDBAReq skb.
314 *  return:  0(pass), other(fail)
315 *  notice:  As this function need support of QOS, I comment some code out. And when qos is ready, this code need to be support.
316********************************************************************************************************************/
317int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb)
318{
319	 struct ieee80211_hdr_3addr* req = NULL;
320	u16 rc = 0;
321	u8 * dst = NULL, *pDialogToken = NULL, *tag = NULL;
322	PBA_RECORD pBA = NULL;
323	PBA_PARAM_SET	pBaParamSet = NULL;
324	u16* pBaTimeoutVal = NULL;
325	PSEQUENCE_CONTROL pBaStartSeqCtrl = NULL;
326	PRX_TS_RECORD	pTS = NULL;
327
328	if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9)
329	{
330		IEEE80211_DEBUG(IEEE80211_DL_ERR,
331				" Invalid skb len in BAREQ(%d / %zd)\n",
332				skb->len,
333				sizeof(struct ieee80211_hdr_3addr) + 9);
334		return -1;
335	}
336
337	IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len);
338
339	req = ( struct ieee80211_hdr_3addr*) skb->data;
340	tag = (u8*)req;
341	dst = (u8*)(&req->addr2[0]);
342	tag += sizeof( struct ieee80211_hdr_3addr);
343	pDialogToken = tag + 2;  //category+action
344	pBaParamSet = (PBA_PARAM_SET)(tag + 3);   //+DialogToken
345	pBaTimeoutVal = (u16*)(tag + 5);
346	pBaStartSeqCtrl = (PSEQUENCE_CONTROL)(req + 7);
347
348	printk("====================>rx ADDBAREQ from :%pM\n", dst);
349//some other capability is not ready now.
350	if(	(ieee->current_network.qos_data.active == 0) ||
351		(ieee->pHTInfo->bCurrentHTSupport == false) ||
352		(ieee->pHTInfo->IOTAction & HT_IOT_ACT_REJECT_ADDBA_REQ))
353	{
354		rc = ADDBA_STATUS_REFUSED;
355		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);
356		goto OnADDBAReq_Fail;
357	}
358	// Search for related traffic stream.
359	// If there is no matched TS, reject the ADDBA request.
360	if(	!GetTs(
361			ieee,
362			(PTS_COMMON_INFO*)(&pTS),
363			dst,
364			(u8)(pBaParamSet->field.TID),
365			RX_DIR,
366			true)	)
367	{
368		rc = ADDBA_STATUS_REFUSED;
369		IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS in %s()\n", __FUNCTION__);
370		goto OnADDBAReq_Fail;
371	}
372	pBA = &pTS->RxAdmittedBARecord;
373	// To Determine the ADDBA Req content
374	// We can do much more check here, including BufferSize, AMSDU_Support, Policy, StartSeqCtrl...
375	// I want to check StartSeqCtrl to make sure when we start aggregation!!!
376	//
377	if(pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED)
378	{
379		rc = ADDBA_STATUS_INVALID_PARAM;
380		IEEE80211_DEBUG(IEEE80211_DL_ERR, "BA Policy is not correct in %s()\n", __FUNCTION__);
381		goto OnADDBAReq_Fail;
382	}
383		// Admit the ADDBA Request
384	DeActivateBAEntry(ieee, pBA);
385	pBA->DialogToken = *pDialogToken;
386	pBA->BaParamSet = *pBaParamSet;
387	pBA->BaTimeoutValue = *pBaTimeoutVal;
388	pBA->BaStartSeqCtrl = *pBaStartSeqCtrl;
389	//for half N mode we only aggregate 1 frame
390	if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)||
391	(ieee->pHTInfo->IOTAction & HT_IOT_ACT_ALLOW_PEER_AGG_ONE_PKT))
392	pBA->BaParamSet.field.BufferSize = 1;
393	else
394	pBA->BaParamSet.field.BufferSize = 32;
395	ActivateBAEntry(ieee, pBA, 0);
396	ieee80211_send_ADDBARsp(ieee, dst, pBA, ADDBA_STATUS_SUCCESS);
397
398	return 0;
399
400OnADDBAReq_Fail:
401	{
402		BA_RECORD	BA;
403		BA.BaParamSet = *pBaParamSet;
404		BA.BaTimeoutValue = *pBaTimeoutVal;
405		BA.DialogToken = *pDialogToken;
406		BA.BaParamSet.field.BAPolicy = BA_POLICY_IMMEDIATE;
407		ieee80211_send_ADDBARsp(ieee, dst, &BA, rc);
408		return 0; //we send RSP out.
409	}
410
411}
412
413/********************************************************************************************************************
414 *function: RX ADDBARSP
415 *   input:  struct sk_buff *   skb	//incoming ADDBAReq skb.
416 *  return:  0(pass), other(fail)
417 *  notice:  As this function need support of QOS, I comment some code out. And when qos is ready, this code need to be support.
418********************************************************************************************************************/
419int ieee80211_rx_ADDBARsp( struct ieee80211_device* ieee, struct sk_buff *skb)
420{
421	 struct ieee80211_hdr_3addr* rsp = NULL;
422	PBA_RECORD		pPendingBA, pAdmittedBA;
423	PTX_TS_RECORD		pTS = NULL;
424	u8* dst = NULL, *pDialogToken = NULL, *tag = NULL;
425	u16* pStatusCode = NULL, *pBaTimeoutVal = NULL;
426	PBA_PARAM_SET		pBaParamSet = NULL;
427	u16			ReasonCode;
428
429	if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9)
430	{
431		IEEE80211_DEBUG(IEEE80211_DL_ERR,
432				" Invalid skb len in BARSP(%d / %zd)\n",
433				skb->len,
434				sizeof(struct ieee80211_hdr_3addr) + 9);
435		return -1;
436	}
437	rsp = ( struct ieee80211_hdr_3addr*)skb->data;
438	tag = (u8*)rsp;
439	dst = (u8*)(&rsp->addr2[0]);
440	tag += sizeof( struct ieee80211_hdr_3addr);
441	pDialogToken = tag + 2;
442	pStatusCode = (u16*)(tag + 3);
443	pBaParamSet = (PBA_PARAM_SET)(tag + 5);
444	pBaTimeoutVal = (u16*)(tag + 7);
445
446	// Check the capability
447	// Since we can always receive A-MPDU, we just check if it is under HT mode.
448	if(     ieee->current_network.qos_data.active == 0  ||
449		ieee->pHTInfo->bCurrentHTSupport == false ||
450		ieee->pHTInfo->bCurrentAMPDUEnable == false )
451	{
452		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);
453		ReasonCode = DELBA_REASON_UNKNOWN_BA;
454		goto OnADDBARsp_Reject;
455	}
456
457
458	//
459	// Search for related TS.
460	// If there is no TS found, we wil reject ADDBA Rsp by sending DELBA frame.
461	//
462	if (!GetTs(
463			ieee,
464			(PTS_COMMON_INFO*)(&pTS),
465			dst,
466			(u8)(pBaParamSet->field.TID),
467			TX_DIR,
468			false)	)
469	{
470		IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS in %s()\n", __FUNCTION__);
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	// Check if related BA is waiting for setup.
482	// If not, reject by sending DELBA frame.
483	//
484	if((pAdmittedBA->bValid==true))
485	{
486		// Since BA is already setup, we ignore all other ADDBA Response.
487		IEEE80211_DEBUG(IEEE80211_DL_BA, "OnADDBARsp(): Recv ADDBA Rsp. Drop because already admit it! \n");
488		return -1;
489	}
490	else if((pPendingBA->bValid == false) ||(*pDialogToken != pPendingBA->DialogToken))
491	{
492		IEEE80211_DEBUG(IEEE80211_DL_ERR,  "OnADDBARsp(): Recv ADDBA Rsp. BA invalid, DELBA! \n");
493		ReasonCode = DELBA_REASON_UNKNOWN_BA;
494		goto OnADDBARsp_Reject;
495	}
496	else
497	{
498		IEEE80211_DEBUG(IEEE80211_DL_BA, "OnADDBARsp(): Recv ADDBA Rsp. BA is admitted! Status code:%X\n", *pStatusCode);
499		DeActivateBAEntry(ieee, pPendingBA);
500	}
501
502
503	if(*pStatusCode == ADDBA_STATUS_SUCCESS)
504	{
505		//
506		// Determine ADDBA Rsp content here.
507		// We can compare the value of BA parameter set that Peer returned and Self sent.
508		// If it is OK, then admitted. Or we can send DELBA to cancel BA mechanism.
509		//
510		if(pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED)
511		{
512			// Since this is a kind of ADDBA failed, we delay next ADDBA process.
513			pTS->bAddBaReqDelayed = true;
514			DeActivateBAEntry(ieee, pAdmittedBA);
515			ReasonCode = DELBA_REASON_END_BA;
516			goto OnADDBARsp_Reject;
517		}
518
519
520		//
521		// Admitted condition
522		//
523		pAdmittedBA->DialogToken = *pDialogToken;
524		pAdmittedBA->BaTimeoutValue = *pBaTimeoutVal;
525		pAdmittedBA->BaStartSeqCtrl = pPendingBA->BaStartSeqCtrl;
526		pAdmittedBA->BaParamSet = *pBaParamSet;
527		DeActivateBAEntry(ieee, pAdmittedBA);
528		ActivateBAEntry(ieee, pAdmittedBA, *pBaTimeoutVal);
529	} else {
530		pTS->bAddBaReqDelayed = true;
531		pTS->bDisable_AddBa = true;
532		ReasonCode = DELBA_REASON_END_BA;
533		goto OnADDBARsp_Reject;
534	}
535
536	// End of procedure
537	return 0;
538
539OnADDBARsp_Reject:
540	{
541		BA_RECORD	BA;
542		BA.BaParamSet = *pBaParamSet;
543		ieee80211_send_DELBA(ieee, dst, &BA, TX_DIR, ReasonCode);
544		return 0;
545	}
546
547}
548
549/********************************************************************************************************************
550 *function: RX DELBA
551 *   input:  struct sk_buff *   skb	//incoming ADDBAReq skb.
552 *  return:  0(pass), other(fail)
553 *  notice:  As this function need support of QOS, I comment some code out. And when qos is ready, this code need to be support.
554********************************************************************************************************************/
555int ieee80211_rx_DELBA(struct ieee80211_device* ieee,struct sk_buff *skb)
556{
557	 struct ieee80211_hdr_3addr* delba = NULL;
558	PDELBA_PARAM_SET	pDelBaParamSet = NULL;
559	u16*			pReasonCode = NULL;
560	u8*			dst = NULL;
561
562	if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 6)
563	{
564		IEEE80211_DEBUG(IEEE80211_DL_ERR,
565				" Invalid skb len in DELBA(%d / %zd)\n",
566				skb->len,
567				sizeof(struct ieee80211_hdr_3addr) + 6);
568		return -1;
569	}
570
571	if(ieee->current_network.qos_data.active == 0 ||
572		ieee->pHTInfo->bCurrentHTSupport == false )
573	{
574		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);
575		return -1;
576	}
577
578	IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len);
579	delba = ( struct ieee80211_hdr_3addr*)skb->data;
580	dst = (u8*)(&delba->addr2[0]);
581	delba += sizeof( struct ieee80211_hdr_3addr);
582	pDelBaParamSet = (PDELBA_PARAM_SET)(delba+2);
583	pReasonCode = (u16*)(delba+4);
584
585	if(pDelBaParamSet->field.Initiator == 1)
586	{
587		PRX_TS_RECORD 	pRxTs;
588
589		if( !GetTs(
590				ieee,
591				(PTS_COMMON_INFO*)&pRxTs,
592				dst,
593				(u8)pDelBaParamSet->field.TID,
594				RX_DIR,
595				false)	)
596		{
597			IEEE80211_DEBUG(IEEE80211_DL_ERR,  "can't get TS for RXTS in %s()\n", __FUNCTION__);
598			return -1;
599		}
600
601		RxTsDeleteBA(ieee, pRxTs);
602	}
603	else
604	{
605		PTX_TS_RECORD	pTxTs;
606
607		if(!GetTs(
608			ieee,
609			(PTS_COMMON_INFO*)&pTxTs,
610			dst,
611			(u8)pDelBaParamSet->field.TID,
612			TX_DIR,
613			false)	)
614		{
615			IEEE80211_DEBUG(IEEE80211_DL_ERR,  "can't get TS for TXTS in %s()\n", __FUNCTION__);
616			return -1;
617		}
618
619		pTxTs->bUsingBa = false;
620		pTxTs->bAddBaReqInProgress = false;
621		pTxTs->bAddBaReqDelayed = false;
622		del_timer_sync(&pTxTs->TsAddBaTimer);
623		TxTsDeleteBA(ieee, pTxTs);
624	}
625	return 0;
626}
627
628//
629// ADDBA initiate. This can only be called by TX side.
630//
631void
632TsInitAddBA(
633	struct ieee80211_device* ieee,
634	PTX_TS_RECORD	pTS,
635	u8		Policy,
636	u8		bOverwritePending
637	)
638{
639	PBA_RECORD			pBA = &pTS->TxPendingBARecord;
640
641	if(pBA->bValid==true && bOverwritePending==false)
642		return;
643
644	// Set parameters to "Pending" variable set
645	DeActivateBAEntry(ieee, pBA);
646
647	pBA->DialogToken++;						// DialogToken: Only keep the latest dialog token
648	pBA->BaParamSet.field.AMSDU_Support = 0;	// Do not support A-MSDU with A-MPDU now!!
649	pBA->BaParamSet.field.BAPolicy = Policy;	// Policy: Delayed or Immediate
650	pBA->BaParamSet.field.TID = pTS->TsCommonInfo.TSpec.f.TSInfo.field.ucTSID;	// TID
651	// BufferSize: This need to be set according to A-MPDU vector
652	pBA->BaParamSet.field.BufferSize = 32;		// BufferSize: This need to be set according to A-MPDU vector
653	pBA->BaTimeoutValue = 0;					// Timeout value: Set 0 to disable Timer
654	pBA->BaStartSeqCtrl.field.SeqNum = (pTS->TxCurSeq + 3) % 4096; 	// Block Ack will start after 3 packets later.
655
656	ActivateBAEntry(ieee, pBA, BA_SETUP_TIMEOUT);
657
658	ieee80211_send_ADDBAReq(ieee, pTS->TsCommonInfo.Addr, pBA);
659}
660
661void
662TsInitDelBA( struct ieee80211_device* ieee, PTS_COMMON_INFO pTsCommonInfo, TR_SELECT TxRxSelect)
663{
664
665	if(TxRxSelect == TX_DIR)
666	{
667		PTX_TS_RECORD	pTxTs = (PTX_TS_RECORD)pTsCommonInfo;
668
669		if(TxTsDeleteBA(ieee, pTxTs))
670			ieee80211_send_DELBA(
671				ieee,
672				pTsCommonInfo->Addr,
673				(pTxTs->TxAdmittedBARecord.bValid)?(&pTxTs->TxAdmittedBARecord):(&pTxTs->TxPendingBARecord),
674				TxRxSelect,
675				DELBA_REASON_END_BA);
676	}
677	else if(TxRxSelect == RX_DIR)
678	{
679		PRX_TS_RECORD	pRxTs = (PRX_TS_RECORD)pTsCommonInfo;
680		if(RxTsDeleteBA(ieee, pRxTs))
681			ieee80211_send_DELBA(
682				ieee,
683				pTsCommonInfo->Addr,
684				&pRxTs->RxAdmittedBARecord,
685				TxRxSelect,
686				DELBA_REASON_END_BA	);
687	}
688}
689/********************************************************************************************************************
690 *function:  BA setup timer
691 *   input:  unsigned long	 data		//acturally we send TX_TS_RECORD or RX_TS_RECORD to these timer
692 *  return:  NULL
693 *  notice:
694********************************************************************************************************************/
695void BaSetupTimeOut(unsigned long data)
696{
697	PTX_TS_RECORD	pTxTs = (PTX_TS_RECORD)data;
698
699	pTxTs->bAddBaReqInProgress = false;
700	pTxTs->bAddBaReqDelayed = true;
701	pTxTs->TxPendingBARecord.bValid = false;
702}
703
704void TxBaInactTimeout(unsigned long data)
705{
706	PTX_TS_RECORD	pTxTs = (PTX_TS_RECORD)data;
707	struct ieee80211_device *ieee = container_of(pTxTs, struct ieee80211_device, TxTsRecord[pTxTs->num]);
708	TxTsDeleteBA(ieee, pTxTs);
709	ieee80211_send_DELBA(
710		ieee,
711		pTxTs->TsCommonInfo.Addr,
712		&pTxTs->TxAdmittedBARecord,
713		TX_DIR,
714		DELBA_REASON_TIMEOUT);
715}
716
717void RxBaInactTimeout(unsigned long data)
718{
719	PRX_TS_RECORD	pRxTs = (PRX_TS_RECORD)data;
720	struct ieee80211_device *ieee = container_of(pRxTs, struct ieee80211_device, RxTsRecord[pRxTs->num]);
721
722	RxTsDeleteBA(ieee, pRxTs);
723	ieee80211_send_DELBA(
724		ieee,
725		pRxTs->TsCommonInfo.Addr,
726		&pRxTs->RxAdmittedBARecord,
727		RX_DIR,
728		DELBA_REASON_TIMEOUT);
729	return ;
730}
731