1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved. |
4 | * |
5 | * Contact Information: wlanfae <wlanfae@realtek.com> |
6 | */ |
7 | #include <asm/byteorder.h> |
8 | #include <asm/unaligned.h> |
9 | #include <linux/etherdevice.h> |
10 | #include "rtllib.h" |
11 | #include "rtl819x_BA.h" |
12 | |
13 | static void activate_ba_entry(struct ba_record *ba, u16 time) |
14 | { |
15 | ba->b_valid = true; |
16 | if (time != 0) |
17 | mod_timer(timer: &ba->timer, expires: jiffies + msecs_to_jiffies(m: time)); |
18 | } |
19 | |
20 | static void deactivate_ba_entry(struct rtllib_device *ieee, struct ba_record *ba) |
21 | { |
22 | ba->b_valid = false; |
23 | del_timer_sync(timer: &ba->timer); |
24 | } |
25 | |
26 | static u8 tx_ts_delete_ba(struct rtllib_device *ieee, struct tx_ts_record *pTxTs) |
27 | { |
28 | struct ba_record *admitted_ba = &pTxTs->TxAdmittedBARecord; |
29 | struct ba_record *pending_ba = &pTxTs->TxPendingBARecord; |
30 | u8 bSendDELBA = false; |
31 | |
32 | if (pending_ba->b_valid) { |
33 | deactivate_ba_entry(ieee, ba: pending_ba); |
34 | bSendDELBA = true; |
35 | } |
36 | |
37 | if (admitted_ba->b_valid) { |
38 | deactivate_ba_entry(ieee, ba: admitted_ba); |
39 | bSendDELBA = true; |
40 | } |
41 | return bSendDELBA; |
42 | } |
43 | |
44 | static u8 rx_ts_delete_ba(struct rtllib_device *ieee, struct rx_ts_record *ts) |
45 | { |
46 | struct ba_record *ba = &ts->rx_admitted_ba_record; |
47 | u8 bSendDELBA = false; |
48 | |
49 | if (ba->b_valid) { |
50 | deactivate_ba_entry(ieee, ba); |
51 | bSendDELBA = true; |
52 | } |
53 | |
54 | return bSendDELBA; |
55 | } |
56 | |
57 | void rtllib_reset_ba_entry(struct ba_record *ba) |
58 | { |
59 | ba->b_valid = false; |
60 | ba->ba_param_set.short_data = 0; |
61 | ba->ba_timeout_value = 0; |
62 | ba->dialog_token = 0; |
63 | ba->ba_start_seq_ctrl.short_data = 0; |
64 | } |
65 | |
66 | static struct sk_buff *rtllib_ADDBA(struct rtllib_device *ieee, u8 *dst, |
67 | struct ba_record *ba, |
68 | u16 status_code, u8 type) |
69 | { |
70 | struct sk_buff *skb = NULL; |
71 | struct ieee80211_hdr_3addr *BAReq = NULL; |
72 | u8 *tag = NULL; |
73 | u16 len = ieee->tx_headroom + 9; |
74 | |
75 | netdev_dbg(ieee->dev, "%s(): frame(%d) sentd to: %pM, ieee->dev:%p\n" , |
76 | __func__, type, dst, ieee->dev); |
77 | |
78 | if (!ba) { |
79 | netdev_warn(dev: ieee->dev, format: "ba is NULL\n" ); |
80 | return NULL; |
81 | } |
82 | skb = dev_alloc_skb(length: len + sizeof(struct ieee80211_hdr_3addr)); |
83 | if (!skb) |
84 | return NULL; |
85 | |
86 | memset(skb->data, 0, sizeof(struct ieee80211_hdr_3addr)); |
87 | |
88 | skb_reserve(skb, len: ieee->tx_headroom); |
89 | |
90 | BAReq = skb_put(skb, len: sizeof(struct ieee80211_hdr_3addr)); |
91 | |
92 | ether_addr_copy(dst: BAReq->addr1, src: dst); |
93 | ether_addr_copy(dst: BAReq->addr2, src: ieee->dev->dev_addr); |
94 | |
95 | ether_addr_copy(dst: BAReq->addr3, src: ieee->current_network.bssid); |
96 | BAReq->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION); |
97 | |
98 | tag = skb_put(skb, len: 9); |
99 | *tag++ = ACT_CAT_BA; |
100 | *tag++ = type; |
101 | *tag++ = ba->dialog_token; |
102 | |
103 | if (type == ACT_ADDBARSP) { |
104 | put_unaligned_le16(val: status_code, p: tag); |
105 | tag += 2; |
106 | } |
107 | |
108 | put_unaligned_le16(val: ba->ba_param_set.short_data, p: tag); |
109 | tag += 2; |
110 | |
111 | put_unaligned_le16(val: ba->ba_timeout_value, p: tag); |
112 | tag += 2; |
113 | |
114 | if (type == ACT_ADDBAREQ) { |
115 | memcpy(tag, (u8 *)&ba->ba_start_seq_ctrl, 2); |
116 | tag += 2; |
117 | } |
118 | |
119 | #ifdef VERBOSE_DEBUG |
120 | print_hex_dump_bytes("%s: " , DUMP_PREFIX_NONE, skb->data, |
121 | __func__, skb->len); |
122 | #endif |
123 | return skb; |
124 | } |
125 | |
126 | static struct sk_buff *rtllib_DELBA(struct rtllib_device *ieee, u8 *dst, |
127 | struct ba_record *ba, |
128 | enum tr_select TxRxSelect, u16 reason_code) |
129 | { |
130 | union delba_param_set DelbaParamSet; |
131 | struct sk_buff *skb = NULL; |
132 | struct ieee80211_hdr_3addr *Delba = NULL; |
133 | u8 *tag = NULL; |
134 | u16 len = 6 + ieee->tx_headroom; |
135 | |
136 | if (net_ratelimit()) |
137 | netdev_dbg(ieee->dev, "%s(): reason_code(%d) sentd to: %pM\n" , |
138 | __func__, reason_code, dst); |
139 | |
140 | memset(&DelbaParamSet, 0, 2); |
141 | |
142 | DelbaParamSet.field.initiator = (TxRxSelect == TX_DIR) ? 1 : 0; |
143 | DelbaParamSet.field.tid = ba->ba_param_set.field.tid; |
144 | |
145 | skb = dev_alloc_skb(length: len + sizeof(struct ieee80211_hdr_3addr)); |
146 | if (!skb) |
147 | return NULL; |
148 | |
149 | skb_reserve(skb, len: ieee->tx_headroom); |
150 | |
151 | Delba = skb_put(skb, len: sizeof(struct ieee80211_hdr_3addr)); |
152 | |
153 | ether_addr_copy(dst: Delba->addr1, src: dst); |
154 | ether_addr_copy(dst: Delba->addr2, src: ieee->dev->dev_addr); |
155 | ether_addr_copy(dst: Delba->addr3, src: ieee->current_network.bssid); |
156 | Delba->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION); |
157 | |
158 | tag = skb_put(skb, len: 6); |
159 | |
160 | *tag++ = ACT_CAT_BA; |
161 | *tag++ = ACT_DELBA; |
162 | |
163 | put_unaligned_le16(val: DelbaParamSet.short_data, p: tag); |
164 | tag += 2; |
165 | |
166 | put_unaligned_le16(val: reason_code, p: tag); |
167 | tag += 2; |
168 | |
169 | #ifdef VERBOSE_DEBUG |
170 | print_hex_dump_bytes("%s: " , DUMP_PREFIX_NONE, skb->data, |
171 | __func__, skb->len); |
172 | #endif |
173 | return skb; |
174 | } |
175 | |
176 | static void rtllib_send_ADDBAReq(struct rtllib_device *ieee, u8 *dst, |
177 | struct ba_record *ba) |
178 | { |
179 | struct sk_buff *skb; |
180 | |
181 | skb = rtllib_ADDBA(ieee, dst, ba, status_code: 0, type: ACT_ADDBAREQ); |
182 | |
183 | if (skb) |
184 | softmac_mgmt_xmit(skb, ieee); |
185 | else |
186 | netdev_dbg(ieee->dev, "Failed to generate ADDBAReq packet.\n" ); |
187 | } |
188 | |
189 | static void rtllib_send_ADDBARsp(struct rtllib_device *ieee, u8 *dst, |
190 | struct ba_record *ba, u16 status_code) |
191 | { |
192 | struct sk_buff *skb; |
193 | |
194 | skb = rtllib_ADDBA(ieee, dst, ba, status_code, type: ACT_ADDBARSP); |
195 | if (skb) |
196 | softmac_mgmt_xmit(skb, ieee); |
197 | else |
198 | netdev_dbg(ieee->dev, "Failed to generate ADDBARsp packet.\n" ); |
199 | } |
200 | |
201 | static void rtllib_send_DELBA(struct rtllib_device *ieee, u8 *dst, |
202 | struct ba_record *ba, enum tr_select TxRxSelect, |
203 | u16 reason_code) |
204 | { |
205 | struct sk_buff *skb; |
206 | |
207 | skb = rtllib_DELBA(ieee, dst, ba, TxRxSelect, reason_code); |
208 | if (skb) |
209 | softmac_mgmt_xmit(skb, ieee); |
210 | else |
211 | netdev_dbg(ieee->dev, "Failed to generate DELBA packet.\n" ); |
212 | } |
213 | |
214 | int rtllib_rx_ADDBAReq(struct rtllib_device *ieee, struct sk_buff *skb) |
215 | { |
216 | struct ieee80211_hdr_3addr *req = NULL; |
217 | u16 rc = 0; |
218 | u8 *dst = NULL, *pDialogToken = NULL, *tag = NULL; |
219 | struct ba_record *ba = NULL; |
220 | union ba_param_set *pBaParamSet = NULL; |
221 | u16 *pBaTimeoutVal = NULL; |
222 | union sequence_control *pBaStartSeqCtrl = NULL; |
223 | struct rx_ts_record *ts = NULL; |
224 | |
225 | if (skb->len < sizeof(struct ieee80211_hdr_3addr) + 9) { |
226 | netdev_warn(dev: ieee->dev, format: "Invalid skb len in BAREQ(%d / %d)\n" , |
227 | (int)skb->len, |
228 | (int)(sizeof(struct ieee80211_hdr_3addr) + 9)); |
229 | return -1; |
230 | } |
231 | |
232 | #ifdef VERBOSE_DEBUG |
233 | print_hex_dump_bytes("%s: " , DUMP_PREFIX_NONE, __func__, |
234 | skb->data, skb->len); |
235 | #endif |
236 | |
237 | req = (struct ieee80211_hdr_3addr *)skb->data; |
238 | tag = (u8 *)req; |
239 | dst = (u8 *)(&req->addr2[0]); |
240 | tag += sizeof(struct ieee80211_hdr_3addr); |
241 | pDialogToken = tag + 2; |
242 | pBaParamSet = (union ba_param_set *)(tag + 3); |
243 | pBaTimeoutVal = (u16 *)(tag + 5); |
244 | pBaStartSeqCtrl = (union sequence_control *)(req + 7); |
245 | |
246 | if (!ieee->current_network.qos_data.active || |
247 | !ieee->ht_info->current_ht_support || |
248 | (ieee->ht_info->iot_action & HT_IOT_ACT_REJECT_ADDBA_REQ)) { |
249 | rc = ADDBA_STATUS_REFUSED; |
250 | netdev_warn(dev: ieee->dev, |
251 | format: "Failed to reply on ADDBA_REQ as some capability is not ready(%d, %d)\n" , |
252 | ieee->current_network.qos_data.active, |
253 | ieee->ht_info->current_ht_support); |
254 | goto OnADDBAReq_Fail; |
255 | } |
256 | if (!rtllib_get_ts(ieee, ppTS: (struct ts_common_info **)&ts, addr: dst, |
257 | TID: (u8)(pBaParamSet->field.tid), TxRxSelect: RX_DIR, bAddNewTs: true)) { |
258 | rc = ADDBA_STATUS_REFUSED; |
259 | netdev_warn(dev: ieee->dev, format: "%s(): can't get TS\n" , __func__); |
260 | goto OnADDBAReq_Fail; |
261 | } |
262 | ba = &ts->rx_admitted_ba_record; |
263 | |
264 | if (pBaParamSet->field.ba_policy == BA_POLICY_DELAYED) { |
265 | rc = ADDBA_STATUS_INVALID_PARAM; |
266 | netdev_warn(dev: ieee->dev, format: "%s(): BA Policy is not correct\n" , |
267 | __func__); |
268 | goto OnADDBAReq_Fail; |
269 | } |
270 | |
271 | rtllib_FlushRxTsPendingPkts(ieee, ts); |
272 | |
273 | deactivate_ba_entry(ieee, ba); |
274 | ba->dialog_token = *pDialogToken; |
275 | ba->ba_param_set = *pBaParamSet; |
276 | ba->ba_timeout_value = *pBaTimeoutVal; |
277 | ba->ba_start_seq_ctrl = *pBaStartSeqCtrl; |
278 | |
279 | if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev) || |
280 | (ieee->ht_info->iot_action & HT_IOT_ACT_ALLOW_PEER_AGG_ONE_PKT)) |
281 | ba->ba_param_set.field.buffer_size = 1; |
282 | else |
283 | ba->ba_param_set.field.buffer_size = 32; |
284 | |
285 | activate_ba_entry(ba, time: 0); |
286 | rtllib_send_ADDBARsp(ieee, dst, ba, ADDBA_STATUS_SUCCESS); |
287 | |
288 | return 0; |
289 | |
290 | OnADDBAReq_Fail: |
291 | { |
292 | struct ba_record BA; |
293 | |
294 | BA.ba_param_set = *pBaParamSet; |
295 | BA.ba_timeout_value = *pBaTimeoutVal; |
296 | BA.dialog_token = *pDialogToken; |
297 | BA.ba_param_set.field.ba_policy = BA_POLICY_IMMEDIATE; |
298 | rtllib_send_ADDBARsp(ieee, dst, ba: &BA, status_code: rc); |
299 | return 0; |
300 | } |
301 | } |
302 | |
303 | int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb) |
304 | { |
305 | struct ieee80211_hdr_3addr *rsp = NULL; |
306 | struct ba_record *pending_ba, *pAdmittedBA; |
307 | struct tx_ts_record *ts = NULL; |
308 | u8 *dst = NULL, *pDialogToken = NULL, *tag = NULL; |
309 | u16 *status_code = NULL, *pBaTimeoutVal = NULL; |
310 | union ba_param_set *pBaParamSet = NULL; |
311 | u16 reason_code; |
312 | |
313 | if (skb->len < sizeof(struct ieee80211_hdr_3addr) + 9) { |
314 | netdev_warn(dev: ieee->dev, format: "Invalid skb len in BARSP(%d / %d)\n" , |
315 | (int)skb->len, |
316 | (int)(sizeof(struct ieee80211_hdr_3addr) + 9)); |
317 | return -1; |
318 | } |
319 | rsp = (struct ieee80211_hdr_3addr *)skb->data; |
320 | tag = (u8 *)rsp; |
321 | dst = (u8 *)(&rsp->addr2[0]); |
322 | tag += sizeof(struct ieee80211_hdr_3addr); |
323 | pDialogToken = tag + 2; |
324 | status_code = (u16 *)(tag + 3); |
325 | pBaParamSet = (union ba_param_set *)(tag + 5); |
326 | pBaTimeoutVal = (u16 *)(tag + 7); |
327 | |
328 | if (!ieee->current_network.qos_data.active || |
329 | !ieee->ht_info->current_ht_support || |
330 | !ieee->ht_info->bCurrentAMPDUEnable) { |
331 | netdev_warn(dev: ieee->dev, |
332 | format: "reject to ADDBA_RSP as some capability is not ready(%d, %d, %d)\n" , |
333 | ieee->current_network.qos_data.active, |
334 | ieee->ht_info->current_ht_support, |
335 | ieee->ht_info->bCurrentAMPDUEnable); |
336 | reason_code = DELBA_REASON_UNKNOWN_BA; |
337 | goto OnADDBARsp_Reject; |
338 | } |
339 | |
340 | if (!rtllib_get_ts(ieee, ppTS: (struct ts_common_info **)&ts, addr: dst, |
341 | TID: (u8)(pBaParamSet->field.tid), TxRxSelect: TX_DIR, bAddNewTs: false)) { |
342 | netdev_warn(dev: ieee->dev, format: "%s(): can't get TS\n" , __func__); |
343 | reason_code = DELBA_REASON_UNKNOWN_BA; |
344 | goto OnADDBARsp_Reject; |
345 | } |
346 | |
347 | ts->bAddBaReqInProgress = false; |
348 | pending_ba = &ts->TxPendingBARecord; |
349 | pAdmittedBA = &ts->TxAdmittedBARecord; |
350 | |
351 | if (pAdmittedBA->b_valid) { |
352 | netdev_dbg(ieee->dev, "%s(): ADDBA response already admitted\n" , |
353 | __func__); |
354 | return -1; |
355 | } else if (!pending_ba->b_valid || |
356 | (*pDialogToken != pending_ba->dialog_token)) { |
357 | netdev_warn(dev: ieee->dev, |
358 | format: "%s(): ADDBA Rsp. BA invalid, DELBA!\n" , |
359 | __func__); |
360 | reason_code = DELBA_REASON_UNKNOWN_BA; |
361 | goto OnADDBARsp_Reject; |
362 | } else { |
363 | netdev_dbg(ieee->dev, |
364 | "%s(): Recv ADDBA Rsp. BA is admitted! Status code:%X\n" , |
365 | __func__, *status_code); |
366 | deactivate_ba_entry(ieee, ba: pending_ba); |
367 | } |
368 | |
369 | if (*status_code == ADDBA_STATUS_SUCCESS) { |
370 | if (pBaParamSet->field.ba_policy == BA_POLICY_DELAYED) { |
371 | ts->bAddBaReqDelayed = true; |
372 | deactivate_ba_entry(ieee, ba: pAdmittedBA); |
373 | reason_code = DELBA_REASON_END_BA; |
374 | goto OnADDBARsp_Reject; |
375 | } |
376 | |
377 | pAdmittedBA->dialog_token = *pDialogToken; |
378 | pAdmittedBA->ba_timeout_value = *pBaTimeoutVal; |
379 | pAdmittedBA->ba_start_seq_ctrl = pending_ba->ba_start_seq_ctrl; |
380 | pAdmittedBA->ba_param_set = *pBaParamSet; |
381 | deactivate_ba_entry(ieee, ba: pAdmittedBA); |
382 | activate_ba_entry(ba: pAdmittedBA, time: *pBaTimeoutVal); |
383 | } else { |
384 | ts->bAddBaReqDelayed = true; |
385 | ts->bDisable_AddBa = true; |
386 | reason_code = DELBA_REASON_END_BA; |
387 | goto OnADDBARsp_Reject; |
388 | } |
389 | |
390 | return 0; |
391 | |
392 | OnADDBARsp_Reject: |
393 | { |
394 | struct ba_record BA; |
395 | |
396 | BA.ba_param_set = *pBaParamSet; |
397 | rtllib_send_DELBA(ieee, dst, ba: &BA, TxRxSelect: TX_DIR, reason_code); |
398 | return 0; |
399 | } |
400 | } |
401 | |
402 | int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb) |
403 | { |
404 | struct ieee80211_hdr_3addr *delba = NULL; |
405 | union delba_param_set *pDelBaParamSet = NULL; |
406 | u8 *dst = NULL; |
407 | |
408 | if (skb->len < sizeof(struct ieee80211_hdr_3addr) + 6) { |
409 | netdev_warn(dev: ieee->dev, format: "Invalid skb len in DELBA(%d / %d)\n" , |
410 | (int)skb->len, |
411 | (int)(sizeof(struct ieee80211_hdr_3addr) + 6)); |
412 | return -1; |
413 | } |
414 | |
415 | if (!ieee->current_network.qos_data.active || |
416 | !ieee->ht_info->current_ht_support) { |
417 | netdev_warn(dev: ieee->dev, |
418 | format: "received DELBA while QOS or HT is not supported(%d, %d)\n" , |
419 | ieee->current_network. qos_data.active, |
420 | ieee->ht_info->current_ht_support); |
421 | return -1; |
422 | } |
423 | |
424 | #ifdef VERBOSE_DEBUG |
425 | print_hex_dump_bytes("%s: " , DUMP_PREFIX_NONE, skb->data, |
426 | __func__, skb->len); |
427 | #endif |
428 | delba = (struct ieee80211_hdr_3addr *)skb->data; |
429 | dst = (u8 *)(&delba->addr2[0]); |
430 | pDelBaParamSet = (union delba_param_set *)&delba->seq_ctrl + 2; |
431 | |
432 | if (pDelBaParamSet->field.initiator == 1) { |
433 | struct rx_ts_record *ts; |
434 | |
435 | if (!rtllib_get_ts(ieee, ppTS: (struct ts_common_info **)&ts, addr: dst, |
436 | TID: (u8)pDelBaParamSet->field.tid, TxRxSelect: RX_DIR, bAddNewTs: false)) { |
437 | netdev_warn(dev: ieee->dev, |
438 | format: "%s(): can't get TS for RXTS. dst:%pM TID:%d\n" , |
439 | __func__, dst, |
440 | (u8)pDelBaParamSet->field.tid); |
441 | return -1; |
442 | } |
443 | |
444 | rx_ts_delete_ba(ieee, ts); |
445 | } else { |
446 | struct tx_ts_record *pTxTs; |
447 | |
448 | if (!rtllib_get_ts(ieee, ppTS: (struct ts_common_info **)&pTxTs, addr: dst, |
449 | TID: (u8)pDelBaParamSet->field.tid, TxRxSelect: TX_DIR, bAddNewTs: false)) { |
450 | netdev_warn(dev: ieee->dev, format: "%s(): can't get TS for TXTS\n" , |
451 | __func__); |
452 | return -1; |
453 | } |
454 | |
455 | pTxTs->bUsingBa = false; |
456 | pTxTs->bAddBaReqInProgress = false; |
457 | pTxTs->bAddBaReqDelayed = false; |
458 | del_timer_sync(timer: &pTxTs->TsAddBaTimer); |
459 | tx_ts_delete_ba(ieee, pTxTs); |
460 | } |
461 | return 0; |
462 | } |
463 | |
464 | void rtllib_ts_init_add_ba(struct rtllib_device *ieee, struct tx_ts_record *ts, |
465 | u8 policy, u8 bOverwritePending) |
466 | { |
467 | struct ba_record *ba = &ts->TxPendingBARecord; |
468 | |
469 | if (ba->b_valid && !bOverwritePending) |
470 | return; |
471 | |
472 | deactivate_ba_entry(ieee, ba); |
473 | |
474 | ba->dialog_token++; |
475 | ba->ba_param_set.field.amsdu_support = 0; |
476 | ba->ba_param_set.field.ba_policy = policy; |
477 | ba->ba_param_set.field.tid = ts->TsCommonInfo.TSpec.ucTSID; |
478 | ba->ba_param_set.field.buffer_size = 32; |
479 | ba->ba_timeout_value = 0; |
480 | ba->ba_start_seq_ctrl.field.seq_num = (ts->TxCurSeq + 3) % 4096; |
481 | |
482 | activate_ba_entry(ba, BA_SETUP_TIMEOUT); |
483 | |
484 | rtllib_send_ADDBAReq(ieee, dst: ts->TsCommonInfo.addr, ba); |
485 | } |
486 | |
487 | void rtllib_ts_init_del_ba(struct rtllib_device *ieee, |
488 | struct ts_common_info *pTsCommonInfo, |
489 | enum tr_select TxRxSelect) |
490 | { |
491 | if (TxRxSelect == TX_DIR) { |
492 | struct tx_ts_record *pTxTs = |
493 | (struct tx_ts_record *)pTsCommonInfo; |
494 | |
495 | if (tx_ts_delete_ba(ieee, pTxTs)) |
496 | rtllib_send_DELBA(ieee, dst: pTsCommonInfo->addr, |
497 | ba: (pTxTs->TxAdmittedBARecord.b_valid) ? |
498 | (&pTxTs->TxAdmittedBARecord) : |
499 | (&pTxTs->TxPendingBARecord), |
500 | TxRxSelect, DELBA_REASON_END_BA); |
501 | } else if (TxRxSelect == RX_DIR) { |
502 | struct rx_ts_record *ts = |
503 | (struct rx_ts_record *)pTsCommonInfo; |
504 | if (rx_ts_delete_ba(ieee, ts)) |
505 | rtllib_send_DELBA(ieee, dst: pTsCommonInfo->addr, |
506 | ba: &ts->rx_admitted_ba_record, |
507 | TxRxSelect, DELBA_REASON_END_BA); |
508 | } |
509 | } |
510 | |
511 | void rtllib_ba_setup_timeout(struct timer_list *t) |
512 | { |
513 | struct tx_ts_record *pTxTs = from_timer(pTxTs, t, |
514 | TxPendingBARecord.timer); |
515 | |
516 | pTxTs->bAddBaReqInProgress = false; |
517 | pTxTs->bAddBaReqDelayed = true; |
518 | pTxTs->TxPendingBARecord.b_valid = false; |
519 | } |
520 | |
521 | void rtllib_tx_ba_inact_timeout(struct timer_list *t) |
522 | { |
523 | struct tx_ts_record *pTxTs = from_timer(pTxTs, t, |
524 | TxAdmittedBARecord.timer); |
525 | struct rtllib_device *ieee = container_of(pTxTs, struct rtllib_device, |
526 | TxTsRecord[pTxTs->num]); |
527 | tx_ts_delete_ba(ieee, pTxTs); |
528 | rtllib_send_DELBA(ieee, dst: pTxTs->TsCommonInfo.addr, |
529 | ba: &pTxTs->TxAdmittedBARecord, TxRxSelect: TX_DIR, |
530 | DELBA_REASON_TIMEOUT); |
531 | } |
532 | |
533 | void rtllib_rx_ba_inact_timeout(struct timer_list *t) |
534 | { |
535 | struct rx_ts_record *ts = from_timer(ts, t, |
536 | rx_admitted_ba_record.timer); |
537 | struct rtllib_device *ieee = container_of(ts, struct rtllib_device, |
538 | RxTsRecord[ts->num]); |
539 | |
540 | rx_ts_delete_ba(ieee, ts); |
541 | rtllib_send_DELBA(ieee, dst: ts->ts_common_info.addr, |
542 | ba: &ts->rx_admitted_ba_record, TxRxSelect: RX_DIR, |
543 | DELBA_REASON_TIMEOUT); |
544 | } |
545 | |