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