| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * HT handling |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 8 | 9 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> |
|---|
| 9 | 10 | * Copyright 2007-2010, Intel Corporation |
|---|
| 10 | 11 | * Copyright(c) 2015-2017 Intel Deutschland GmbH |
|---|
| 11 | | - * Copyright (C) 2018 - 2019 Intel Corporation |
|---|
| 12 | | - * |
|---|
| 13 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 14 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 15 | | - * published by the Free Software Foundation. |
|---|
| 12 | + * Copyright (C) 2018 - 2022 Intel Corporation |
|---|
| 16 | 13 | */ |
|---|
| 17 | 14 | |
|---|
| 18 | 15 | #include <linux/ieee80211.h> |
|---|
| .. | .. |
|---|
| 216 | 213 | struct ieee80211_txq *txq = sta->sta.txq[tid]; |
|---|
| 217 | 214 | struct txq_info *txqi; |
|---|
| 218 | 215 | |
|---|
| 216 | + lockdep_assert_held(&sta->ampdu_mlme.mtx); |
|---|
| 217 | + |
|---|
| 219 | 218 | if (!txq) |
|---|
| 220 | 219 | return; |
|---|
| 221 | 220 | |
|---|
| .. | .. |
|---|
| 229 | 228 | clear_bit(IEEE80211_TXQ_STOP, &txqi->flags); |
|---|
| 230 | 229 | local_bh_disable(); |
|---|
| 231 | 230 | rcu_read_lock(); |
|---|
| 232 | | - drv_wake_tx_queue(sta->sdata->local, txqi); |
|---|
| 231 | + schedule_and_wake_txq(sta->sdata->local, txqi); |
|---|
| 233 | 232 | rcu_read_unlock(); |
|---|
| 234 | 233 | local_bh_enable(); |
|---|
| 235 | 234 | } |
|---|
| .. | .. |
|---|
| 293 | 292 | ieee80211_assign_tid_tx(sta, tid, NULL); |
|---|
| 294 | 293 | |
|---|
| 295 | 294 | ieee80211_agg_splice_finish(sta->sdata, tid); |
|---|
| 296 | | - ieee80211_agg_start_txq(sta, tid, false); |
|---|
| 297 | 295 | |
|---|
| 298 | 296 | kfree_rcu(tid_tx, rcu_head); |
|---|
| 299 | 297 | } |
|---|
| .. | .. |
|---|
| 451 | 449 | ieee80211_stop_tx_ba_session(&sta->sta, tid); |
|---|
| 452 | 450 | } |
|---|
| 453 | 451 | |
|---|
| 454 | | -void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) |
|---|
| 452 | +static void ieee80211_send_addba_with_timeout(struct sta_info *sta, |
|---|
| 453 | + struct tid_ampdu_tx *tid_tx) |
|---|
| 455 | 454 | { |
|---|
| 456 | | - struct tid_ampdu_tx *tid_tx; |
|---|
| 457 | | - struct ieee80211_local *local = sta->local; |
|---|
| 458 | 455 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
|---|
| 459 | | - struct ieee80211_ampdu_params params = { |
|---|
| 460 | | - .sta = &sta->sta, |
|---|
| 461 | | - .action = IEEE80211_AMPDU_TX_START, |
|---|
| 462 | | - .tid = tid, |
|---|
| 463 | | - .buf_size = 0, |
|---|
| 464 | | - .amsdu = false, |
|---|
| 465 | | - .timeout = 0, |
|---|
| 466 | | - }; |
|---|
| 467 | | - int ret; |
|---|
| 456 | + struct ieee80211_local *local = sta->local; |
|---|
| 457 | + u8 tid = tid_tx->tid; |
|---|
| 468 | 458 | u16 buf_size; |
|---|
| 469 | | - |
|---|
| 470 | | - tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
|---|
| 471 | | - |
|---|
| 472 | | - /* |
|---|
| 473 | | - * Start queuing up packets for this aggregation session. |
|---|
| 474 | | - * We're going to release them once the driver is OK with |
|---|
| 475 | | - * that. |
|---|
| 476 | | - */ |
|---|
| 477 | | - clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state); |
|---|
| 478 | | - |
|---|
| 479 | | - ieee80211_agg_stop_txq(sta, tid); |
|---|
| 480 | | - |
|---|
| 481 | | - /* |
|---|
| 482 | | - * Make sure no packets are being processed. This ensures that |
|---|
| 483 | | - * we have a valid starting sequence number and that in-flight |
|---|
| 484 | | - * packets have been flushed out and no packets for this TID |
|---|
| 485 | | - * will go into the driver during the ampdu_action call. |
|---|
| 486 | | - */ |
|---|
| 487 | | - synchronize_net(); |
|---|
| 488 | | - |
|---|
| 489 | | - params.ssn = sta->tid_seq[tid] >> 4; |
|---|
| 490 | | - ret = drv_ampdu_action(local, sdata, ¶ms); |
|---|
| 491 | | - if (ret) { |
|---|
| 492 | | - ht_dbg(sdata, |
|---|
| 493 | | - "BA request denied - HW unavailable for %pM tid %d\n", |
|---|
| 494 | | - sta->sta.addr, tid); |
|---|
| 495 | | - spin_lock_bh(&sta->lock); |
|---|
| 496 | | - ieee80211_agg_splice_packets(sdata, tid_tx, tid); |
|---|
| 497 | | - ieee80211_assign_tid_tx(sta, tid, NULL); |
|---|
| 498 | | - ieee80211_agg_splice_finish(sdata, tid); |
|---|
| 499 | | - spin_unlock_bh(&sta->lock); |
|---|
| 500 | | - |
|---|
| 501 | | - ieee80211_agg_start_txq(sta, tid, false); |
|---|
| 502 | | - |
|---|
| 503 | | - kfree_rcu(tid_tx, rcu_head); |
|---|
| 504 | | - return; |
|---|
| 505 | | - } |
|---|
| 506 | 459 | |
|---|
| 507 | 460 | /* activate the timer for the recipient's addBA response */ |
|---|
| 508 | 461 | mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL); |
|---|
| .. | .. |
|---|
| 528 | 481 | |
|---|
| 529 | 482 | /* send AddBA request */ |
|---|
| 530 | 483 | ieee80211_send_addba_request(sdata, sta->sta.addr, tid, |
|---|
| 531 | | - tid_tx->dialog_token, params.ssn, |
|---|
| 484 | + tid_tx->dialog_token, tid_tx->ssn, |
|---|
| 532 | 485 | buf_size, tid_tx->timeout); |
|---|
| 486 | + |
|---|
| 487 | + WARN_ON(test_and_set_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state)); |
|---|
| 488 | +} |
|---|
| 489 | + |
|---|
| 490 | +void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) |
|---|
| 491 | +{ |
|---|
| 492 | + struct tid_ampdu_tx *tid_tx; |
|---|
| 493 | + struct ieee80211_local *local = sta->local; |
|---|
| 494 | + struct ieee80211_sub_if_data *sdata; |
|---|
| 495 | + struct ieee80211_ampdu_params params = { |
|---|
| 496 | + .sta = &sta->sta, |
|---|
| 497 | + .action = IEEE80211_AMPDU_TX_START, |
|---|
| 498 | + .tid = tid, |
|---|
| 499 | + .buf_size = 0, |
|---|
| 500 | + .amsdu = false, |
|---|
| 501 | + .timeout = 0, |
|---|
| 502 | + }; |
|---|
| 503 | + int ret; |
|---|
| 504 | + |
|---|
| 505 | + tid_tx = rcu_dereference_protected_tid_tx(sta, tid); |
|---|
| 506 | + |
|---|
| 507 | + /* |
|---|
| 508 | + * Start queuing up packets for this aggregation session. |
|---|
| 509 | + * We're going to release them once the driver is OK with |
|---|
| 510 | + * that. |
|---|
| 511 | + */ |
|---|
| 512 | + clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state); |
|---|
| 513 | + |
|---|
| 514 | + ieee80211_agg_stop_txq(sta, tid); |
|---|
| 515 | + |
|---|
| 516 | + /* |
|---|
| 517 | + * Make sure no packets are being processed. This ensures that |
|---|
| 518 | + * we have a valid starting sequence number and that in-flight |
|---|
| 519 | + * packets have been flushed out and no packets for this TID |
|---|
| 520 | + * will go into the driver during the ampdu_action call. |
|---|
| 521 | + */ |
|---|
| 522 | + synchronize_net(); |
|---|
| 523 | + |
|---|
| 524 | + sdata = sta->sdata; |
|---|
| 525 | + params.ssn = sta->tid_seq[tid] >> 4; |
|---|
| 526 | + ret = drv_ampdu_action(local, sdata, ¶ms); |
|---|
| 527 | + tid_tx->ssn = params.ssn; |
|---|
| 528 | + if (ret == IEEE80211_AMPDU_TX_START_DELAY_ADDBA) { |
|---|
| 529 | + return; |
|---|
| 530 | + } else if (ret == IEEE80211_AMPDU_TX_START_IMMEDIATE) { |
|---|
| 531 | + /* |
|---|
| 532 | + * We didn't send the request yet, so don't need to check |
|---|
| 533 | + * here if we already got a response, just mark as driver |
|---|
| 534 | + * ready immediately. |
|---|
| 535 | + */ |
|---|
| 536 | + set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state); |
|---|
| 537 | + } else if (ret) { |
|---|
| 538 | + if (!sdata) |
|---|
| 539 | + return; |
|---|
| 540 | + |
|---|
| 541 | + ht_dbg(sdata, |
|---|
| 542 | + "BA request denied - HW unavailable for %pM tid %d\n", |
|---|
| 543 | + sta->sta.addr, tid); |
|---|
| 544 | + spin_lock_bh(&sta->lock); |
|---|
| 545 | + ieee80211_agg_splice_packets(sdata, tid_tx, tid); |
|---|
| 546 | + ieee80211_assign_tid_tx(sta, tid, NULL); |
|---|
| 547 | + ieee80211_agg_splice_finish(sdata, tid); |
|---|
| 548 | + spin_unlock_bh(&sta->lock); |
|---|
| 549 | + |
|---|
| 550 | + ieee80211_agg_start_txq(sta, tid, false); |
|---|
| 551 | + |
|---|
| 552 | + kfree_rcu(tid_tx, rcu_head); |
|---|
| 553 | + return; |
|---|
| 554 | + } |
|---|
| 555 | + |
|---|
| 556 | + ieee80211_send_addba_with_timeout(sta, tid_tx); |
|---|
| 533 | 557 | } |
|---|
| 534 | 558 | |
|---|
| 535 | 559 | /* |
|---|
| .. | .. |
|---|
| 574 | 598 | "Requested to start BA session on reserved tid=%d", tid)) |
|---|
| 575 | 599 | return -EINVAL; |
|---|
| 576 | 600 | |
|---|
| 577 | | - if (!pubsta->ht_cap.ht_supported) |
|---|
| 601 | + if (!pubsta->ht_cap.ht_supported && |
|---|
| 602 | + sta->sdata->vif.bss_conf.chandef.chan->band != NL80211_BAND_6GHZ) |
|---|
| 578 | 603 | return -EINVAL; |
|---|
| 579 | 604 | |
|---|
| 580 | 605 | if (WARN_ON_ONCE(!local->ops->ampdu_action)) |
|---|
| .. | .. |
|---|
| 601 | 626 | if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { |
|---|
| 602 | 627 | ht_dbg(sdata, |
|---|
| 603 | 628 | "BA sessions blocked - Denying BA session request %pM tid %d\n", |
|---|
| 629 | + sta->sta.addr, tid); |
|---|
| 630 | + return -EINVAL; |
|---|
| 631 | + } |
|---|
| 632 | + |
|---|
| 633 | + if (test_sta_flag(sta, WLAN_STA_MFP) && |
|---|
| 634 | + !test_sta_flag(sta, WLAN_STA_AUTHORIZED)) { |
|---|
| 635 | + ht_dbg(sdata, |
|---|
| 636 | + "MFP STA not authorized - deny BA session request %pM tid %d\n", |
|---|
| 604 | 637 | sta->sta.addr, tid); |
|---|
| 605 | 638 | return -EINVAL; |
|---|
| 606 | 639 | } |
|---|
| .. | .. |
|---|
| 750 | 783 | if (WARN_ON(test_and_set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state))) |
|---|
| 751 | 784 | return; |
|---|
| 752 | 785 | |
|---|
| 786 | + if (!test_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state)) { |
|---|
| 787 | + ieee80211_send_addba_with_timeout(sta, tid_tx); |
|---|
| 788 | + /* RESPONSE_RECEIVED state whould trigger the flow again */ |
|---|
| 789 | + return; |
|---|
| 790 | + } |
|---|
| 791 | + |
|---|
| 753 | 792 | if (test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) |
|---|
| 754 | 793 | ieee80211_agg_tx_operational(local, sta, tid); |
|---|
| 755 | 794 | } |
|---|
| .. | .. |
|---|
| 863 | 902 | { |
|---|
| 864 | 903 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
|---|
| 865 | 904 | bool send_delba = false; |
|---|
| 905 | + bool start_txq = false; |
|---|
| 866 | 906 | |
|---|
| 867 | 907 | ht_dbg(sdata, "Stopping Tx BA session for %pM tid %d\n", |
|---|
| 868 | 908 | sta->sta.addr, tid); |
|---|
| .. | .. |
|---|
| 880 | 920 | send_delba = true; |
|---|
| 881 | 921 | |
|---|
| 882 | 922 | ieee80211_remove_tid_tx(sta, tid); |
|---|
| 923 | + start_txq = true; |
|---|
| 883 | 924 | |
|---|
| 884 | 925 | unlock_sta: |
|---|
| 885 | 926 | spin_unlock_bh(&sta->lock); |
|---|
| 886 | 927 | |
|---|
| 928 | + if (start_txq) |
|---|
| 929 | + ieee80211_agg_start_txq(sta, tid, false); |
|---|
| 930 | + |
|---|
| 887 | 931 | if (send_delba) |
|---|
| 888 | 932 | ieee80211_send_delba(sdata, sta->sta.addr, tid, |
|---|
| 889 | 933 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); |
|---|