Commit | Line | Data |
---|---|---|
8fc8598e JC |
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 | ||
8fc8598e JC |
177 | |
178 | /******************************************************************************************************************** | |
179 | *function: construct DELBA frame | |
180 | * input: u8* dst //DELBA frame's destination | |
181 | * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA | |
182 | * TR_SELECT TxRxSelect //TX RX direction | |
183 | * u16 ReasonCode //status code. | |
184 | * output: none | |
185 | * return: sk_buff* skb //return constructed skb to xmit | |
186 | ********************************************************************************************************************/ | |
187 | static struct sk_buff* ieee80211_DELBA( | |
188 | struct ieee80211_device* ieee, | |
189 | u8* dst, | |
190 | PBA_RECORD pBA, | |
191 | TR_SELECT TxRxSelect, | |
192 | u16 ReasonCode | |
193 | ) | |
194 | { | |
195 | DELBA_PARAM_SET DelbaParamSet; | |
196 | struct sk_buff *skb = NULL; | |
197 | struct ieee80211_hdr_3addr* Delba = NULL; | |
198 | u8* tag = NULL; | |
199 | u16 tmp = 0; | |
200 | //len = head len + DELBA Parameter Set(2) + Reason Code(2) | |
201 | u16 len = 6 + ieee->tx_headroom; | |
202 | ||
203 | if (net_ratelimit()) | |
204 | IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), ReasonCode(%d) sentd to:"MAC_FMT"\n", __FUNCTION__, ReasonCode, MAC_ARG(dst)); | |
205 | ||
206 | memset(&DelbaParamSet, 0, 2); | |
207 | ||
208 | DelbaParamSet.field.Initiator = (TxRxSelect==TX_DIR)?1:0; | |
209 | DelbaParamSet.field.TID = pBA->BaParamSet.field.TID; | |
210 | ||
211 | skb = dev_alloc_skb(len + sizeof( struct ieee80211_hdr_3addr)); //need to add something others? FIXME | |
212 | if (skb == NULL) | |
213 | { | |
214 | IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc skb for ADDBA_REQ\n"); | |
215 | return NULL; | |
216 | } | |
217 | // memset(skb->data, 0, len+sizeof( struct ieee80211_hdr_3addr)); | |
218 | skb_reserve(skb, ieee->tx_headroom); | |
219 | ||
220 | Delba = ( struct ieee80211_hdr_3addr *) skb_put(skb,sizeof( struct ieee80211_hdr_3addr)); | |
221 | ||
222 | memcpy(Delba->addr1, dst, ETH_ALEN); | |
223 | memcpy(Delba->addr2, ieee->dev->dev_addr, ETH_ALEN); | |
224 | memcpy(Delba->addr3, ieee->current_network.bssid, ETH_ALEN); | |
225 | Delba->frame_ctl = cpu_to_le16(IEEE80211_STYPE_MANAGE_ACT); //action frame | |
226 | ||
227 | tag = (u8*)skb_put(skb, 6); | |
228 | ||
229 | *tag ++= ACT_CAT_BA; | |
230 | *tag ++= ACT_DELBA; | |
231 | ||
232 | // DELBA Parameter Set | |
233 | tmp = cpu_to_le16(DelbaParamSet.shortData); | |
234 | memcpy(tag, (u8*)&tmp, 2); | |
235 | tag += 2; | |
236 | // Reason Code | |
237 | tmp = cpu_to_le16(ReasonCode); | |
238 | memcpy(tag, (u8*)&tmp, 2); | |
239 | tag += 2; | |
240 | ||
241 | IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); | |
242 | if (net_ratelimit()) | |
243 | IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "<=====%s()\n", __FUNCTION__); | |
244 | return skb; | |
245 | } | |
246 | ||
247 | /******************************************************************************************************************** | |
248 | *function: send ADDBAReq frame out | |
249 | * input: u8* dst //ADDBAReq frame's destination | |
250 | * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA | |
251 | * output: none | |
252 | * notice: If any possible, please hide pBA in ieee. And temporarily use Manage Queue as softmac_mgmt_xmit() usually does | |
253 | ********************************************************************************************************************/ | |
254 | void ieee80211_send_ADDBAReq(struct ieee80211_device* ieee, u8* dst, PBA_RECORD pBA) | |
255 | { | |
256 | struct sk_buff *skb = NULL; | |
257 | skb = ieee80211_ADDBA(ieee, dst, pBA, 0, ACT_ADDBAREQ); //construct ACT_ADDBAREQ frames so set statuscode zero. | |
258 | ||
259 | if (skb) | |
260 | { | |
261 | softmac_mgmt_xmit(skb, ieee); | |
262 | //add statistic needed here. | |
263 | //and skb will be freed in softmac_mgmt_xmit(), so omit all dev_kfree_skb_any() outside softmac_mgmt_xmit() | |
264 | //WB | |
265 | } | |
266 | else | |
267 | { | |
268 | IEEE80211_DEBUG(IEEE80211_DL_ERR, "alloc skb error in function %s()\n", __FUNCTION__); | |
269 | } | |
270 | return; | |
271 | } | |
272 | ||
273 | /******************************************************************************************************************** | |
274 | *function: send ADDBARSP frame out | |
275 | * input: u8* dst //DELBA frame's destination | |
276 | * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA | |
277 | * u16 StatusCode //RSP StatusCode | |
278 | * output: none | |
279 | * notice: If any possible, please hide pBA in ieee. And temporarily use Manage Queue as softmac_mgmt_xmit() usually does | |
280 | ********************************************************************************************************************/ | |
281 | void ieee80211_send_ADDBARsp(struct ieee80211_device* ieee, u8* dst, PBA_RECORD pBA, u16 StatusCode) | |
282 | { | |
283 | struct sk_buff *skb = NULL; | |
284 | skb = ieee80211_ADDBA(ieee, dst, pBA, StatusCode, ACT_ADDBARSP); //construct ACT_ADDBARSP frames | |
285 | if (skb) | |
286 | { | |
287 | softmac_mgmt_xmit(skb, ieee); | |
288 | //same above | |
289 | } | |
290 | else | |
291 | { | |
292 | IEEE80211_DEBUG(IEEE80211_DL_ERR, "alloc skb error in function %s()\n", __FUNCTION__); | |
293 | } | |
294 | ||
295 | return; | |
296 | ||
297 | } | |
298 | /******************************************************************************************************************** | |
299 | *function: send ADDBARSP frame out | |
300 | * input: u8* dst //DELBA frame's destination | |
301 | * PBA_RECORD pBA //BA_RECORD entry which stores the necessary information for BA | |
302 | * TR_SELECT TxRxSelect //TX or RX | |
303 | * u16 ReasonCode //DEL ReasonCode | |
304 | * output: none | |
305 | * notice: If any possible, please hide pBA in ieee. And temporarily use Manage Queue as softmac_mgmt_xmit() usually does | |
306 | ********************************************************************************************************************/ | |
307 | ||
308 | void ieee80211_send_DELBA(struct ieee80211_device* ieee, u8* dst, PBA_RECORD pBA, TR_SELECT TxRxSelect, u16 ReasonCode) | |
309 | { | |
310 | struct sk_buff *skb = NULL; | |
311 | skb = ieee80211_DELBA(ieee, dst, pBA, TxRxSelect, ReasonCode); //construct ACT_ADDBARSP frames | |
312 | if (skb) | |
313 | { | |
314 | softmac_mgmt_xmit(skb, ieee); | |
315 | //same above | |
316 | } | |
317 | else | |
318 | { | |
319 | IEEE80211_DEBUG(IEEE80211_DL_ERR, "alloc skb error in function %s()\n", __FUNCTION__); | |
320 | } | |
321 | return ; | |
322 | } | |
323 | ||
324 | /******************************************************************************************************************** | |
325 | *function: RX ADDBAReq | |
326 | * input: struct sk_buff * skb //incoming ADDBAReq skb. | |
327 | * return: 0(pass), other(fail) | |
328 | * notice: As this function need support of QOS, I comment some code out. And when qos is ready, this code need to be support. | |
329 | ********************************************************************************************************************/ | |
330 | int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb) | |
331 | { | |
332 | struct ieee80211_hdr_3addr* req = NULL; | |
333 | u16 rc = 0; | |
334 | u8 * dst = NULL, *pDialogToken = NULL, *tag = NULL; | |
335 | PBA_RECORD pBA = NULL; | |
336 | PBA_PARAM_SET pBaParamSet = NULL; | |
337 | u16* pBaTimeoutVal = NULL; | |
338 | PSEQUENCE_CONTROL pBaStartSeqCtrl = NULL; | |
339 | PRX_TS_RECORD pTS = NULL; | |
340 | ||
341 | if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9) | |
342 | { | |
3d8affc0 | 343 | IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BAREQ(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9)); |
8fc8598e JC |
344 | return -1; |
345 | } | |
346 | ||
347 | IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); | |
348 | ||
349 | req = ( struct ieee80211_hdr_3addr*) skb->data; | |
350 | tag = (u8*)req; | |
351 | dst = (u8*)(&req->addr2[0]); | |
352 | tag += sizeof( struct ieee80211_hdr_3addr); | |
353 | pDialogToken = tag + 2; //category+action | |
354 | pBaParamSet = (PBA_PARAM_SET)(tag + 3); //+DialogToken | |
355 | pBaTimeoutVal = (u16*)(tag + 5); | |
356 | pBaStartSeqCtrl = (PSEQUENCE_CONTROL)(req + 7); | |
357 | ||
358 | printk("====================>rx ADDBAREQ from :"MAC_FMT"\n", MAC_ARG(dst)); | |
359 | //some other capability is not ready now. | |
360 | if( (ieee->current_network.qos_data.active == 0) || | |
361 | (ieee->pHTInfo->bCurrentHTSupport == false)) //|| | |
362 | // (ieee->pStaQos->bEnableRxImmBA == false) ) | |
363 | { | |
364 | rc = ADDBA_STATUS_REFUSED; | |
365 | 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); | |
366 | goto OnADDBAReq_Fail; | |
367 | } | |
368 | // Search for related traffic stream. | |
369 | // If there is no matched TS, reject the ADDBA request. | |
370 | if( !GetTs( | |
371 | ieee, | |
372 | (PTS_COMMON_INFO*)(&pTS), | |
373 | dst, | |
374 | (u8)(pBaParamSet->field.TID), | |
375 | RX_DIR, | |
376 | true) ) | |
377 | { | |
378 | rc = ADDBA_STATUS_REFUSED; | |
379 | IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS in %s()\n", __FUNCTION__); | |
380 | goto OnADDBAReq_Fail; | |
381 | } | |
382 | pBA = &pTS->RxAdmittedBARecord; | |
383 | // To Determine the ADDBA Req content | |
384 | // We can do much more check here, including BufferSize, AMSDU_Support, Policy, StartSeqCtrl... | |
385 | // I want to check StartSeqCtrl to make sure when we start aggregation!!! | |
386 | // | |
387 | if(pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) | |
388 | { | |
389 | rc = ADDBA_STATUS_INVALID_PARAM; | |
390 | IEEE80211_DEBUG(IEEE80211_DL_ERR, "BA Policy is not correct in %s()\n", __FUNCTION__); | |
391 | goto OnADDBAReq_Fail; | |
392 | } | |
393 | // Admit the ADDBA Request | |
394 | // | |
395 | DeActivateBAEntry(ieee, pBA); | |
396 | pBA->DialogToken = *pDialogToken; | |
397 | pBA->BaParamSet = *pBaParamSet; | |
398 | pBA->BaTimeoutValue = *pBaTimeoutVal; | |
399 | pBA->BaStartSeqCtrl = *pBaStartSeqCtrl; | |
400 | //for half N mode we only aggregate 1 frame | |
401 | if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) | |
402 | pBA->BaParamSet.field.BufferSize = 1; | |
403 | else | |
404 | pBA->BaParamSet.field.BufferSize = 32; | |
405 | ActivateBAEntry(ieee, pBA, pBA->BaTimeoutValue); | |
406 | ieee80211_send_ADDBARsp(ieee, dst, pBA, ADDBA_STATUS_SUCCESS); | |
407 | ||
408 | // End of procedure. | |
409 | return 0; | |
410 | ||
411 | OnADDBAReq_Fail: | |
412 | { | |
413 | BA_RECORD BA; | |
414 | BA.BaParamSet = *pBaParamSet; | |
415 | BA.BaTimeoutValue = *pBaTimeoutVal; | |
416 | BA.DialogToken = *pDialogToken; | |
417 | BA.BaParamSet.field.BAPolicy = BA_POLICY_IMMEDIATE; | |
418 | ieee80211_send_ADDBARsp(ieee, dst, &BA, rc); | |
419 | return 0; //we send RSP out. | |
420 | } | |
421 | ||
422 | } | |
423 | ||
424 | /******************************************************************************************************************** | |
425 | *function: RX ADDBARSP | |
426 | * input: struct sk_buff * skb //incoming ADDBAReq skb. | |
427 | * return: 0(pass), other(fail) | |
428 | * notice: As this function need support of QOS, I comment some code out. And when qos is ready, this code need to be support. | |
429 | ********************************************************************************************************************/ | |
430 | int ieee80211_rx_ADDBARsp( struct ieee80211_device* ieee, struct sk_buff *skb) | |
431 | { | |
432 | struct ieee80211_hdr_3addr* rsp = NULL; | |
433 | PBA_RECORD pPendingBA, pAdmittedBA; | |
434 | PTX_TS_RECORD pTS = NULL; | |
435 | u8* dst = NULL, *pDialogToken = NULL, *tag = NULL; | |
436 | u16* pStatusCode = NULL, *pBaTimeoutVal = NULL; | |
437 | PBA_PARAM_SET pBaParamSet = NULL; | |
438 | u16 ReasonCode; | |
439 | ||
440 | if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9) | |
441 | { | |
3d8affc0 | 442 | IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BARSP(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9)); |
8fc8598e JC |
443 | return -1; |
444 | } | |
445 | rsp = ( struct ieee80211_hdr_3addr*)skb->data; | |
446 | tag = (u8*)rsp; | |
447 | dst = (u8*)(&rsp->addr2[0]); | |
448 | tag += sizeof( struct ieee80211_hdr_3addr); | |
449 | pDialogToken = tag + 2; | |
450 | pStatusCode = (u16*)(tag + 3); | |
451 | pBaParamSet = (PBA_PARAM_SET)(tag + 5); | |
452 | pBaTimeoutVal = (u16*)(tag + 7); | |
453 | ||
454 | // Check the capability | |
455 | // Since we can always receive A-MPDU, we just check if it is under HT mode. | |
456 | if( ieee->current_network.qos_data.active == 0 || | |
457 | ieee->pHTInfo->bCurrentHTSupport == false || | |
458 | ieee->pHTInfo->bCurrentAMPDUEnable == false ) | |
459 | { | |
460 | 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); | |
461 | ReasonCode = DELBA_REASON_UNKNOWN_BA; | |
462 | goto OnADDBARsp_Reject; | |
463 | } | |
464 | ||
465 | ||
466 | // | |
467 | // Search for related TS. | |
468 | // If there is no TS found, we wil reject ADDBA Rsp by sending DELBA frame. | |
469 | // | |
470 | if (!GetTs( | |
471 | ieee, | |
472 | (PTS_COMMON_INFO*)(&pTS), | |
473 | dst, | |
474 | (u8)(pBaParamSet->field.TID), | |
475 | TX_DIR, | |
476 | false) ) | |
477 | { | |
478 | IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS in %s()\n", __FUNCTION__); | |
479 | ReasonCode = DELBA_REASON_UNKNOWN_BA; | |
480 | goto OnADDBARsp_Reject; | |
481 | } | |
482 | ||
483 | pTS->bAddBaReqInProgress = false; | |
484 | pPendingBA = &pTS->TxPendingBARecord; | |
485 | pAdmittedBA = &pTS->TxAdmittedBARecord; | |
486 | ||
487 | ||
488 | // | |
489 | // Check if related BA is waiting for setup. | |
490 | // If not, reject by sending DELBA frame. | |
491 | // | |
492 | if((pAdmittedBA->bValid==true)) | |
493 | { | |
494 | // Since BA is already setup, we ignore all other ADDBA Response. | |
495 | IEEE80211_DEBUG(IEEE80211_DL_BA, "OnADDBARsp(): Recv ADDBA Rsp. Drop because already admit it! \n"); | |
496 | return -1; | |
497 | } | |
498 | else if((pPendingBA->bValid == false) ||(*pDialogToken != pPendingBA->DialogToken)) | |
499 | { | |
500 | IEEE80211_DEBUG(IEEE80211_DL_ERR, "OnADDBARsp(): Recv ADDBA Rsp. BA invalid, DELBA! \n"); | |
501 | ReasonCode = DELBA_REASON_UNKNOWN_BA; | |
502 | goto OnADDBARsp_Reject; | |
503 | } | |
504 | else | |
505 | { | |
506 | IEEE80211_DEBUG(IEEE80211_DL_BA, "OnADDBARsp(): Recv ADDBA Rsp. BA is admitted! Status code:%X\n", *pStatusCode); | |
507 | DeActivateBAEntry(ieee, pPendingBA); | |
508 | } | |
509 | ||
510 | ||
511 | if(*pStatusCode == ADDBA_STATUS_SUCCESS) | |
512 | { | |
513 | // | |
514 | // Determine ADDBA Rsp content here. | |
515 | // We can compare the value of BA parameter set that Peer returned and Self sent. | |
516 | // If it is OK, then admitted. Or we can send DELBA to cancel BA mechanism. | |
517 | // | |
518 | if(pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) | |
519 | { | |
520 | // Since this is a kind of ADDBA failed, we delay next ADDBA process. | |
521 | pTS->bAddBaReqDelayed = true; | |
522 | DeActivateBAEntry(ieee, pAdmittedBA); | |
523 | ReasonCode = DELBA_REASON_END_BA; | |
524 | goto OnADDBARsp_Reject; | |
525 | } | |
526 | ||
527 | ||
528 | // | |
529 | // Admitted condition | |
530 | // | |
531 | pAdmittedBA->DialogToken = *pDialogToken; | |
532 | pAdmittedBA->BaTimeoutValue = *pBaTimeoutVal; | |
533 | pAdmittedBA->BaStartSeqCtrl = pPendingBA->BaStartSeqCtrl; | |
534 | pAdmittedBA->BaParamSet = *pBaParamSet; | |
535 | DeActivateBAEntry(ieee, pAdmittedBA); | |
536 | ActivateBAEntry(ieee, pAdmittedBA, *pBaTimeoutVal); | |
537 | } | |
538 | else | |
539 | { | |
540 | // Delay next ADDBA process. | |
541 | pTS->bAddBaReqDelayed = true; | |
542 | } | |
543 | ||
544 | // End of procedure | |
545 | return 0; | |
546 | ||
547 | OnADDBARsp_Reject: | |
548 | { | |
549 | BA_RECORD BA; | |
550 | BA.BaParamSet = *pBaParamSet; | |
551 | ieee80211_send_DELBA(ieee, dst, &BA, TX_DIR, ReasonCode); | |
552 | return 0; | |
553 | } | |
554 | ||
555 | } | |
556 | ||
557 | /******************************************************************************************************************** | |
558 | *function: RX DELBA | |
559 | * input: struct sk_buff * skb //incoming ADDBAReq skb. | |
560 | * return: 0(pass), other(fail) | |
561 | * notice: As this function need support of QOS, I comment some code out. And when qos is ready, this code need to be support. | |
562 | ********************************************************************************************************************/ | |
563 | int ieee80211_rx_DELBA(struct ieee80211_device* ieee,struct sk_buff *skb) | |
564 | { | |
565 | struct ieee80211_hdr_3addr* delba = NULL; | |
566 | PDELBA_PARAM_SET pDelBaParamSet = NULL; | |
567 | u16* pReasonCode = NULL; | |
568 | u8* dst = NULL; | |
569 | ||
570 | if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 6) | |
571 | { | |
3d8affc0 | 572 | IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in DELBA(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 6)); |
8fc8598e JC |
573 | return -1; |
574 | } | |
575 | ||
576 | if(ieee->current_network.qos_data.active == 0 || | |
577 | ieee->pHTInfo->bCurrentHTSupport == false ) | |
578 | { | |
579 | 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); | |
580 | return -1; | |
581 | } | |
582 | ||
583 | IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); | |
584 | delba = ( struct ieee80211_hdr_3addr*)skb->data; | |
585 | dst = (u8*)(&delba->addr2[0]); | |
586 | delba += sizeof( struct ieee80211_hdr_3addr); | |
587 | pDelBaParamSet = (PDELBA_PARAM_SET)(delba+2); | |
588 | pReasonCode = (u16*)(delba+4); | |
589 | ||
590 | if(pDelBaParamSet->field.Initiator == 1) | |
591 | { | |
592 | PRX_TS_RECORD pRxTs; | |
593 | ||
594 | if( !GetTs( | |
595 | ieee, | |
596 | (PTS_COMMON_INFO*)&pRxTs, | |
597 | dst, | |
598 | (u8)pDelBaParamSet->field.TID, | |
599 | RX_DIR, | |
600 | false) ) | |
601 | { | |
602 | IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS for RXTS in %s()\n", __FUNCTION__); | |
603 | return -1; | |
604 | } | |
605 | ||
606 | RxTsDeleteBA(ieee, pRxTs); | |
607 | } | |
608 | else | |
609 | { | |
610 | PTX_TS_RECORD pTxTs; | |
611 | ||
612 | if(!GetTs( | |
613 | ieee, | |
614 | (PTS_COMMON_INFO*)&pTxTs, | |
615 | dst, | |
616 | (u8)pDelBaParamSet->field.TID, | |
617 | TX_DIR, | |
618 | false) ) | |
619 | { | |
620 | IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't get TS for TXTS in %s()\n", __FUNCTION__); | |
621 | return -1; | |
622 | } | |
623 | ||
624 | pTxTs->bUsingBa = false; | |
625 | pTxTs->bAddBaReqInProgress = false; | |
626 | pTxTs->bAddBaReqDelayed = false; | |
627 | del_timer_sync(&pTxTs->TsAddBaTimer); | |
628 | //PlatformCancelTimer(Adapter, &pTxTs->TsAddBaTimer); | |
629 | TxTsDeleteBA(ieee, pTxTs); | |
630 | } | |
631 | return 0; | |
632 | } | |
633 | ||
634 | // | |
635 | // ADDBA initiate. This can only be called by TX side. | |
636 | // | |
637 | void | |
638 | TsInitAddBA( | |
639 | struct ieee80211_device* ieee, | |
640 | PTX_TS_RECORD pTS, | |
641 | u8 Policy, | |
642 | u8 bOverwritePending | |
643 | ) | |
644 | { | |
645 | PBA_RECORD pBA = &pTS->TxPendingBARecord; | |
646 | ||
647 | if(pBA->bValid==true && bOverwritePending==false) | |
648 | return; | |
649 | ||
650 | // Set parameters to "Pending" variable set | |
651 | DeActivateBAEntry(ieee, pBA); | |
652 | ||
653 | pBA->DialogToken++; // DialogToken: Only keep the latest dialog token | |
654 | pBA->BaParamSet.field.AMSDU_Support = 0; // Do not support A-MSDU with A-MPDU now!! | |
655 | pBA->BaParamSet.field.BAPolicy = Policy; // Policy: Delayed or Immediate | |
656 | pBA->BaParamSet.field.TID = pTS->TsCommonInfo.TSpec.f.TSInfo.field.ucTSID; // TID | |
657 | // BufferSize: This need to be set according to A-MPDU vector | |
658 | pBA->BaParamSet.field.BufferSize = 32; // BufferSize: This need to be set according to A-MPDU vector | |
659 | pBA->BaTimeoutValue = 0; // Timeout value: Set 0 to disable Timer | |
660 | pBA->BaStartSeqCtrl.field.SeqNum = (pTS->TxCurSeq + 3) % 4096; // Block Ack will start after 3 packets later. | |
661 | ||
662 | ActivateBAEntry(ieee, pBA, BA_SETUP_TIMEOUT); | |
663 | ||
664 | ieee80211_send_ADDBAReq(ieee, pTS->TsCommonInfo.Addr, pBA); | |
665 | } | |
666 | ||
667 | void | |
668 | TsInitDelBA( struct ieee80211_device* ieee, PTS_COMMON_INFO pTsCommonInfo, TR_SELECT TxRxSelect) | |
669 | { | |
670 | ||
671 | if(TxRxSelect == TX_DIR) | |
672 | { | |
673 | PTX_TS_RECORD pTxTs = (PTX_TS_RECORD)pTsCommonInfo; | |
674 | ||
675 | if(TxTsDeleteBA(ieee, pTxTs)) | |
676 | ieee80211_send_DELBA( | |
677 | ieee, | |
678 | pTsCommonInfo->Addr, | |
679 | (pTxTs->TxAdmittedBARecord.bValid)?(&pTxTs->TxAdmittedBARecord):(&pTxTs->TxPendingBARecord), | |
680 | TxRxSelect, | |
681 | DELBA_REASON_END_BA); | |
682 | } | |
683 | else if(TxRxSelect == RX_DIR) | |
684 | { | |
685 | PRX_TS_RECORD pRxTs = (PRX_TS_RECORD)pTsCommonInfo; | |
686 | if(RxTsDeleteBA(ieee, pRxTs)) | |
687 | ieee80211_send_DELBA( | |
688 | ieee, | |
689 | pTsCommonInfo->Addr, | |
690 | &pRxTs->RxAdmittedBARecord, | |
691 | TxRxSelect, | |
692 | DELBA_REASON_END_BA ); | |
693 | } | |
694 | } | |
695 | /******************************************************************************************************************** | |
696 | *function: BA setup timer | |
697 | * input: unsigned long data //acturally we send TX_TS_RECORD or RX_TS_RECORD to these timer | |
698 | * return: NULL | |
699 | * notice: | |
700 | ********************************************************************************************************************/ | |
701 | void BaSetupTimeOut(unsigned long data) | |
702 | { | |
703 | PTX_TS_RECORD pTxTs = (PTX_TS_RECORD)data; | |
704 | ||
705 | pTxTs->bAddBaReqInProgress = false; | |
706 | pTxTs->bAddBaReqDelayed = true; | |
707 | pTxTs->TxPendingBARecord.bValid = false; | |
708 | } | |
709 | ||
710 | void TxBaInactTimeout(unsigned long data) | |
711 | { | |
712 | PTX_TS_RECORD pTxTs = (PTX_TS_RECORD)data; | |
713 | struct ieee80211_device *ieee = container_of(pTxTs, struct ieee80211_device, TxTsRecord[pTxTs->num]); | |
714 | TxTsDeleteBA(ieee, pTxTs); | |
715 | ieee80211_send_DELBA( | |
716 | ieee, | |
717 | pTxTs->TsCommonInfo.Addr, | |
718 | &pTxTs->TxAdmittedBARecord, | |
719 | TX_DIR, | |
720 | DELBA_REASON_TIMEOUT); | |
721 | } | |
722 | ||
723 | void RxBaInactTimeout(unsigned long data) | |
724 | { | |
725 | PRX_TS_RECORD pRxTs = (PRX_TS_RECORD)data; | |
726 | struct ieee80211_device *ieee = container_of(pRxTs, struct ieee80211_device, RxTsRecord[pRxTs->num]); | |
727 | ||
728 | RxTsDeleteBA(ieee, pRxTs); | |
729 | ieee80211_send_DELBA( | |
730 | ieee, | |
731 | pRxTs->TsCommonInfo.Addr, | |
732 | &pRxTs->RxAdmittedBARecord, | |
733 | RX_DIR, | |
734 | DELBA_REASON_TIMEOUT); | |
735 | return ; | |
736 | } | |
737 |