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