Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/mac80211/agg-rx.c
26278 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-2024 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, true, NULL);
210
211
if (!elems || elems->parse_error || !elems->addba_ext_ie)
212
goto free;
213
214
data = elems->addba_ext_ie->data;
215
216
if (buf_size &&
217
(sta->sta.valid_links || sta->sta.deflink.eht_cap.has_eht)) {
218
buf_size_1k = u8_get_bits(elems->addba_ext_ie->data,
219
IEEE80211_ADDBA_EXT_BUF_SIZE_MASK);
220
*buf_size |= (u16)buf_size_1k <<
221
IEEE80211_ADDBA_EXT_BUF_SIZE_SHIFT;
222
}
223
224
free:
225
kfree(elems);
226
227
return data;
228
}
229
230
static void ieee80211_send_addba_resp(struct sta_info *sta, u8 *da, u16 tid,
231
u8 dialog_token, u16 status, u16 policy,
232
u16 buf_size, u16 timeout,
233
const u8 req_addba_ext_data)
234
{
235
struct ieee80211_sub_if_data *sdata = sta->sdata;
236
struct ieee80211_local *local = sdata->local;
237
struct sk_buff *skb;
238
struct ieee80211_mgmt *mgmt;
239
bool amsdu = ieee80211_hw_check(&local->hw, SUPPORTS_AMSDU_IN_AMPDU);
240
u16 capab;
241
242
skb = dev_alloc_skb(sizeof(*mgmt) +
243
2 + sizeof(struct ieee80211_addba_ext_ie) +
244
local->hw.extra_tx_headroom);
245
if (!skb)
246
return;
247
248
skb_reserve(skb, local->hw.extra_tx_headroom);
249
mgmt = ieee80211_mgmt_ba(skb, da, sdata);
250
251
skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
252
mgmt->u.action.category = WLAN_CATEGORY_BACK;
253
mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
254
mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
255
256
capab = u16_encode_bits(amsdu, IEEE80211_ADDBA_PARAM_AMSDU_MASK);
257
capab |= u16_encode_bits(policy, IEEE80211_ADDBA_PARAM_POLICY_MASK);
258
capab |= u16_encode_bits(tid, IEEE80211_ADDBA_PARAM_TID_MASK);
259
capab |= u16_encode_bits(buf_size, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK);
260
261
mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
262
mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
263
mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
264
265
if (sta->sta.valid_links || sta->sta.deflink.he_cap.has_he)
266
ieee80211_add_addbaext(skb, req_addba_ext_data, buf_size);
267
268
ieee80211_tx_skb(sdata, skb);
269
}
270
271
void __ieee80211_start_rx_ba_session(struct sta_info *sta,
272
u8 dialog_token, u16 timeout,
273
u16 start_seq_num, u16 ba_policy, u16 tid,
274
u16 buf_size, bool tx, bool auto_seq,
275
const u8 addba_ext_data)
276
{
277
struct ieee80211_local *local = sta->sdata->local;
278
struct tid_ampdu_rx *tid_agg_rx;
279
struct ieee80211_ampdu_params params = {
280
.sta = &sta->sta,
281
.action = IEEE80211_AMPDU_RX_START,
282
.tid = tid,
283
.amsdu = false,
284
.timeout = timeout,
285
.ssn = start_seq_num,
286
};
287
int i, ret = -EOPNOTSUPP;
288
u16 status = WLAN_STATUS_REQUEST_DECLINED;
289
u16 max_buf_size;
290
291
lockdep_assert_wiphy(sta->local->hw.wiphy);
292
293
if (tid >= IEEE80211_FIRST_TSPEC_TSID) {
294
ht_dbg(sta->sdata,
295
"STA %pM requests BA session on unsupported tid %d\n",
296
sta->sta.addr, tid);
297
goto end;
298
}
299
300
if (!sta->sta.valid_links &&
301
!sta->sta.deflink.ht_cap.ht_supported &&
302
!sta->sta.deflink.he_cap.has_he &&
303
!sta->sta.deflink.s1g_cap.s1g) {
304
ht_dbg(sta->sdata,
305
"STA %pM erroneously requests BA session on tid %d w/o HT\n",
306
sta->sta.addr, tid);
307
/* send a response anyway, it's an error case if we get here */
308
goto end;
309
}
310
311
if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
312
ht_dbg(sta->sdata,
313
"Suspend in progress - Denying ADDBA request (%pM tid %d)\n",
314
sta->sta.addr, tid);
315
goto end;
316
}
317
318
if (sta->sta.valid_links || sta->sta.deflink.eht_cap.has_eht)
319
max_buf_size = IEEE80211_MAX_AMPDU_BUF_EHT;
320
else if (sta->sta.deflink.he_cap.has_he)
321
max_buf_size = IEEE80211_MAX_AMPDU_BUF_HE;
322
else
323
max_buf_size = IEEE80211_MAX_AMPDU_BUF_HT;
324
325
/* sanity check for incoming parameters:
326
* check if configuration can support the BA policy
327
* and if buffer size does not exceeds max value */
328
/* XXX: check own ht delayed BA capability?? */
329
if (((ba_policy != 1) &&
330
(sta->sta.valid_links ||
331
!(sta->sta.deflink.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA) ||
332
!(sta->sta.deflink.s1g_cap.cap[3] & S1G_CAP3_HT_DELAYED_BA))) ||
333
(buf_size > max_buf_size)) {
334
status = WLAN_STATUS_INVALID_QOS_PARAM;
335
ht_dbg_ratelimited(sta->sdata,
336
"AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n",
337
sta->sta.addr, tid, ba_policy, buf_size);
338
goto end;
339
}
340
/* determine default buffer size */
341
if (buf_size == 0)
342
buf_size = max_buf_size;
343
344
/* make sure the size doesn't exceed the maximum supported by the hw */
345
if (buf_size > sta->sta.max_rx_aggregation_subframes)
346
buf_size = sta->sta.max_rx_aggregation_subframes;
347
params.buf_size = buf_size;
348
349
ht_dbg(sta->sdata, "AddBA Req buf_size=%d for %pM\n",
350
buf_size, sta->sta.addr);
351
352
if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) {
353
if (sta->ampdu_mlme.tid_rx_token[tid] == dialog_token) {
354
struct tid_ampdu_rx *tid_rx;
355
356
ht_dbg_ratelimited(sta->sdata,
357
"updated AddBA Req from %pM on tid %u\n",
358
sta->sta.addr, tid);
359
/* We have no API to update the timeout value in the
360
* driver so reject the timeout update if the timeout
361
* changed. If it did not change, i.e., no real update,
362
* just reply with success.
363
*/
364
rcu_read_lock();
365
tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
366
if (tid_rx && tid_rx->timeout == timeout)
367
status = WLAN_STATUS_SUCCESS;
368
else
369
status = WLAN_STATUS_REQUEST_DECLINED;
370
rcu_read_unlock();
371
goto end;
372
}
373
374
ht_dbg_ratelimited(sta->sdata,
375
"unexpected AddBA Req from %pM on tid %u\n",
376
sta->sta.addr, tid);
377
378
/* delete existing Rx BA session on the same tid */
379
__ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
380
WLAN_STATUS_UNSPECIFIED_QOS,
381
false);
382
}
383
384
if (ieee80211_hw_check(&local->hw, SUPPORTS_REORDERING_BUFFER)) {
385
ret = drv_ampdu_action(local, sta->sdata, &params);
386
ht_dbg(sta->sdata,
387
"Rx A-MPDU request on %pM tid %d result %d\n",
388
sta->sta.addr, tid, ret);
389
if (!ret)
390
status = WLAN_STATUS_SUCCESS;
391
goto end;
392
}
393
394
/* prepare A-MPDU MLME for Rx aggregation */
395
tid_agg_rx = kzalloc(sizeof(*tid_agg_rx), GFP_KERNEL);
396
if (!tid_agg_rx)
397
goto end;
398
399
spin_lock_init(&tid_agg_rx->reorder_lock);
400
401
/* rx timer */
402
timer_setup(&tid_agg_rx->session_timer,
403
sta_rx_agg_session_timer_expired, TIMER_DEFERRABLE);
404
405
/* rx reorder timer */
406
timer_setup(&tid_agg_rx->reorder_timer,
407
sta_rx_agg_reorder_timer_expired, 0);
408
409
/* prepare reordering buffer */
410
tid_agg_rx->reorder_buf =
411
kcalloc(buf_size, sizeof(struct sk_buff_head), GFP_KERNEL);
412
tid_agg_rx->reorder_time =
413
kcalloc(buf_size, sizeof(unsigned long), GFP_KERNEL);
414
if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) {
415
kfree(tid_agg_rx->reorder_buf);
416
kfree(tid_agg_rx->reorder_time);
417
kfree(tid_agg_rx);
418
goto end;
419
}
420
421
for (i = 0; i < buf_size; i++)
422
__skb_queue_head_init(&tid_agg_rx->reorder_buf[i]);
423
424
ret = drv_ampdu_action(local, sta->sdata, &params);
425
ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n",
426
sta->sta.addr, tid, ret);
427
if (ret) {
428
kfree(tid_agg_rx->reorder_buf);
429
kfree(tid_agg_rx->reorder_time);
430
kfree(tid_agg_rx);
431
goto end;
432
}
433
434
/* update data */
435
tid_agg_rx->ssn = start_seq_num;
436
tid_agg_rx->head_seq_num = start_seq_num;
437
tid_agg_rx->buf_size = buf_size;
438
tid_agg_rx->timeout = timeout;
439
tid_agg_rx->stored_mpdu_num = 0;
440
tid_agg_rx->auto_seq = auto_seq;
441
tid_agg_rx->started = false;
442
tid_agg_rx->reorder_buf_filtered = 0;
443
tid_agg_rx->tid = tid;
444
tid_agg_rx->sta = sta;
445
status = WLAN_STATUS_SUCCESS;
446
447
/* activate it for RX */
448
rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx);
449
450
if (timeout) {
451
mod_timer(&tid_agg_rx->session_timer, TU_TO_EXP_TIME(timeout));
452
tid_agg_rx->last_rx = jiffies;
453
}
454
455
end:
456
if (status == WLAN_STATUS_SUCCESS) {
457
__set_bit(tid, sta->ampdu_mlme.agg_session_valid);
458
__clear_bit(tid, sta->ampdu_mlme.unexpected_agg);
459
sta->ampdu_mlme.tid_rx_token[tid] = dialog_token;
460
}
461
462
if (tx)
463
ieee80211_send_addba_resp(sta, sta->sta.addr, tid,
464
dialog_token, status, 1, buf_size,
465
timeout, addba_ext_data);
466
}
467
468
void ieee80211_process_addba_request(struct ieee80211_local *local,
469
struct sta_info *sta,
470
struct ieee80211_mgmt *mgmt,
471
size_t len)
472
{
473
u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num;
474
u8 dialog_token, addba_ext_data;
475
476
/* extract session parameters from addba request frame */
477
dialog_token = mgmt->u.action.u.addba_req.dialog_token;
478
timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
479
start_seq_num =
480
le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
481
482
capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
483
ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
484
tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
485
buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
486
487
addba_ext_data =
488
ieee80211_retrieve_addba_ext_data(sta,
489
mgmt->u.action.u.addba_req.variable,
490
len -
491
offsetof(typeof(*mgmt),
492
u.action.u.addba_req.variable),
493
&buf_size);
494
495
__ieee80211_start_rx_ba_session(sta, dialog_token, timeout,
496
start_seq_num, ba_policy, tid,
497
buf_size, true, false, addba_ext_data);
498
}
499
500
void ieee80211_manage_rx_ba_offl(struct ieee80211_vif *vif,
501
const u8 *addr, unsigned int tid)
502
{
503
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
504
struct sta_info *sta;
505
506
rcu_read_lock();
507
sta = sta_info_get_bss(sdata, addr);
508
if (!sta)
509
goto unlock;
510
511
set_bit(tid, sta->ampdu_mlme.tid_rx_manage_offl);
512
wiphy_work_queue(sta->local->hw.wiphy, &sta->ampdu_mlme.work);
513
unlock:
514
rcu_read_unlock();
515
}
516
EXPORT_SYMBOL(ieee80211_manage_rx_ba_offl);
517
518
void ieee80211_rx_ba_timer_expired(struct ieee80211_vif *vif,
519
const u8 *addr, unsigned int tid)
520
{
521
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
522
struct sta_info *sta;
523
524
rcu_read_lock();
525
sta = sta_info_get_bss(sdata, addr);
526
if (!sta)
527
goto unlock;
528
529
set_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired);
530
wiphy_work_queue(sta->local->hw.wiphy, &sta->ampdu_mlme.work);
531
532
unlock:
533
rcu_read_unlock();
534
}
535
EXPORT_SYMBOL(ieee80211_rx_ba_timer_expired);
536
537