PageRenderTime 49ms CodeModel.GetById 21ms app.highlight 24ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c

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