Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/mac80211/agg-rx.c
49639 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* HT handling
4
*
5
* Copyright 2003, Jouni Malinen <[email protected]>
6
* Copyright 2002-2005, Instant802 Networks, Inc.
7
* Copyright 2005-2006, Devicescape Software, Inc.
8
* Copyright 2006-2007 Jiri Benc <[email protected]>
9
* Copyright 2007, Michael Wu <[email protected]>
10
* Copyright 2007-2010, Intel Corporation
11
* Copyright(c) 2015-2017 Intel Deutschland GmbH
12
* Copyright (C) 2018-2025 Intel Corporation
13
*/
14
15
/**
16
* DOC: RX A-MPDU aggregation
17
*
18
* Aggregation on the RX side requires only implementing the
19
* @ampdu_action callback that is invoked to start/stop any
20
* block-ack sessions for RX aggregation.
21
*
22
* When RX aggregation is started by the peer, the driver is
23
* notified via @ampdu_action function, with the
24
* %IEEE80211_AMPDU_RX_START action, and may reject the request
25
* in which case a negative response is sent to the peer, if it
26
* accepts it a positive response is sent.
27
*
28
* While the session is active, the device/driver are required
29
* to de-aggregate frames and pass them up one by one to mac80211,
30
* which will handle the reorder buffer.
31
*
32
* When the aggregation session is stopped again by the peer or
33
* ourselves, the driver's @ampdu_action function will be called
34
* with the action %IEEE80211_AMPDU_RX_STOP. In this case, the
35
* call must not fail.
36
*/
37
38
#include <linux/ieee80211.h>
39
#include <linux/slab.h>
40
#include <linux/export.h>
41
#include <net/mac80211.h>
42
#include "ieee80211_i.h"
43
#include "driver-ops.h"
44
45
static void ieee80211_free_tid_rx(struct rcu_head *h)
46
{
47
struct tid_ampdu_rx *tid_rx =
48
container_of(h, struct tid_ampdu_rx, rcu_head);
49
int i;
50
51
for (i = 0; i < tid_rx->buf_size; i++)
52
__skb_queue_purge(&tid_rx->reorder_buf[i]);
53
kfree(tid_rx->reorder_buf);
54
kfree(tid_rx->reorder_time);
55
kfree(tid_rx);
56
}
57
58
void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
59
u16 initiator, u16 reason, bool tx)
60
{
61
struct ieee80211_local *local = sta->local;
62
struct tid_ampdu_rx *tid_rx;
63
struct ieee80211_ampdu_params params = {
64
.sta = &sta->sta,
65
.action = IEEE80211_AMPDU_RX_STOP,
66
.tid = tid,
67
.amsdu = false,
68
.timeout = 0,
69
.ssn = 0,
70
};
71
72
lockdep_assert_wiphy(sta->local->hw.wiphy);
73
74
tid_rx = rcu_dereference_protected(sta->ampdu_mlme.tid_rx[tid],
75
lockdep_is_held(&sta->local->hw.wiphy->mtx));
76
77
if (!test_bit(tid, sta->ampdu_mlme.agg_session_valid))
78
return;
79
80
RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL);
81
__clear_bit(tid, sta->ampdu_mlme.agg_session_valid);
82
83
ht_dbg(sta->sdata,
84
"Rx BA session stop requested for %pM tid %u %s reason: %d\n",
85
sta->sta.addr, tid,
86
initiator == WLAN_BACK_RECIPIENT ? "recipient" : "initiator",
87
(int)reason);
88
89
if (drv_ampdu_action(local, sta->sdata, &params))
90
sdata_info(sta->sdata,
91
"HW problem - can not stop rx aggregation for %pM tid %d\n",
92
sta->sta.addr, tid);
93
94
/* check if this is a self generated aggregation halt */
95
if (initiator == WLAN_BACK_RECIPIENT && tx)
96
ieee80211_send_delba(sta->sdata, sta->sta.addr,
97
tid, WLAN_BACK_RECIPIENT, reason);
98
99
/*
100
* return here in case tid_rx is not assigned - which will happen if
101
* IEEE80211_HW_SUPPORTS_REORDERING_BUFFER is set.
102
*/
103
if (!tid_rx)
104
return;
105
106
timer_delete_sync(&tid_rx->session_timer);
107
108
/* make sure ieee80211_sta_reorder_release() doesn't re-arm the timer */
109
spin_lock_bh(&tid_rx->reorder_lock);
110
tid_rx->removed = true;
111
spin_unlock_bh(&tid_rx->reorder_lock);
112
timer_delete_sync(&tid_rx->reorder_timer);
113
114
call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx);
115
}
116
117
void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap,
118
const u8 *addr)
119
{
120
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
121
struct sta_info *sta;
122
int i;
123
124
rcu_read_lock();
125
sta = sta_info_get_bss(sdata, addr);
126
if (!sta) {
127
rcu_read_unlock();
128
return;
129
}
130
131
for (i = 0; i < IEEE80211_NUM_TIDS; i++)
132
if (ba_rx_bitmap & BIT(i))
133
set_bit(i, sta->ampdu_mlme.tid_rx_stop_requested);
134
135
wiphy_work_queue(sta->local->hw.wiphy, &sta->ampdu_mlme.work);
136
rcu_read_unlock();
137
}
138
EXPORT_SYMBOL(ieee80211_stop_rx_ba_session);
139
140
/*
141
* After accepting the AddBA Request we activated a timer,
142
* resetting it after each frame that arrives from the originator.
143
*/
144
static void sta_rx_agg_session_timer_expired(struct timer_list *t)
145
{
146
struct tid_ampdu_rx *tid_rx = timer_container_of(tid_rx, t,
147
session_timer);
148
struct sta_info *sta = tid_rx->sta;
149
u8 tid = tid_rx->tid;
150
unsigned long timeout;
151
152
timeout = tid_rx->last_rx + TU_TO_JIFFIES(tid_rx->timeout);
153
if (time_is_after_jiffies(timeout)) {
154
mod_timer(&tid_rx->session_timer, timeout);
155
return;
156
}
157
158
ht_dbg(sta->sdata, "RX session timer expired on %pM tid %d\n",
159
sta->sta.addr, tid);
160
161
set_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired);
162
wiphy_work_queue(sta->local->hw.wiphy, &sta->ampdu_mlme.work);
163
}
164
165
static void sta_rx_agg_reorder_timer_expired(struct timer_list *t)
166
{
167
struct tid_ampdu_rx *tid_rx = timer_container_of(tid_rx, t,
168
reorder_timer);
169
170
rcu_read_lock();
171
ieee80211_release_reorder_timeout(tid_rx->sta, tid_rx->tid);
172
rcu_read_unlock();
173
}
174
175
void ieee80211_add_addbaext(struct sk_buff *skb,
176
const u8 req_addba_ext_data,
177
u16 buf_size)
178
{
179
struct ieee80211_addba_ext_ie *addba_ext;
180
u8 *pos;
181
182
pos = skb_put_zero(skb, 2 + sizeof(struct ieee80211_addba_ext_ie));
183
*pos++ = WLAN_EID_ADDBA_EXT;
184
*pos++ = sizeof(struct ieee80211_addba_ext_ie);
185
addba_ext = (struct ieee80211_addba_ext_ie *)pos;
186
187
addba_ext->data = IEEE80211_ADDBA_EXT_NO_FRAG;
188
if (req_addba_ext_data)
189
addba_ext->data &= req_addba_ext_data;
190
191
addba_ext->data |=
192
u8_encode_bits(buf_size >> IEEE80211_ADDBA_EXT_BUF_SIZE_SHIFT,
193
IEEE80211_ADDBA_EXT_BUF_SIZE_MASK);
194
}
195
196
u8 ieee80211_retrieve_addba_ext_data(struct sta_info *sta,
197
const void *elem_data, ssize_t elem_len,
198
u16 *buf_size)
199
{
200
struct ieee802_11_elems *elems;
201
u8 buf_size_1k, data = 0;
202
203
if (!sta->sta.deflink.he_cap.has_he)
204
return 0;
205
206
if (elem_len <= 0)
207
return 0;
208
209
elems = ieee802_11_parse_elems(elem_data, elem_len,
210
IEEE80211_FTYPE_MGMT |
211
IEEE80211_STYPE_ACTION,
212
NULL);
213
214
if (!elems || elems->parse_error || !elems->addba_ext_ie)
215
goto free;
216
217
data = elems->addba_ext_ie->data;
218
219
if (buf_size &&
220
(sta->sta.valid_links || sta->sta.deflink.eht_cap.has_eht)) {
221
buf_size_1k = u8_get_bits(elems->addba_ext_ie->data,
222
IEEE80211_ADDBA_EXT_BUF_SIZE_MASK);
223
*buf_size |= (u16)buf_size_1k <<
224
IEEE80211_ADDBA_EXT_BUF_SIZE_SHIFT;
225
}
226
227
free:
228
kfree(elems);
229
230
return data;
231
}
232
233
static void ieee80211_send_addba_resp(struct sta_info *sta, u8 *da, u16 tid,
234
u8 dialog_token, u16 status, u16 policy,
235
u16 buf_size, u16 timeout,
236
const u8 req_addba_ext_data)
237
{
238
struct ieee80211_sub_if_data *sdata = sta->sdata;
239
struct ieee80211_local *local = sdata->local;
240
struct sk_buff *skb;
241
struct ieee80211_mgmt *mgmt;
242
bool amsdu = ieee80211_hw_check(&local->hw, SUPPORTS_AMSDU_IN_AMPDU);
243
u16 capab;
244
245
skb = dev_alloc_skb(sizeof(*mgmt) +
246
2 + sizeof(struct ieee80211_addba_ext_ie) +
247
local->hw.extra_tx_headroom);
248
if (!skb)
249
return;
250
251
skb_reserve(skb, local->hw.extra_tx_headroom);
252
mgmt = ieee80211_mgmt_ba(skb, da, sdata);
253
254
skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
255
mgmt->u.action.category = WLAN_CATEGORY_BACK;
256
mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
257
mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
258
259
capab = u16_encode_bits(amsdu, IEEE80211_ADDBA_PARAM_AMSDU_MASK);
260
capab |= u16_encode_bits(policy, IEEE80211_ADDBA_PARAM_POLICY_MASK);
261
capab |= u16_encode_bits(tid, IEEE80211_ADDBA_PARAM_TID_MASK);
262
capab |= u16_encode_bits(buf_size, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK);
263
264
mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
265
mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
266
mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
267
268
if (sta->sta.valid_links || sta->sta.deflink.he_cap.has_he)
269
ieee80211_add_addbaext(skb, req_addba_ext_data, buf_size);
270
271
ieee80211_tx_skb(sdata, skb);
272
}
273
274
void __ieee80211_start_rx_ba_session(struct sta_info *sta,
275
u8 dialog_token, u16 timeout,
276
u16 start_seq_num, u16 ba_policy, u16 tid,
277
u16 buf_size, bool tx, bool auto_seq,
278
const u8 addba_ext_data)
279
{
280
struct ieee80211_local *local = sta->sdata->local;
281
struct tid_ampdu_rx *tid_agg_rx;
282
struct ieee80211_ampdu_params params = {
283
.sta = &sta->sta,
284
.action = IEEE80211_AMPDU_RX_START,
285
.tid = tid,
286
.amsdu = false,
287
.timeout = timeout,
288
.ssn = start_seq_num,
289
};
290
int i, ret = -EOPNOTSUPP;
291
u16 status = WLAN_STATUS_REQUEST_DECLINED;
292
u16 max_buf_size;
293
294
lockdep_assert_wiphy(sta->local->hw.wiphy);
295
296
if (tid >= IEEE80211_FIRST_TSPEC_TSID) {
297
ht_dbg(sta->sdata,
298
"STA %pM requests BA session on unsupported tid %d\n",
299
sta->sta.addr, tid);
300
goto end;
301
}
302
303
if (!sta->sta.valid_links &&
304
!sta->sta.deflink.ht_cap.ht_supported &&
305
!sta->sta.deflink.he_cap.has_he &&
306
!sta->sta.deflink.s1g_cap.s1g) {
307
ht_dbg(sta->sdata,
308
"STA %pM erroneously requests BA session on tid %d w/o HT\n",
309
sta->sta.addr, tid);
310
/* send a response anyway, it's an error case if we get here */
311
goto end;
312
}
313
314
if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
315
ht_dbg(sta->sdata,
316
"Suspend in progress - Denying ADDBA request (%pM tid %d)\n",
317
sta->sta.addr, tid);
318
goto end;
319
}
320
321
if (sta->sta.valid_links || sta->sta.deflink.eht_cap.has_eht)
322
max_buf_size = IEEE80211_MAX_AMPDU_BUF_EHT;
323
else if (sta->sta.deflink.he_cap.has_he)
324
max_buf_size = IEEE80211_MAX_AMPDU_BUF_HE;
325
else
326
max_buf_size = IEEE80211_MAX_AMPDU_BUF_HT;
327
328
/* sanity check for incoming parameters:
329
* check if configuration can support the BA policy
330
* and if buffer size does not exceeds max value */
331
/* XXX: check own ht delayed BA capability?? */
332
if (((ba_policy != 1) &&
333
(sta->sta.valid_links ||
334
!(sta->sta.deflink.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA) ||
335
!(sta->sta.deflink.s1g_cap.cap[3] & S1G_CAP3_HT_DELAYED_BA))) ||
336
(buf_size > max_buf_size)) {
337
status = WLAN_STATUS_INVALID_QOS_PARAM;
338
ht_dbg_ratelimited(sta->sdata,
339
"AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n",
340
sta->sta.addr, tid, ba_policy, buf_size);
341
goto end;
342
}
343
/* determine default buffer size */
344
if (buf_size == 0)
345
buf_size = max_buf_size;
346
347
/* make sure the size doesn't exceed the maximum supported by the hw */
348
if (buf_size > sta->sta.max_rx_aggregation_subframes)
349
buf_size = sta->sta.max_rx_aggregation_subframes;
350
params.buf_size = buf_size;
351
352
ht_dbg(sta->sdata, "AddBA Req buf_size=%d for %pM\n",
353
buf_size, sta->sta.addr);
354
355
if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) {
356
if (sta->ampdu_mlme.tid_rx_token[tid] == dialog_token) {
357
struct tid_ampdu_rx *tid_rx;
358
359
ht_dbg_ratelimited(sta->sdata,
360
"updated AddBA Req from %pM on tid %u\n",
361
sta->sta.addr, tid);
362
/* We have no API to update the timeout value in the
363
* driver so reject the timeout update if the timeout
364
* changed. If it did not change, i.e., no real update,
365
* just reply with success.
366
*/
367
rcu_read_lock();
368
tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
369
if (tid_rx && tid_rx->timeout == timeout)
370
status = WLAN_STATUS_SUCCESS;
371
else
372
status = WLAN_STATUS_REQUEST_DECLINED;
373
rcu_read_unlock();
374
goto end;
375
}
376
377
ht_dbg_ratelimited(sta->sdata,
378
"unexpected AddBA Req from %pM on tid %u\n",
379
sta->sta.addr, tid);
380
381
/* delete existing Rx BA session on the same tid */
382
__ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
383
WLAN_STATUS_UNSPECIFIED_QOS,
384
false);
385
}
386
387
if (ieee80211_hw_check(&local->hw, SUPPORTS_REORDERING_BUFFER)) {
388
ret = drv_ampdu_action(local, sta->sdata, &params);
389
ht_dbg(sta->sdata,
390
"Rx A-MPDU request on %pM tid %d result %d\n",
391
sta->sta.addr, tid, ret);
392
if (!ret)
393
status = WLAN_STATUS_SUCCESS;
394
goto end;
395
}
396
397
/* prepare A-MPDU MLME for Rx aggregation */
398
tid_agg_rx = kzalloc(sizeof(*tid_agg_rx), GFP_KERNEL);
399
if (!tid_agg_rx)
400
goto end;
401
402
spin_lock_init(&tid_agg_rx->reorder_lock);
403
404
/* rx timer */
405
timer_setup(&tid_agg_rx->session_timer,
406
sta_rx_agg_session_timer_expired, TIMER_DEFERRABLE);
407
408
/* rx reorder timer */
409
timer_setup(&tid_agg_rx->reorder_timer,
410
sta_rx_agg_reorder_timer_expired, 0);
411
412
/* prepare reordering buffer */
413
tid_agg_rx->reorder_buf =
414
kcalloc(buf_size, sizeof(struct sk_buff_head), GFP_KERNEL);
415
tid_agg_rx->reorder_time =
416
kcalloc(buf_size, sizeof(unsigned long), GFP_KERNEL);
417
if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) {
418
kfree(tid_agg_rx->reorder_buf);
419
kfree(tid_agg_rx->reorder_time);
420
kfree(tid_agg_rx);
421
goto end;
422
}
423
424
for (i = 0; i < buf_size; i++)
425
__skb_queue_head_init(&tid_agg_rx->reorder_buf[i]);
426
427
ret = drv_ampdu_action(local, sta->sdata, &params);
428
ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n",
429
sta->sta.addr, tid, ret);
430
if (ret) {
431
kfree(tid_agg_rx->reorder_buf);
432
kfree(tid_agg_rx->reorder_time);
433
kfree(tid_agg_rx);
434
goto end;
435
}
436
437
/* update data */
438
tid_agg_rx->ssn = start_seq_num;
439
tid_agg_rx->head_seq_num = start_seq_num;
440
tid_agg_rx->buf_size = buf_size;
441
tid_agg_rx->timeout = timeout;
442
tid_agg_rx->stored_mpdu_num = 0;
443
tid_agg_rx->auto_seq = auto_seq;
444
tid_agg_rx->started = false;
445
tid_agg_rx->reorder_buf_filtered = 0;
446
tid_agg_rx->tid = tid;
447
tid_agg_rx->sta = sta;
448
status = WLAN_STATUS_SUCCESS;
449
450
/* activate it for RX */
451
rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx);
452
453
if (timeout) {
454
mod_timer(&tid_agg_rx->session_timer, TU_TO_EXP_TIME(timeout));
455
tid_agg_rx->last_rx = jiffies;
456
}
457
458
end:
459
if (status == WLAN_STATUS_SUCCESS) {
460
__set_bit(tid, sta->ampdu_mlme.agg_session_valid);
461
__clear_bit(tid, sta->ampdu_mlme.unexpected_agg);
462
sta->ampdu_mlme.tid_rx_token[tid] = dialog_token;
463
}
464
465
if (tx)
466
ieee80211_send_addba_resp(sta, sta->sta.addr, tid,
467
dialog_token, status, 1, buf_size,
468
timeout, addba_ext_data);
469
}
470
471
void ieee80211_process_addba_request(struct ieee80211_local *local,
472
struct sta_info *sta,
473
struct ieee80211_mgmt *mgmt,
474
size_t len)
475
{
476
u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num;
477
u8 dialog_token, addba_ext_data;
478
479
/* extract session parameters from addba request frame */
480
dialog_token = mgmt->u.action.u.addba_req.dialog_token;
481
timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
482
start_seq_num =
483
le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
484
485
capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
486
ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
487
tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
488
buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
489
490
addba_ext_data =
491
ieee80211_retrieve_addba_ext_data(sta,
492
mgmt->u.action.u.addba_req.variable,
493
len -
494
offsetof(typeof(*mgmt),
495
u.action.u.addba_req.variable),
496
&buf_size);
497
498
__ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
499
start_seq_num, ba_policy, tid,
500
buf_size, true, false, addba_ext_data);
501
}
502
503
void ieee80211_manage_rx_ba_offl(struct ieee80211_vif *vif,
504
const u8 *addr, unsigned int tid)
505
{
506
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
507
struct sta_info *sta;
508
509
rcu_read_lock();
510
sta = sta_info_get_bss(sdata, addr);
511
if (!sta)
512
goto unlock;
513
514
set_bit(tid, sta->ampdu_mlme.tid_rx_manage_offl);
515
wiphy_work_queue(sta->local->hw.wiphy, &sta->ampdu_mlme.work);
516
unlock:
517
rcu_read_unlock();
518
}
519
EXPORT_SYMBOL(ieee80211_manage_rx_ba_offl);
520
521
void ieee80211_rx_ba_timer_expired(struct ieee80211_vif *vif,
522
const u8 *addr, unsigned int tid)
523
{
524
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
525
struct sta_info *sta;
526
527
rcu_read_lock();
528
sta = sta_info_get_bss(sdata, addr);
529
if (!sta)
530
goto unlock;
531
532
set_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired);
533
wiphy_work_queue(sta->local->hw.wiphy, &sta->ampdu_mlme.work);
534
535
unlock:
536
rcu_read_unlock();
537
}
538
EXPORT_SYMBOL(ieee80211_rx_ba_timer_expired);
539
540