Commit | Line | Data |
---|---|---|
94a79942 LF |
1 | /****************************************************************************** |
2 | * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. | |
3 | * | |
4 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
5 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
6 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
7 | * more details. | |
8 | * | |
9 | * You should have received a copy of the GNU General Public License along with | |
10 | * this program; if not, write to the Free Software Foundation, Inc., | |
11 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | |
12 | * | |
13 | * The full GNU General Public License is included in this distribution in the | |
14 | * file called LICENSE. | |
15 | * | |
16 | * Contact Information: | |
17 | * wlanfae <wlanfae@realtek.com> | |
18 | ******************************************************************************/ | |
19 | #include "rtllib.h" | |
20 | #include "rtl819x_BA.h" | |
94a79942 | 21 | |
ec0dc6be LF |
22 | static void ActivateBAEntry(struct rtllib_device *ieee, struct ba_record *pBA, |
23 | u16 Time) | |
94a79942 LF |
24 | { |
25 | pBA->bValid = true; | |
26 | if (Time != 0) | |
27 | mod_timer(&pBA->Timer, jiffies + MSECS(Time)); | |
28 | } | |
29 | ||
ec0dc6be | 30 | static void DeActivateBAEntry(struct rtllib_device *ieee, struct ba_record *pBA) |
94a79942 LF |
31 | { |
32 | pBA->bValid = false; | |
33 | del_timer_sync(&pBA->Timer); | |
34 | } | |
831cb9db | 35 | |
ec0dc6be | 36 | static u8 TxTsDeleteBA(struct rtllib_device *ieee, struct tx_ts_record *pTxTs) |
94a79942 | 37 | { |
8cf33316 LF |
38 | struct ba_record *pAdmittedBa = &pTxTs->TxAdmittedBARecord; |
39 | struct ba_record *pPendingBa = &pTxTs->TxPendingBARecord; | |
831cb9db | 40 | u8 bSendDELBA = false; |
94a79942 | 41 | |
831cb9db | 42 | if (pPendingBa->bValid) { |
94a79942 LF |
43 | DeActivateBAEntry(ieee, pPendingBa); |
44 | bSendDELBA = true; | |
45 | } | |
46 | ||
831cb9db | 47 | if (pAdmittedBa->bValid) { |
94a79942 LF |
48 | DeActivateBAEntry(ieee, pAdmittedBa); |
49 | bSendDELBA = true; | |
50 | } | |
94a79942 LF |
51 | return bSendDELBA; |
52 | } | |
53 | ||
ec0dc6be | 54 | static u8 RxTsDeleteBA(struct rtllib_device *ieee, struct rx_ts_record *pRxTs) |
94a79942 | 55 | { |
8cf33316 | 56 | struct ba_record *pBa = &pRxTs->RxAdmittedBARecord; |
94a79942 LF |
57 | u8 bSendDELBA = false; |
58 | ||
831cb9db | 59 | if (pBa->bValid) { |
94a79942 LF |
60 | DeActivateBAEntry(ieee, pBa); |
61 | bSendDELBA = true; | |
62 | } | |
63 | ||
64 | return bSendDELBA; | |
65 | } | |
66 | ||
831cb9db | 67 | void ResetBaEntry(struct ba_record *pBA) |
94a79942 LF |
68 | { |
69 | pBA->bValid = false; | |
70 | pBA->BaParamSet.shortData = 0; | |
71 | pBA->BaTimeoutValue = 0; | |
72 | pBA->DialogToken = 0; | |
73 | pBA->BaStartSeqCtrl.ShortData = 0; | |
74 | } | |
831cb9db LF |
75 | static struct sk_buff *rtllib_ADDBA(struct rtllib_device *ieee, u8 *Dst, |
76 | struct ba_record *pBA, | |
77 | u16 StatusCode, u8 type) | |
94a79942 LF |
78 | { |
79 | struct sk_buff *skb = NULL; | |
831cb9db LF |
80 | struct rtllib_hdr_3addr *BAReq = NULL; |
81 | u8 *tag = NULL; | |
94a79942 LF |
82 | u16 tmp = 0; |
83 | u16 len = ieee->tx_headroom + 9; | |
ce7b393f | 84 | |
831cb9db | 85 | RTLLIB_DEBUG(RTLLIB_DL_TRACE | RTLLIB_DL_BA, "========>%s(), frame(%d)" |
ac50ddaa LF |
86 | " sentd to: %pM, ieee->dev:%p\n", __func__, |
87 | type, Dst, ieee->dev); | |
ce7b393f | 88 | if (pBA == NULL) { |
a85fe2c6 | 89 | RTLLIB_DEBUG(RTLLIB_DL_ERR, "pBA is NULL\n"); |
94a79942 LF |
90 | return NULL; |
91 | } | |
831cb9db LF |
92 | skb = dev_alloc_skb(len + sizeof(struct rtllib_hdr_3addr)); |
93 | if (skb == NULL) { | |
94a79942 LF |
94 | RTLLIB_DEBUG(RTLLIB_DL_ERR, "can't alloc skb for ADDBA_REQ\n"); |
95 | return NULL; | |
96 | } | |
97 | ||
831cb9db | 98 | memset(skb->data, 0, sizeof(struct rtllib_hdr_3addr)); |
94a79942 | 99 | |
94a79942 LF |
100 | skb_reserve(skb, ieee->tx_headroom); |
101 | ||
831cb9db LF |
102 | BAReq = (struct rtllib_hdr_3addr *)skb_put(skb, |
103 | sizeof(struct rtllib_hdr_3addr)); | |
94a79942 LF |
104 | |
105 | memcpy(BAReq->addr1, Dst, ETH_ALEN); | |
106 | memcpy(BAReq->addr2, ieee->dev->dev_addr, ETH_ALEN); | |
107 | ||
108 | memcpy(BAReq->addr3, ieee->current_network.bssid, ETH_ALEN); | |
109 | BAReq->frame_ctl = cpu_to_le16(RTLLIB_STYPE_MANAGE_ACT); | |
110 | ||
831cb9db | 111 | tag = (u8 *)skb_put(skb, 9); |
82671db8 PM |
112 | *tag++ = ACT_CAT_BA; |
113 | *tag++ = type; | |
114 | *tag++ = pBA->DialogToken; | |
94a79942 | 115 | |
831cb9db | 116 | if (ACT_ADDBARSP == type) { |
94a79942 | 117 | RT_TRACE(COMP_DBG, "====>to send ADDBARSP\n"); |
45024646 | 118 | tmp = StatusCode; |
831cb9db | 119 | memcpy(tag, (u8 *)&tmp, 2); |
94a79942 LF |
120 | tag += 2; |
121 | } | |
45024646 | 122 | tmp = pBA->BaParamSet.shortData; |
831cb9db | 123 | memcpy(tag, (u8 *)&tmp, 2); |
94a79942 | 124 | tag += 2; |
45024646 | 125 | tmp = pBA->BaTimeoutValue; |
831cb9db | 126 | memcpy(tag, (u8 *)&tmp, 2); |
94a79942 LF |
127 | tag += 2; |
128 | ||
831cb9db LF |
129 | if (ACT_ADDBAREQ == type) { |
130 | memcpy(tag, (u8 *)&(pBA->BaStartSeqCtrl), 2); | |
94a79942 LF |
131 | tag += 2; |
132 | } | |
133 | ||
134 | RTLLIB_DEBUG_DATA(RTLLIB_DL_DATA|RTLLIB_DL_BA, skb->data, skb->len); | |
135 | return skb; | |
136 | } | |
137 | ||
831cb9db LF |
138 | static struct sk_buff *rtllib_DELBA(struct rtllib_device *ieee, u8 *dst, |
139 | struct ba_record *pBA, | |
140 | enum tr_select TxRxSelect, u16 ReasonCode) | |
94a79942 | 141 | { |
f198db0c | 142 | union delba_param_set DelbaParamSet; |
94a79942 | 143 | struct sk_buff *skb = NULL; |
831cb9db LF |
144 | struct rtllib_hdr_3addr *Delba = NULL; |
145 | u8 *tag = NULL; | |
94a79942 LF |
146 | u16 tmp = 0; |
147 | u16 len = 6 + ieee->tx_headroom; | |
148 | ||
149 | if (net_ratelimit()) | |
831cb9db LF |
150 | RTLLIB_DEBUG(RTLLIB_DL_TRACE | RTLLIB_DL_BA, |
151 | "========>%s(), Reason" | |
ac50ddaa LF |
152 | "Code(%d) sentd to: %pM\n", __func__, |
153 | ReasonCode, dst); | |
94a79942 LF |
154 | |
155 | memset(&DelbaParamSet, 0, 2); | |
156 | ||
831cb9db | 157 | DelbaParamSet.field.Initiator = (TxRxSelect == TX_DIR) ? 1 : 0; |
94a79942 LF |
158 | DelbaParamSet.field.TID = pBA->BaParamSet.field.TID; |
159 | ||
831cb9db LF |
160 | skb = dev_alloc_skb(len + sizeof(struct rtllib_hdr_3addr)); |
161 | if (skb == NULL) { | |
94a79942 LF |
162 | RTLLIB_DEBUG(RTLLIB_DL_ERR, "can't alloc skb for ADDBA_REQ\n"); |
163 | return NULL; | |
164 | } | |
165 | ||
94a79942 LF |
166 | skb_reserve(skb, ieee->tx_headroom); |
167 | ||
831cb9db LF |
168 | Delba = (struct rtllib_hdr_3addr *) skb_put(skb, |
169 | sizeof(struct rtllib_hdr_3addr)); | |
94a79942 LF |
170 | |
171 | memcpy(Delba->addr1, dst, ETH_ALEN); | |
172 | memcpy(Delba->addr2, ieee->dev->dev_addr, ETH_ALEN); | |
173 | memcpy(Delba->addr3, ieee->current_network.bssid, ETH_ALEN); | |
174 | Delba->frame_ctl = cpu_to_le16(RTLLIB_STYPE_MANAGE_ACT); | |
175 | ||
831cb9db | 176 | tag = (u8 *)skb_put(skb, 6); |
94a79942 | 177 | |
82671db8 PM |
178 | *tag++ = ACT_CAT_BA; |
179 | *tag++ = ACT_DELBA; | |
94a79942 | 180 | |
45024646 | 181 | tmp = DelbaParamSet.shortData; |
831cb9db | 182 | memcpy(tag, (u8 *)&tmp, 2); |
94a79942 | 183 | tag += 2; |
45024646 | 184 | tmp = ReasonCode; |
831cb9db | 185 | memcpy(tag, (u8 *)&tmp, 2); |
94a79942 LF |
186 | tag += 2; |
187 | ||
188 | RTLLIB_DEBUG_DATA(RTLLIB_DL_DATA|RTLLIB_DL_BA, skb->data, skb->len); | |
189 | if (net_ratelimit()) | |
831cb9db LF |
190 | RTLLIB_DEBUG(RTLLIB_DL_TRACE | RTLLIB_DL_BA, "<=====%s()\n", |
191 | __func__); | |
94a79942 LF |
192 | return skb; |
193 | } | |
194 | ||
ec0dc6be LF |
195 | static void rtllib_send_ADDBAReq(struct rtllib_device *ieee, u8 *dst, |
196 | struct ba_record *pBA) | |
94a79942 LF |
197 | { |
198 | struct sk_buff *skb = NULL; | |
3a6b70c3 | 199 | |
94a79942 LF |
200 | skb = rtllib_ADDBA(ieee, dst, pBA, 0, ACT_ADDBAREQ); |
201 | ||
202 | if (skb) { | |
203 | RT_TRACE(COMP_DBG, "====>to send ADDBAREQ!!!!!\n"); | |
204 | softmac_mgmt_xmit(skb, ieee); | |
205 | } else { | |
831cb9db LF |
206 | RTLLIB_DEBUG(RTLLIB_DL_ERR, "alloc skb error in function" |
207 | " %s()\n", __func__); | |
94a79942 LF |
208 | } |
209 | return; | |
210 | } | |
211 | ||
ec0dc6be LF |
212 | static void rtllib_send_ADDBARsp(struct rtllib_device *ieee, u8 *dst, |
213 | struct ba_record *pBA, u16 StatusCode) | |
94a79942 LF |
214 | { |
215 | struct sk_buff *skb = NULL; | |
3a6b70c3 | 216 | |
94a79942 LF |
217 | skb = rtllib_ADDBA(ieee, dst, pBA, StatusCode, ACT_ADDBARSP); |
218 | if (skb) | |
219 | softmac_mgmt_xmit(skb, ieee); | |
220 | else | |
831cb9db LF |
221 | RTLLIB_DEBUG(RTLLIB_DL_ERR, "alloc skb error in function" |
222 | " %s()\n", __func__); | |
94a79942 | 223 | return; |
94a79942 LF |
224 | } |
225 | ||
ec0dc6be LF |
226 | static void rtllib_send_DELBA(struct rtllib_device *ieee, u8 *dst, |
227 | struct ba_record *pBA, enum tr_select TxRxSelect, | |
228 | u16 ReasonCode) | |
94a79942 LF |
229 | { |
230 | struct sk_buff *skb = NULL; | |
3a6b70c3 | 231 | |
94a79942 LF |
232 | skb = rtllib_DELBA(ieee, dst, pBA, TxRxSelect, ReasonCode); |
233 | if (skb) | |
94a79942 | 234 | softmac_mgmt_xmit(skb, ieee); |
94a79942 | 235 | else |
86595967 MI |
236 | RTLLIB_DEBUG(RTLLIB_DL_ERR, "alloc skb error in function" |
237 | " %s()\n", __func__); | |
94a79942 LF |
238 | return ; |
239 | } | |
240 | ||
831cb9db | 241 | int rtllib_rx_ADDBAReq(struct rtllib_device *ieee, struct sk_buff *skb) |
94a79942 | 242 | { |
831cb9db | 243 | struct rtllib_hdr_3addr *req = NULL; |
94a79942 | 244 | u16 rc = 0; |
831cb9db | 245 | u8 *dst = NULL, *pDialogToken = NULL, *tag = NULL; |
8cf33316 | 246 | struct ba_record *pBA = NULL; |
6857f367 | 247 | union ba_param_set *pBaParamSet = NULL; |
831cb9db | 248 | u16 *pBaTimeoutVal = NULL; |
7baf9546 | 249 | union sequence_control *pBaStartSeqCtrl = NULL; |
2c47ae28 | 250 | struct rx_ts_record *pTS = NULL; |
94a79942 | 251 | |
831cb9db LF |
252 | if (skb->len < sizeof(struct rtllib_hdr_3addr) + 9) { |
253 | RTLLIB_DEBUG(RTLLIB_DL_ERR, " Invalid skb len in BAREQ(%d / " | |
254 | "%d)\n", (int)skb->len, | |
255 | (int)(sizeof(struct rtllib_hdr_3addr) + 9)); | |
94a79942 LF |
256 | return -1; |
257 | } | |
258 | ||
259 | RTLLIB_DEBUG_DATA(RTLLIB_DL_DATA|RTLLIB_DL_BA, skb->data, skb->len); | |
260 | ||
831cb9db LF |
261 | req = (struct rtllib_hdr_3addr *) skb->data; |
262 | tag = (u8 *)req; | |
263 | dst = (u8 *)(&req->addr2[0]); | |
264 | tag += sizeof(struct rtllib_hdr_3addr); | |
94a79942 | 265 | pDialogToken = tag + 2; |
6857f367 | 266 | pBaParamSet = (union ba_param_set *)(tag + 3); |
831cb9db | 267 | pBaTimeoutVal = (u16 *)(tag + 5); |
7baf9546 | 268 | pBaStartSeqCtrl = (union sequence_control *)(req + 7); |
94a79942 | 269 | |
ac50ddaa | 270 | RT_TRACE(COMP_DBG, "====>rx ADDBAREQ from : %pM\n", dst); |
94a79942 LF |
271 | if (ieee->current_network.qos_data.active == 0 || |
272 | (ieee->pHTInfo->bCurrentHTSupport == false) || | |
273 | (ieee->pHTInfo->IOTAction & HT_IOT_ACT_REJECT_ADDBA_REQ)) { | |
274 | rc = ADDBA_STATUS_REFUSED; | |
831cb9db LF |
275 | RTLLIB_DEBUG(RTLLIB_DL_ERR, "Failed to reply on ADDBA_REQ as " |
276 | "some capability is not ready(%d, %d)\n", | |
277 | ieee->current_network.qos_data.active, | |
278 | ieee->pHTInfo->bCurrentHTSupport); | |
94a79942 LF |
279 | goto OnADDBAReq_Fail; |
280 | } | |
831cb9db LF |
281 | if (!GetTs(ieee, (struct ts_common_info **)(&pTS), dst, |
282 | (u8)(pBaParamSet->field.TID), RX_DIR, true)) { | |
94a79942 LF |
283 | rc = ADDBA_STATUS_REFUSED; |
284 | RTLLIB_DEBUG(RTLLIB_DL_ERR, "can't get TS in %s()\n", __func__); | |
285 | goto OnADDBAReq_Fail; | |
286 | } | |
287 | pBA = &pTS->RxAdmittedBARecord; | |
288 | ||
831cb9db | 289 | if (pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) { |
94a79942 | 290 | rc = ADDBA_STATUS_INVALID_PARAM; |
831cb9db LF |
291 | RTLLIB_DEBUG(RTLLIB_DL_ERR, "BA Policy is not correct in " |
292 | "%s()\n", __func__); | |
94a79942 LF |
293 | goto OnADDBAReq_Fail; |
294 | } | |
295 | ||
94a79942 LF |
296 | rtllib_FlushRxTsPendingPkts(ieee, pTS); |
297 | ||
298 | DeActivateBAEntry(ieee, pBA); | |
299 | pBA->DialogToken = *pDialogToken; | |
300 | pBA->BaParamSet = *pBaParamSet; | |
301 | pBA->BaTimeoutValue = *pBaTimeoutVal; | |
302 | pBA->BaStartSeqCtrl = *pBaStartSeqCtrl; | |
303 | ||
831cb9db LF |
304 | if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev) || |
305 | (ieee->pHTInfo->IOTAction & HT_IOT_ACT_ALLOW_PEER_AGG_ONE_PKT)) | |
306 | pBA->BaParamSet.field.BufferSize = 1; | |
94a79942 | 307 | else |
831cb9db | 308 | pBA->BaParamSet.field.BufferSize = 32; |
94a79942 LF |
309 | |
310 | ActivateBAEntry(ieee, pBA, 0); | |
311 | rtllib_send_ADDBARsp(ieee, dst, pBA, ADDBA_STATUS_SUCCESS); | |
312 | ||
313 | return 0; | |
314 | ||
315 | OnADDBAReq_Fail: | |
316 | { | |
8cf33316 | 317 | struct ba_record BA; |
3a6b70c3 | 318 | |
94a79942 LF |
319 | BA.BaParamSet = *pBaParamSet; |
320 | BA.BaTimeoutValue = *pBaTimeoutVal; | |
321 | BA.DialogToken = *pDialogToken; | |
322 | BA.BaParamSet.field.BAPolicy = BA_POLICY_IMMEDIATE; | |
323 | rtllib_send_ADDBARsp(ieee, dst, &BA, rc); | |
324 | return 0; | |
325 | } | |
94a79942 LF |
326 | } |
327 | ||
831cb9db | 328 | int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb) |
94a79942 | 329 | { |
831cb9db | 330 | struct rtllib_hdr_3addr *rsp = NULL; |
8cf33316 | 331 | struct ba_record *pPendingBA, *pAdmittedBA; |
60554f2b | 332 | struct tx_ts_record *pTS = NULL; |
831cb9db LF |
333 | u8 *dst = NULL, *pDialogToken = NULL, *tag = NULL; |
334 | u16 *pStatusCode = NULL, *pBaTimeoutVal = NULL; | |
6857f367 | 335 | union ba_param_set *pBaParamSet = NULL; |
94a79942 LF |
336 | u16 ReasonCode; |
337 | ||
831cb9db LF |
338 | if (skb->len < sizeof(struct rtllib_hdr_3addr) + 9) { |
339 | RTLLIB_DEBUG(RTLLIB_DL_ERR, " Invalid skb len in BARSP(%d / " | |
340 | "%d)\n", (int)skb->len, | |
341 | (int)(sizeof(struct rtllib_hdr_3addr) + 9)); | |
94a79942 LF |
342 | return -1; |
343 | } | |
831cb9db LF |
344 | rsp = (struct rtllib_hdr_3addr *)skb->data; |
345 | tag = (u8 *)rsp; | |
346 | dst = (u8 *)(&rsp->addr2[0]); | |
347 | tag += sizeof(struct rtllib_hdr_3addr); | |
94a79942 | 348 | pDialogToken = tag + 2; |
831cb9db | 349 | pStatusCode = (u16 *)(tag + 3); |
6857f367 | 350 | pBaParamSet = (union ba_param_set *)(tag + 5); |
831cb9db | 351 | pBaTimeoutVal = (u16 *)(tag + 7); |
94a79942 | 352 | |
ac50ddaa | 353 | RT_TRACE(COMP_DBG, "====>rx ADDBARSP from : %pM\n", dst); |
831cb9db LF |
354 | if (ieee->current_network.qos_data.active == 0 || |
355 | ieee->pHTInfo->bCurrentHTSupport == false || | |
356 | ieee->pHTInfo->bCurrentAMPDUEnable == false) { | |
357 | RTLLIB_DEBUG(RTLLIB_DL_ERR, "reject to ADDBA_RSP as some capab" | |
358 | "ility is not ready(%d, %d, %d)\n", | |
359 | ieee->current_network.qos_data.active, | |
360 | ieee->pHTInfo->bCurrentHTSupport, | |
361 | ieee->pHTInfo->bCurrentAMPDUEnable); | |
94a79942 LF |
362 | ReasonCode = DELBA_REASON_UNKNOWN_BA; |
363 | goto OnADDBARsp_Reject; | |
364 | } | |
365 | ||
366 | ||
74724de1 | 367 | if (!GetTs(ieee, (struct ts_common_info **)(&pTS), dst, |
94a79942 LF |
368 | (u8)(pBaParamSet->field.TID), TX_DIR, false)) { |
369 | RTLLIB_DEBUG(RTLLIB_DL_ERR, "can't get TS in %s()\n", __func__); | |
370 | ReasonCode = DELBA_REASON_UNKNOWN_BA; | |
371 | goto OnADDBARsp_Reject; | |
372 | } | |
373 | ||
374 | pTS->bAddBaReqInProgress = false; | |
375 | pPendingBA = &pTS->TxPendingBARecord; | |
376 | pAdmittedBA = &pTS->TxAdmittedBARecord; | |
377 | ||
378 | ||
52e93b8a | 379 | if (pAdmittedBA->bValid == true) { |
831cb9db LF |
380 | RTLLIB_DEBUG(RTLLIB_DL_BA, "OnADDBARsp(): Recv ADDBA Rsp." |
381 | " Drop because already admit it!\n"); | |
94a79942 | 382 | return -1; |
831cb9db LF |
383 | } else if ((pPendingBA->bValid == false) || |
384 | (*pDialogToken != pPendingBA->DialogToken)) { | |
385 | RTLLIB_DEBUG(RTLLIB_DL_ERR, "OnADDBARsp(): Recv ADDBA Rsp. " | |
386 | "BA invalid, DELBA!\n"); | |
94a79942 LF |
387 | ReasonCode = DELBA_REASON_UNKNOWN_BA; |
388 | goto OnADDBARsp_Reject; | |
831cb9db LF |
389 | } else { |
390 | RTLLIB_DEBUG(RTLLIB_DL_BA, "OnADDBARsp(): Recv ADDBA Rsp. BA " | |
391 | "is admitted! Status code:%X\n", *pStatusCode); | |
94a79942 LF |
392 | DeActivateBAEntry(ieee, pPendingBA); |
393 | } | |
394 | ||
395 | ||
831cb9db LF |
396 | if (*pStatusCode == ADDBA_STATUS_SUCCESS) { |
397 | if (pBaParamSet->field.BAPolicy == BA_POLICY_DELAYED) { | |
94a79942 LF |
398 | pTS->bAddBaReqDelayed = true; |
399 | DeActivateBAEntry(ieee, pAdmittedBA); | |
400 | ReasonCode = DELBA_REASON_END_BA; | |
401 | goto OnADDBARsp_Reject; | |
402 | } | |
403 | ||
404 | ||
405 | pAdmittedBA->DialogToken = *pDialogToken; | |
406 | pAdmittedBA->BaTimeoutValue = *pBaTimeoutVal; | |
407 | pAdmittedBA->BaStartSeqCtrl = pPendingBA->BaStartSeqCtrl; | |
408 | pAdmittedBA->BaParamSet = *pBaParamSet; | |
409 | DeActivateBAEntry(ieee, pAdmittedBA); | |
410 | ActivateBAEntry(ieee, pAdmittedBA, *pBaTimeoutVal); | |
411 | } else { | |
412 | pTS->bAddBaReqDelayed = true; | |
413 | pTS->bDisable_AddBa = true; | |
414 | ReasonCode = DELBA_REASON_END_BA; | |
415 | goto OnADDBARsp_Reject; | |
416 | } | |
417 | ||
418 | return 0; | |
419 | ||
420 | OnADDBARsp_Reject: | |
421 | { | |
8cf33316 | 422 | struct ba_record BA; |
3a6b70c3 | 423 | |
94a79942 LF |
424 | BA.BaParamSet = *pBaParamSet; |
425 | rtllib_send_DELBA(ieee, dst, &BA, TX_DIR, ReasonCode); | |
426 | return 0; | |
427 | } | |
94a79942 LF |
428 | } |
429 | ||
831cb9db | 430 | int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb) |
94a79942 | 431 | { |
831cb9db | 432 | struct rtllib_hdr_3addr *delba = NULL; |
f198db0c | 433 | union delba_param_set *pDelBaParamSet = NULL; |
831cb9db LF |
434 | u16 *pReasonCode = NULL; |
435 | u8 *dst = NULL; | |
94a79942 | 436 | |
831cb9db LF |
437 | if (skb->len < sizeof(struct rtllib_hdr_3addr) + 6) { |
438 | RTLLIB_DEBUG(RTLLIB_DL_ERR, " Invalid skb len in DELBA(%d /" | |
439 | " %d)\n", (int)skb->len, | |
440 | (int)(sizeof(struct rtllib_hdr_3addr) + 6)); | |
94a79942 LF |
441 | return -1; |
442 | } | |
443 | ||
831cb9db LF |
444 | if (ieee->current_network.qos_data.active == 0 || |
445 | ieee->pHTInfo->bCurrentHTSupport == false) { | |
446 | RTLLIB_DEBUG(RTLLIB_DL_ERR, "received DELBA while QOS or HT " | |
447 | "is not supported(%d, %d)\n", | |
448 | ieee->current_network. qos_data.active, | |
449 | ieee->pHTInfo->bCurrentHTSupport); | |
94a79942 LF |
450 | return -1; |
451 | } | |
452 | ||
453 | RTLLIB_DEBUG_DATA(RTLLIB_DL_DATA|RTLLIB_DL_BA, skb->data, skb->len); | |
831cb9db LF |
454 | delba = (struct rtllib_hdr_3addr *)skb->data; |
455 | dst = (u8 *)(&delba->addr2[0]); | |
456 | delba += sizeof(struct rtllib_hdr_3addr); | |
f198db0c | 457 | pDelBaParamSet = (union delba_param_set *)(delba+2); |
831cb9db | 458 | pReasonCode = (u16 *)(delba+4); |
94a79942 | 459 | |
831cb9db | 460 | if (pDelBaParamSet->field.Initiator == 1) { |
2c47ae28 | 461 | struct rx_ts_record *pRxTs; |
94a79942 | 462 | |
831cb9db LF |
463 | if (!GetTs(ieee, (struct ts_common_info **)&pRxTs, dst, |
464 | (u8)pDelBaParamSet->field.TID, RX_DIR, false)) { | |
465 | RTLLIB_DEBUG(RTLLIB_DL_ERR, "can't get TS for RXTS in " | |
ac50ddaa | 466 | "%s().dst: %pM TID:%d\n", __func__, dst, |
831cb9db | 467 | (u8)pDelBaParamSet->field.TID); |
94a79942 LF |
468 | return -1; |
469 | } | |
470 | ||
471 | RxTsDeleteBA(ieee, pRxTs); | |
831cb9db | 472 | } else { |
60554f2b | 473 | struct tx_ts_record *pTxTs; |
94a79942 | 474 | |
831cb9db LF |
475 | if (!GetTs(ieee, (struct ts_common_info **)&pTxTs, dst, |
476 | (u8)pDelBaParamSet->field.TID, TX_DIR, false)) { | |
477 | RTLLIB_DEBUG(RTLLIB_DL_ERR, "can't get TS for TXTS in " | |
478 | "%s()\n", __func__); | |
94a79942 LF |
479 | return -1; |
480 | } | |
481 | ||
482 | pTxTs->bUsingBa = false; | |
483 | pTxTs->bAddBaReqInProgress = false; | |
484 | pTxTs->bAddBaReqDelayed = false; | |
485 | del_timer_sync(&pTxTs->TsAddBaTimer); | |
486 | TxTsDeleteBA(ieee, pTxTs); | |
487 | } | |
488 | return 0; | |
489 | } | |
490 | ||
831cb9db LF |
491 | void TsInitAddBA(struct rtllib_device *ieee, struct tx_ts_record *pTS, |
492 | u8 Policy, u8 bOverwritePending) | |
94a79942 | 493 | { |
8cf33316 | 494 | struct ba_record *pBA = &pTS->TxPendingBARecord; |
94a79942 | 495 | |
831cb9db | 496 | if (pBA->bValid == true && bOverwritePending == false) |
94a79942 LF |
497 | return; |
498 | ||
499 | DeActivateBAEntry(ieee, pBA); | |
500 | ||
501 | pBA->DialogToken++; | |
502 | pBA->BaParamSet.field.AMSDU_Support = 0; | |
503 | pBA->BaParamSet.field.BAPolicy = Policy; | |
831cb9db LF |
504 | pBA->BaParamSet.field.TID = |
505 | pTS->TsCommonInfo.TSpec.f.TSInfo.field.ucTSID; | |
94a79942 LF |
506 | pBA->BaParamSet.field.BufferSize = 32; |
507 | pBA->BaTimeoutValue = 0; | |
508 | pBA->BaStartSeqCtrl.field.SeqNum = (pTS->TxCurSeq + 3) % 4096; | |
509 | ||
510 | ActivateBAEntry(ieee, pBA, BA_SETUP_TIMEOUT); | |
511 | ||
512 | rtllib_send_ADDBAReq(ieee, pTS->TsCommonInfo.Addr, pBA); | |
513 | } | |
514 | ||
831cb9db LF |
515 | void TsInitDelBA(struct rtllib_device *ieee, |
516 | struct ts_common_info *pTsCommonInfo, | |
517 | enum tr_select TxRxSelect) | |
94a79942 | 518 | { |
831cb9db LF |
519 | if (TxRxSelect == TX_DIR) { |
520 | struct tx_ts_record *pTxTs = | |
521 | (struct tx_ts_record *)pTsCommonInfo; | |
94a79942 LF |
522 | |
523 | if (TxTsDeleteBA(ieee, pTxTs)) | |
831cb9db LF |
524 | rtllib_send_DELBA(ieee, pTsCommonInfo->Addr, |
525 | (pTxTs->TxAdmittedBARecord.bValid) ? | |
526 | (&pTxTs->TxAdmittedBARecord) : | |
527 | (&pTxTs->TxPendingBARecord), | |
528 | TxRxSelect, DELBA_REASON_END_BA); | |
529 | } else if (TxRxSelect == RX_DIR) { | |
530 | struct rx_ts_record *pRxTs = | |
531 | (struct rx_ts_record *)pTsCommonInfo; | |
94a79942 | 532 | if (RxTsDeleteBA(ieee, pRxTs)) |
831cb9db LF |
533 | rtllib_send_DELBA(ieee, pTsCommonInfo->Addr, |
534 | &pRxTs->RxAdmittedBARecord, | |
535 | TxRxSelect, DELBA_REASON_END_BA); | |
94a79942 LF |
536 | } |
537 | } | |
831cb9db | 538 | |
94a79942 LF |
539 | void BaSetupTimeOut(unsigned long data) |
540 | { | |
60554f2b | 541 | struct tx_ts_record *pTxTs = (struct tx_ts_record *)data; |
94a79942 LF |
542 | |
543 | pTxTs->bAddBaReqInProgress = false; | |
544 | pTxTs->bAddBaReqDelayed = true; | |
545 | pTxTs->TxPendingBARecord.bValid = false; | |
546 | } | |
547 | ||
548 | void TxBaInactTimeout(unsigned long data) | |
549 | { | |
60554f2b | 550 | struct tx_ts_record *pTxTs = (struct tx_ts_record *)data; |
831cb9db LF |
551 | struct rtllib_device *ieee = container_of(pTxTs, struct rtllib_device, |
552 | TxTsRecord[pTxTs->num]); | |
94a79942 | 553 | TxTsDeleteBA(ieee, pTxTs); |
831cb9db LF |
554 | rtllib_send_DELBA(ieee, pTxTs->TsCommonInfo.Addr, |
555 | &pTxTs->TxAdmittedBARecord, TX_DIR, | |
556 | DELBA_REASON_TIMEOUT); | |
94a79942 LF |
557 | } |
558 | ||
559 | void RxBaInactTimeout(unsigned long data) | |
560 | { | |
2c47ae28 | 561 | struct rx_ts_record *pRxTs = (struct rx_ts_record *)data; |
831cb9db LF |
562 | struct rtllib_device *ieee = container_of(pRxTs, struct rtllib_device, |
563 | RxTsRecord[pRxTs->num]); | |
94a79942 LF |
564 | |
565 | RxTsDeleteBA(ieee, pRxTs); | |
831cb9db LF |
566 | rtllib_send_DELBA(ieee, pRxTs->TsCommonInfo.Addr, |
567 | &pRxTs->RxAdmittedBARecord, RX_DIR, | |
568 | DELBA_REASON_TIMEOUT); | |
94a79942 LF |
569 | return ; |
570 | } |