162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * HT handling
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
662306a36Sopenharmony_ci * Copyright 2002-2005, Instant802 Networks, Inc.
762306a36Sopenharmony_ci * Copyright 2005-2006, Devicescape Software, Inc.
862306a36Sopenharmony_ci * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
962306a36Sopenharmony_ci * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
1062306a36Sopenharmony_ci * Copyright 2007-2010, Intel Corporation
1162306a36Sopenharmony_ci * Copyright(c) 2015-2017 Intel Deutschland GmbH
1262306a36Sopenharmony_ci * Copyright (C) 2018 - 2023 Intel Corporation
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/ieee80211.h>
1662306a36Sopenharmony_ci#include <linux/slab.h>
1762306a36Sopenharmony_ci#include <linux/export.h>
1862306a36Sopenharmony_ci#include <net/mac80211.h>
1962306a36Sopenharmony_ci#include "ieee80211_i.h"
2062306a36Sopenharmony_ci#include "driver-ops.h"
2162306a36Sopenharmony_ci#include "wme.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/**
2462306a36Sopenharmony_ci * DOC: TX A-MPDU aggregation
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * Aggregation on the TX side requires setting the hardware flag
2762306a36Sopenharmony_ci * %IEEE80211_HW_AMPDU_AGGREGATION. The driver will then be handed
2862306a36Sopenharmony_ci * packets with a flag indicating A-MPDU aggregation. The driver
2962306a36Sopenharmony_ci * or device is responsible for actually aggregating the frames,
3062306a36Sopenharmony_ci * as well as deciding how many and which to aggregate.
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci * When TX aggregation is started by some subsystem (usually the rate
3362306a36Sopenharmony_ci * control algorithm would be appropriate) by calling the
3462306a36Sopenharmony_ci * ieee80211_start_tx_ba_session() function, the driver will be
3562306a36Sopenharmony_ci * notified via its @ampdu_action function, with the
3662306a36Sopenharmony_ci * %IEEE80211_AMPDU_TX_START action.
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci * In response to that, the driver is later required to call the
3962306a36Sopenharmony_ci * ieee80211_start_tx_ba_cb_irqsafe() function, which will really
4062306a36Sopenharmony_ci * start the aggregation session after the peer has also responded.
4162306a36Sopenharmony_ci * If the peer responds negatively, the session will be stopped
4262306a36Sopenharmony_ci * again right away. Note that it is possible for the aggregation
4362306a36Sopenharmony_ci * session to be stopped before the driver has indicated that it
4462306a36Sopenharmony_ci * is done setting it up, in which case it must not indicate the
4562306a36Sopenharmony_ci * setup completion.
4662306a36Sopenharmony_ci *
4762306a36Sopenharmony_ci * Also note that, since we also need to wait for a response from
4862306a36Sopenharmony_ci * the peer, the driver is notified of the completion of the
4962306a36Sopenharmony_ci * handshake by the %IEEE80211_AMPDU_TX_OPERATIONAL action to the
5062306a36Sopenharmony_ci * @ampdu_action callback.
5162306a36Sopenharmony_ci *
5262306a36Sopenharmony_ci * Similarly, when the aggregation session is stopped by the peer
5362306a36Sopenharmony_ci * or something calling ieee80211_stop_tx_ba_session(), the driver's
5462306a36Sopenharmony_ci * @ampdu_action function will be called with the action
5562306a36Sopenharmony_ci * %IEEE80211_AMPDU_TX_STOP. In this case, the call must not fail,
5662306a36Sopenharmony_ci * and the driver must later call ieee80211_stop_tx_ba_cb_irqsafe().
5762306a36Sopenharmony_ci * Note that the sta can get destroyed before the BA tear down is
5862306a36Sopenharmony_ci * complete.
5962306a36Sopenharmony_ci */
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
6262306a36Sopenharmony_ci					 const u8 *da, u16 tid,
6362306a36Sopenharmony_ci					 u8 dialog_token, u16 start_seq_num,
6462306a36Sopenharmony_ci					 u16 agg_size, u16 timeout)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	struct ieee80211_local *local = sdata->local;
6762306a36Sopenharmony_ci	struct sk_buff *skb;
6862306a36Sopenharmony_ci	struct ieee80211_mgmt *mgmt;
6962306a36Sopenharmony_ci	u16 capab;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (!skb)
7462306a36Sopenharmony_ci		return;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	skb_reserve(skb, local->hw.extra_tx_headroom);
7762306a36Sopenharmony_ci	mgmt = skb_put_zero(skb, 24);
7862306a36Sopenharmony_ci	memcpy(mgmt->da, da, ETH_ALEN);
7962306a36Sopenharmony_ci	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
8062306a36Sopenharmony_ci	if (sdata->vif.type == NL80211_IFTYPE_AP ||
8162306a36Sopenharmony_ci	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
8262306a36Sopenharmony_ci	    sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
8362306a36Sopenharmony_ci		memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
8462306a36Sopenharmony_ci	else if (sdata->vif.type == NL80211_IFTYPE_STATION)
8562306a36Sopenharmony_ci		memcpy(mgmt->bssid, sdata->vif.cfg.ap_addr, ETH_ALEN);
8662306a36Sopenharmony_ci	else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
8762306a36Sopenharmony_ci		memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
9062306a36Sopenharmony_ci					  IEEE80211_STYPE_ACTION);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	mgmt->u.action.category = WLAN_CATEGORY_BACK;
9562306a36Sopenharmony_ci	mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	mgmt->u.action.u.addba_req.dialog_token = dialog_token;
9862306a36Sopenharmony_ci	capab = IEEE80211_ADDBA_PARAM_AMSDU_MASK;
9962306a36Sopenharmony_ci	capab |= IEEE80211_ADDBA_PARAM_POLICY_MASK;
10062306a36Sopenharmony_ci	capab |= u16_encode_bits(tid, IEEE80211_ADDBA_PARAM_TID_MASK);
10162306a36Sopenharmony_ci	capab |= u16_encode_bits(agg_size, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
10662306a36Sopenharmony_ci	mgmt->u.action.u.addba_req.start_seq_num =
10762306a36Sopenharmony_ci					cpu_to_le16(start_seq_num << 4);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	ieee80211_tx_skb_tid(sdata, skb, tid, -1);
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_civoid ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
11562306a36Sopenharmony_ci	struct ieee80211_local *local = sdata->local;
11662306a36Sopenharmony_ci	struct sk_buff *skb;
11762306a36Sopenharmony_ci	struct ieee80211_bar *bar;
11862306a36Sopenharmony_ci	u16 bar_control = 0;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
12162306a36Sopenharmony_ci	if (!skb)
12262306a36Sopenharmony_ci		return;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	skb_reserve(skb, local->hw.extra_tx_headroom);
12562306a36Sopenharmony_ci	bar = skb_put_zero(skb, sizeof(*bar));
12662306a36Sopenharmony_ci	bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
12762306a36Sopenharmony_ci					 IEEE80211_STYPE_BACK_REQ);
12862306a36Sopenharmony_ci	memcpy(bar->ra, ra, ETH_ALEN);
12962306a36Sopenharmony_ci	memcpy(bar->ta, sdata->vif.addr, ETH_ALEN);
13062306a36Sopenharmony_ci	bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
13162306a36Sopenharmony_ci	bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
13262306a36Sopenharmony_ci	bar_control |= (u16)(tid << IEEE80211_BAR_CTRL_TID_INFO_SHIFT);
13362306a36Sopenharmony_ci	bar->control = cpu_to_le16(bar_control);
13462306a36Sopenharmony_ci	bar->start_seq_num = cpu_to_le16(ssn);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
13762306a36Sopenharmony_ci					IEEE80211_TX_CTL_REQ_TX_STATUS;
13862306a36Sopenharmony_ci	ieee80211_tx_skb_tid(sdata, skb, tid, -1);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_send_bar);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_civoid ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
14362306a36Sopenharmony_ci			     struct tid_ampdu_tx *tid_tx)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	lockdep_assert_held(&sta->ampdu_mlme.mtx);
14662306a36Sopenharmony_ci	lockdep_assert_held(&sta->lock);
14762306a36Sopenharmony_ci	rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/*
15162306a36Sopenharmony_ci * When multiple aggregation sessions on multiple stations
15262306a36Sopenharmony_ci * are being created/destroyed simultaneously, we need to
15362306a36Sopenharmony_ci * refcount the global queue stop caused by that in order
15462306a36Sopenharmony_ci * to not get into a situation where one of the aggregation
15562306a36Sopenharmony_ci * setup or teardown re-enables queues before the other is
15662306a36Sopenharmony_ci * ready to handle that.
15762306a36Sopenharmony_ci *
15862306a36Sopenharmony_ci * These two functions take care of this issue by keeping
15962306a36Sopenharmony_ci * a global "agg_queue_stop" refcount.
16062306a36Sopenharmony_ci */
16162306a36Sopenharmony_cistatic void __acquires(agg_queue)
16262306a36Sopenharmony_ciieee80211_stop_queue_agg(struct ieee80211_sub_if_data *sdata, int tid)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	/* we do refcounting here, so don't use the queue reason refcounting */
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (atomic_inc_return(&sdata->local->agg_queue_stop[queue]) == 1)
16962306a36Sopenharmony_ci		ieee80211_stop_queue_by_reason(
17062306a36Sopenharmony_ci			&sdata->local->hw, queue,
17162306a36Sopenharmony_ci			IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
17262306a36Sopenharmony_ci			false);
17362306a36Sopenharmony_ci	__acquire(agg_queue);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic void __releases(agg_queue)
17762306a36Sopenharmony_ciieee80211_wake_queue_agg(struct ieee80211_sub_if_data *sdata, int tid)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (atomic_dec_return(&sdata->local->agg_queue_stop[queue]) == 0)
18262306a36Sopenharmony_ci		ieee80211_wake_queue_by_reason(
18362306a36Sopenharmony_ci			&sdata->local->hw, queue,
18462306a36Sopenharmony_ci			IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
18562306a36Sopenharmony_ci			false);
18662306a36Sopenharmony_ci	__release(agg_queue);
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic void
19062306a36Sopenharmony_ciieee80211_agg_stop_txq(struct sta_info *sta, int tid)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	struct ieee80211_txq *txq = sta->sta.txq[tid];
19362306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata;
19462306a36Sopenharmony_ci	struct fq *fq;
19562306a36Sopenharmony_ci	struct txq_info *txqi;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (!txq)
19862306a36Sopenharmony_ci		return;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	txqi = to_txq_info(txq);
20162306a36Sopenharmony_ci	sdata = vif_to_sdata(txq->vif);
20262306a36Sopenharmony_ci	fq = &sdata->local->fq;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	/* Lock here to protect against further seqno updates on dequeue */
20562306a36Sopenharmony_ci	spin_lock_bh(&fq->lock);
20662306a36Sopenharmony_ci	set_bit(IEEE80211_TXQ_STOP, &txqi->flags);
20762306a36Sopenharmony_ci	spin_unlock_bh(&fq->lock);
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic void
21162306a36Sopenharmony_ciieee80211_agg_start_txq(struct sta_info *sta, int tid, bool enable)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	struct ieee80211_txq *txq = sta->sta.txq[tid];
21462306a36Sopenharmony_ci	struct txq_info *txqi;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	lockdep_assert_held(&sta->ampdu_mlme.mtx);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	if (!txq)
21962306a36Sopenharmony_ci		return;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	txqi = to_txq_info(txq);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	if (enable)
22462306a36Sopenharmony_ci		set_bit(IEEE80211_TXQ_AMPDU, &txqi->flags);
22562306a36Sopenharmony_ci	else
22662306a36Sopenharmony_ci		clear_bit(IEEE80211_TXQ_AMPDU, &txqi->flags);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	clear_bit(IEEE80211_TXQ_STOP, &txqi->flags);
22962306a36Sopenharmony_ci	local_bh_disable();
23062306a36Sopenharmony_ci	rcu_read_lock();
23162306a36Sopenharmony_ci	schedule_and_wake_txq(sta->sdata->local, txqi);
23262306a36Sopenharmony_ci	rcu_read_unlock();
23362306a36Sopenharmony_ci	local_bh_enable();
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci/*
23762306a36Sopenharmony_ci * splice packets from the STA's pending to the local pending,
23862306a36Sopenharmony_ci * requires a call to ieee80211_agg_splice_finish later
23962306a36Sopenharmony_ci */
24062306a36Sopenharmony_cistatic void __acquires(agg_queue)
24162306a36Sopenharmony_ciieee80211_agg_splice_packets(struct ieee80211_sub_if_data *sdata,
24262306a36Sopenharmony_ci			     struct tid_ampdu_tx *tid_tx, u16 tid)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	struct ieee80211_local *local = sdata->local;
24562306a36Sopenharmony_ci	int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
24662306a36Sopenharmony_ci	unsigned long flags;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	ieee80211_stop_queue_agg(sdata, tid);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	if (WARN(!tid_tx,
25162306a36Sopenharmony_ci		 "TID %d gone but expected when splicing aggregates from the pending queue\n",
25262306a36Sopenharmony_ci		 tid))
25362306a36Sopenharmony_ci		return;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	if (!skb_queue_empty(&tid_tx->pending)) {
25662306a36Sopenharmony_ci		spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
25762306a36Sopenharmony_ci		/* copy over remaining packets */
25862306a36Sopenharmony_ci		skb_queue_splice_tail_init(&tid_tx->pending,
25962306a36Sopenharmony_ci					   &local->pending[queue]);
26062306a36Sopenharmony_ci		spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic void __releases(agg_queue)
26562306a36Sopenharmony_ciieee80211_agg_splice_finish(struct ieee80211_sub_if_data *sdata, u16 tid)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	ieee80211_wake_queue_agg(sdata, tid);
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic void ieee80211_remove_tid_tx(struct sta_info *sta, int tid)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	struct tid_ampdu_tx *tid_tx;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	lockdep_assert_held(&sta->ampdu_mlme.mtx);
27562306a36Sopenharmony_ci	lockdep_assert_held(&sta->lock);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	/*
28062306a36Sopenharmony_ci	 * When we get here, the TX path will not be lockless any more wrt.
28162306a36Sopenharmony_ci	 * aggregation, since the OPERATIONAL bit has long been cleared.
28262306a36Sopenharmony_ci	 * Thus it will block on getting the lock, if it occurs. So if we
28362306a36Sopenharmony_ci	 * stop the queue now, we will not get any more packets, and any
28462306a36Sopenharmony_ci	 * that might be being processed will wait for us here, thereby
28562306a36Sopenharmony_ci	 * guaranteeing that no packets go to the tid_tx pending queue any
28662306a36Sopenharmony_ci	 * more.
28762306a36Sopenharmony_ci	 */
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	ieee80211_agg_splice_packets(sta->sdata, tid_tx, tid);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	/* future packets must not find the tid_tx struct any more */
29262306a36Sopenharmony_ci	ieee80211_assign_tid_tx(sta, tid, NULL);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	ieee80211_agg_splice_finish(sta->sdata, tid);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	kfree_rcu(tid_tx, rcu_head);
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ciint ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
30062306a36Sopenharmony_ci				    enum ieee80211_agg_stop_reason reason)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	struct ieee80211_local *local = sta->local;
30362306a36Sopenharmony_ci	struct tid_ampdu_tx *tid_tx;
30462306a36Sopenharmony_ci	struct ieee80211_ampdu_params params = {
30562306a36Sopenharmony_ci		.sta = &sta->sta,
30662306a36Sopenharmony_ci		.tid = tid,
30762306a36Sopenharmony_ci		.buf_size = 0,
30862306a36Sopenharmony_ci		.amsdu = false,
30962306a36Sopenharmony_ci		.timeout = 0,
31062306a36Sopenharmony_ci		.ssn = 0,
31162306a36Sopenharmony_ci	};
31262306a36Sopenharmony_ci	int ret;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	lockdep_assert_held(&sta->ampdu_mlme.mtx);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	switch (reason) {
31762306a36Sopenharmony_ci	case AGG_STOP_DECLINED:
31862306a36Sopenharmony_ci	case AGG_STOP_LOCAL_REQUEST:
31962306a36Sopenharmony_ci	case AGG_STOP_PEER_REQUEST:
32062306a36Sopenharmony_ci		params.action = IEEE80211_AMPDU_TX_STOP_CONT;
32162306a36Sopenharmony_ci		break;
32262306a36Sopenharmony_ci	case AGG_STOP_DESTROY_STA:
32362306a36Sopenharmony_ci		params.action = IEEE80211_AMPDU_TX_STOP_FLUSH;
32462306a36Sopenharmony_ci		break;
32562306a36Sopenharmony_ci	default:
32662306a36Sopenharmony_ci		WARN_ON_ONCE(1);
32762306a36Sopenharmony_ci		return -EINVAL;
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	spin_lock_bh(&sta->lock);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	/* free struct pending for start, if present */
33362306a36Sopenharmony_ci	tid_tx = sta->ampdu_mlme.tid_start_tx[tid];
33462306a36Sopenharmony_ci	kfree(tid_tx);
33562306a36Sopenharmony_ci	sta->ampdu_mlme.tid_start_tx[tid] = NULL;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
33862306a36Sopenharmony_ci	if (!tid_tx) {
33962306a36Sopenharmony_ci		spin_unlock_bh(&sta->lock);
34062306a36Sopenharmony_ci		return -ENOENT;
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	/*
34462306a36Sopenharmony_ci	 * if we're already stopping ignore any new requests to stop
34562306a36Sopenharmony_ci	 * unless we're destroying it in which case notify the driver
34662306a36Sopenharmony_ci	 */
34762306a36Sopenharmony_ci	if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
34862306a36Sopenharmony_ci		spin_unlock_bh(&sta->lock);
34962306a36Sopenharmony_ci		if (reason != AGG_STOP_DESTROY_STA)
35062306a36Sopenharmony_ci			return -EALREADY;
35162306a36Sopenharmony_ci		params.action = IEEE80211_AMPDU_TX_STOP_FLUSH_CONT;
35262306a36Sopenharmony_ci		ret = drv_ampdu_action(local, sta->sdata, &params);
35362306a36Sopenharmony_ci		WARN_ON_ONCE(ret);
35462306a36Sopenharmony_ci		return 0;
35562306a36Sopenharmony_ci	}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
35862306a36Sopenharmony_ci		/* not even started yet! */
35962306a36Sopenharmony_ci		ieee80211_assign_tid_tx(sta, tid, NULL);
36062306a36Sopenharmony_ci		spin_unlock_bh(&sta->lock);
36162306a36Sopenharmony_ci		kfree_rcu(tid_tx, rcu_head);
36262306a36Sopenharmony_ci		return 0;
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	ieee80211_agg_stop_txq(sta, tid);
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	spin_unlock_bh(&sta->lock);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	ht_dbg(sta->sdata, "Tx BA session stop requested for %pM tid %u\n",
37262306a36Sopenharmony_ci	       sta->sta.addr, tid);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	del_timer_sync(&tid_tx->addba_resp_timer);
37562306a36Sopenharmony_ci	del_timer_sync(&tid_tx->session_timer);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	/*
37862306a36Sopenharmony_ci	 * After this packets are no longer handed right through
37962306a36Sopenharmony_ci	 * to the driver but are put onto tid_tx->pending instead,
38062306a36Sopenharmony_ci	 * with locking to ensure proper access.
38162306a36Sopenharmony_ci	 */
38262306a36Sopenharmony_ci	clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	/*
38562306a36Sopenharmony_ci	 * There might be a few packets being processed right now (on
38662306a36Sopenharmony_ci	 * another CPU) that have already gotten past the aggregation
38762306a36Sopenharmony_ci	 * check when it was still OPERATIONAL and consequently have
38862306a36Sopenharmony_ci	 * IEEE80211_TX_CTL_AMPDU set. In that case, this code might
38962306a36Sopenharmony_ci	 * call into the driver at the same time or even before the
39062306a36Sopenharmony_ci	 * TX paths calls into it, which could confuse the driver.
39162306a36Sopenharmony_ci	 *
39262306a36Sopenharmony_ci	 * Wait for all currently running TX paths to finish before
39362306a36Sopenharmony_ci	 * telling the driver. New packets will not go through since
39462306a36Sopenharmony_ci	 * the aggregation session is no longer OPERATIONAL.
39562306a36Sopenharmony_ci	 */
39662306a36Sopenharmony_ci	if (!local->in_reconfig)
39762306a36Sopenharmony_ci		synchronize_net();
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	tid_tx->stop_initiator = reason == AGG_STOP_PEER_REQUEST ?
40062306a36Sopenharmony_ci					WLAN_BACK_RECIPIENT :
40162306a36Sopenharmony_ci					WLAN_BACK_INITIATOR;
40262306a36Sopenharmony_ci	tid_tx->tx_stop = reason == AGG_STOP_LOCAL_REQUEST;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	ret = drv_ampdu_action(local, sta->sdata, &params);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	/* HW shall not deny going back to legacy */
40762306a36Sopenharmony_ci	if (WARN_ON(ret)) {
40862306a36Sopenharmony_ci		/*
40962306a36Sopenharmony_ci		 * We may have pending packets get stuck in this case...
41062306a36Sopenharmony_ci		 * Not bothering with a workaround for now.
41162306a36Sopenharmony_ci		 */
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	/*
41562306a36Sopenharmony_ci	 * In the case of AGG_STOP_DESTROY_STA, the driver won't
41662306a36Sopenharmony_ci	 * necessarily call ieee80211_stop_tx_ba_cb(), so this may
41762306a36Sopenharmony_ci	 * seem like we can leave the tid_tx data pending forever.
41862306a36Sopenharmony_ci	 * This is true, in a way, but "forever" is only until the
41962306a36Sopenharmony_ci	 * station struct is actually destroyed. In the meantime,
42062306a36Sopenharmony_ci	 * leaving it around ensures that we don't transmit packets
42162306a36Sopenharmony_ci	 * to the driver on this TID which might confuse it.
42262306a36Sopenharmony_ci	 */
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	return 0;
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci/*
42862306a36Sopenharmony_ci * After sending add Block Ack request we activated a timer until
42962306a36Sopenharmony_ci * add Block Ack response will arrive from the recipient.
43062306a36Sopenharmony_ci * If this timer expires sta_addba_resp_timer_expired will be executed.
43162306a36Sopenharmony_ci */
43262306a36Sopenharmony_cistatic void sta_addba_resp_timer_expired(struct timer_list *t)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	struct tid_ampdu_tx *tid_tx = from_timer(tid_tx, t, addba_resp_timer);
43562306a36Sopenharmony_ci	struct sta_info *sta = tid_tx->sta;
43662306a36Sopenharmony_ci	u8 tid = tid_tx->tid;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	/* check if the TID waits for addBA response */
43962306a36Sopenharmony_ci	if (test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) {
44062306a36Sopenharmony_ci		ht_dbg(sta->sdata,
44162306a36Sopenharmony_ci		       "timer expired on %pM tid %d not expecting addBA response\n",
44262306a36Sopenharmony_ci		       sta->sta.addr, tid);
44362306a36Sopenharmony_ci		return;
44462306a36Sopenharmony_ci	}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	ht_dbg(sta->sdata, "addBA response timer expired on %pM tid %d\n",
44762306a36Sopenharmony_ci	       sta->sta.addr, tid);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	ieee80211_stop_tx_ba_session(&sta->sta, tid);
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_cistatic void ieee80211_send_addba_with_timeout(struct sta_info *sta,
45362306a36Sopenharmony_ci					      struct tid_ampdu_tx *tid_tx)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = sta->sdata;
45662306a36Sopenharmony_ci	struct ieee80211_local *local = sta->local;
45762306a36Sopenharmony_ci	u8 tid = tid_tx->tid;
45862306a36Sopenharmony_ci	u16 buf_size;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	if (WARN_ON_ONCE(test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state) ||
46162306a36Sopenharmony_ci			 test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state)))
46262306a36Sopenharmony_ci		return;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	lockdep_assert_held(&sta->ampdu_mlme.mtx);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	/* activate the timer for the recipient's addBA response */
46762306a36Sopenharmony_ci	mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL);
46862306a36Sopenharmony_ci	ht_dbg(sdata, "activated addBA response timer on %pM tid %d\n",
46962306a36Sopenharmony_ci	       sta->sta.addr, tid);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	spin_lock_bh(&sta->lock);
47262306a36Sopenharmony_ci	sta->ampdu_mlme.last_addba_req_time[tid] = jiffies;
47362306a36Sopenharmony_ci	sta->ampdu_mlme.addba_req_num[tid]++;
47462306a36Sopenharmony_ci	spin_unlock_bh(&sta->lock);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	if (sta->sta.deflink.he_cap.has_he) {
47762306a36Sopenharmony_ci		buf_size = local->hw.max_tx_aggregation_subframes;
47862306a36Sopenharmony_ci	} else {
47962306a36Sopenharmony_ci		/*
48062306a36Sopenharmony_ci		 * We really should use what the driver told us it will
48162306a36Sopenharmony_ci		 * transmit as the maximum, but certain APs (e.g. the
48262306a36Sopenharmony_ci		 * LinkSys WRT120N with FW v1.0.07 build 002 Jun 18 2012)
48362306a36Sopenharmony_ci		 * will crash when we use a lower number.
48462306a36Sopenharmony_ci		 */
48562306a36Sopenharmony_ci		buf_size = IEEE80211_MAX_AMPDU_BUF_HT;
48662306a36Sopenharmony_ci	}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	/* send AddBA request */
48962306a36Sopenharmony_ci	ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
49062306a36Sopenharmony_ci				     tid_tx->dialog_token, tid_tx->ssn,
49162306a36Sopenharmony_ci				     buf_size, tid_tx->timeout);
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	WARN_ON(test_and_set_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state));
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_civoid ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	struct tid_ampdu_tx *tid_tx;
49962306a36Sopenharmony_ci	struct ieee80211_local *local = sta->local;
50062306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata;
50162306a36Sopenharmony_ci	struct ieee80211_ampdu_params params = {
50262306a36Sopenharmony_ci		.sta = &sta->sta,
50362306a36Sopenharmony_ci		.action = IEEE80211_AMPDU_TX_START,
50462306a36Sopenharmony_ci		.tid = tid,
50562306a36Sopenharmony_ci		.buf_size = 0,
50662306a36Sopenharmony_ci		.amsdu = false,
50762306a36Sopenharmony_ci		.timeout = 0,
50862306a36Sopenharmony_ci	};
50962306a36Sopenharmony_ci	int ret;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	/*
51462306a36Sopenharmony_ci	 * Start queuing up packets for this aggregation session.
51562306a36Sopenharmony_ci	 * We're going to release them once the driver is OK with
51662306a36Sopenharmony_ci	 * that.
51762306a36Sopenharmony_ci	 */
51862306a36Sopenharmony_ci	clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	/*
52162306a36Sopenharmony_ci	 * Make sure no packets are being processed. This ensures that
52262306a36Sopenharmony_ci	 * we have a valid starting sequence number and that in-flight
52362306a36Sopenharmony_ci	 * packets have been flushed out and no packets for this TID
52462306a36Sopenharmony_ci	 * will go into the driver during the ampdu_action call.
52562306a36Sopenharmony_ci	 */
52662306a36Sopenharmony_ci	synchronize_net();
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	sdata = sta->sdata;
52962306a36Sopenharmony_ci	params.ssn = sta->tid_seq[tid] >> 4;
53062306a36Sopenharmony_ci	ret = drv_ampdu_action(local, sdata, &params);
53162306a36Sopenharmony_ci	tid_tx->ssn = params.ssn;
53262306a36Sopenharmony_ci	if (ret == IEEE80211_AMPDU_TX_START_DELAY_ADDBA) {
53362306a36Sopenharmony_ci		return;
53462306a36Sopenharmony_ci	} else if (ret == IEEE80211_AMPDU_TX_START_IMMEDIATE) {
53562306a36Sopenharmony_ci		/*
53662306a36Sopenharmony_ci		 * We didn't send the request yet, so don't need to check
53762306a36Sopenharmony_ci		 * here if we already got a response, just mark as driver
53862306a36Sopenharmony_ci		 * ready immediately.
53962306a36Sopenharmony_ci		 */
54062306a36Sopenharmony_ci		set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state);
54162306a36Sopenharmony_ci	} else if (ret) {
54262306a36Sopenharmony_ci		if (!sdata)
54362306a36Sopenharmony_ci			return;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci		ht_dbg(sdata,
54662306a36Sopenharmony_ci		       "BA request denied - HW unavailable for %pM tid %d\n",
54762306a36Sopenharmony_ci		       sta->sta.addr, tid);
54862306a36Sopenharmony_ci		spin_lock_bh(&sta->lock);
54962306a36Sopenharmony_ci		ieee80211_agg_splice_packets(sdata, tid_tx, tid);
55062306a36Sopenharmony_ci		ieee80211_assign_tid_tx(sta, tid, NULL);
55162306a36Sopenharmony_ci		ieee80211_agg_splice_finish(sdata, tid);
55262306a36Sopenharmony_ci		spin_unlock_bh(&sta->lock);
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci		ieee80211_agg_start_txq(sta, tid, false);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci		kfree_rcu(tid_tx, rcu_head);
55762306a36Sopenharmony_ci		return;
55862306a36Sopenharmony_ci	}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	ieee80211_send_addba_with_timeout(sta, tid_tx);
56162306a36Sopenharmony_ci}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_civoid ieee80211_refresh_tx_agg_session_timer(struct ieee80211_sta *pubsta,
56462306a36Sopenharmony_ci					    u16 tid)
56562306a36Sopenharmony_ci{
56662306a36Sopenharmony_ci	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
56762306a36Sopenharmony_ci	struct tid_ampdu_tx *tid_tx;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	if (WARN_ON_ONCE(tid >= IEEE80211_NUM_TIDS))
57062306a36Sopenharmony_ci		return;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
57362306a36Sopenharmony_ci	if (!tid_tx)
57462306a36Sopenharmony_ci		return;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	tid_tx->last_tx = jiffies;
57762306a36Sopenharmony_ci}
57862306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_refresh_tx_agg_session_timer);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci/*
58162306a36Sopenharmony_ci * After accepting the AddBA Response we activated a timer,
58262306a36Sopenharmony_ci * resetting it after each frame that we send.
58362306a36Sopenharmony_ci */
58462306a36Sopenharmony_cistatic void sta_tx_agg_session_timer_expired(struct timer_list *t)
58562306a36Sopenharmony_ci{
58662306a36Sopenharmony_ci	struct tid_ampdu_tx *tid_tx = from_timer(tid_tx, t, session_timer);
58762306a36Sopenharmony_ci	struct sta_info *sta = tid_tx->sta;
58862306a36Sopenharmony_ci	u8 tid = tid_tx->tid;
58962306a36Sopenharmony_ci	unsigned long timeout;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
59262306a36Sopenharmony_ci		return;
59362306a36Sopenharmony_ci	}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	timeout = tid_tx->last_tx + TU_TO_JIFFIES(tid_tx->timeout);
59662306a36Sopenharmony_ci	if (time_is_after_jiffies(timeout)) {
59762306a36Sopenharmony_ci		mod_timer(&tid_tx->session_timer, timeout);
59862306a36Sopenharmony_ci		return;
59962306a36Sopenharmony_ci	}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	ht_dbg(sta->sdata, "tx session timer expired on %pM tid %d\n",
60262306a36Sopenharmony_ci	       sta->sta.addr, tid);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	ieee80211_stop_tx_ba_session(&sta->sta, tid);
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ciint ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
60862306a36Sopenharmony_ci				  u16 timeout)
60962306a36Sopenharmony_ci{
61062306a36Sopenharmony_ci	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
61162306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = sta->sdata;
61262306a36Sopenharmony_ci	struct ieee80211_local *local = sdata->local;
61362306a36Sopenharmony_ci	struct tid_ampdu_tx *tid_tx;
61462306a36Sopenharmony_ci	int ret = 0;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	trace_api_start_tx_ba_session(pubsta, tid);
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	if (WARN(sta->reserved_tid == tid,
61962306a36Sopenharmony_ci		 "Requested to start BA session on reserved tid=%d", tid))
62062306a36Sopenharmony_ci		return -EINVAL;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	if (!pubsta->deflink.ht_cap.ht_supported &&
62362306a36Sopenharmony_ci	    sta->sdata->vif.bss_conf.chandef.chan->band != NL80211_BAND_6GHZ)
62462306a36Sopenharmony_ci		return -EINVAL;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	if (WARN_ON_ONCE(!local->ops->ampdu_action))
62762306a36Sopenharmony_ci		return -EINVAL;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	if ((tid >= IEEE80211_NUM_TIDS) ||
63062306a36Sopenharmony_ci	    !ieee80211_hw_check(&local->hw, AMPDU_AGGREGATION) ||
63162306a36Sopenharmony_ci	    ieee80211_hw_check(&local->hw, TX_AMPDU_SETUP_IN_HW))
63262306a36Sopenharmony_ci		return -EINVAL;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	if (WARN_ON(tid >= IEEE80211_FIRST_TSPEC_TSID))
63562306a36Sopenharmony_ci		return -EINVAL;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	ht_dbg(sdata, "Open BA session requested for %pM tid %u\n",
63862306a36Sopenharmony_ci	       pubsta->addr, tid);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	if (sdata->vif.type != NL80211_IFTYPE_STATION &&
64162306a36Sopenharmony_ci	    sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
64262306a36Sopenharmony_ci	    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
64362306a36Sopenharmony_ci	    sdata->vif.type != NL80211_IFTYPE_AP &&
64462306a36Sopenharmony_ci	    sdata->vif.type != NL80211_IFTYPE_ADHOC)
64562306a36Sopenharmony_ci		return -EINVAL;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
64862306a36Sopenharmony_ci		ht_dbg(sdata,
64962306a36Sopenharmony_ci		       "BA sessions blocked - Denying BA session request %pM tid %d\n",
65062306a36Sopenharmony_ci		       sta->sta.addr, tid);
65162306a36Sopenharmony_ci		return -EINVAL;
65262306a36Sopenharmony_ci	}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	if (test_sta_flag(sta, WLAN_STA_MFP) &&
65562306a36Sopenharmony_ci	    !test_sta_flag(sta, WLAN_STA_AUTHORIZED)) {
65662306a36Sopenharmony_ci		ht_dbg(sdata,
65762306a36Sopenharmony_ci		       "MFP STA not authorized - deny BA session request %pM tid %d\n",
65862306a36Sopenharmony_ci		       sta->sta.addr, tid);
65962306a36Sopenharmony_ci		return -EINVAL;
66062306a36Sopenharmony_ci	}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	/*
66362306a36Sopenharmony_ci	 * 802.11n-2009 11.5.1.1: If the initiating STA is an HT STA, is a
66462306a36Sopenharmony_ci	 * member of an IBSS, and has no other existing Block Ack agreement
66562306a36Sopenharmony_ci	 * with the recipient STA, then the initiating STA shall transmit a
66662306a36Sopenharmony_ci	 * Probe Request frame to the recipient STA and shall not transmit an
66762306a36Sopenharmony_ci	 * ADDBA Request frame unless it receives a Probe Response frame
66862306a36Sopenharmony_ci	 * from the recipient within dot11ADDBAFailureTimeout.
66962306a36Sopenharmony_ci	 *
67062306a36Sopenharmony_ci	 * The probe request mechanism for ADDBA is currently not implemented,
67162306a36Sopenharmony_ci	 * but we only build up Block Ack session with HT STAs. This information
67262306a36Sopenharmony_ci	 * is set when we receive a bss info from a probe response or a beacon.
67362306a36Sopenharmony_ci	 */
67462306a36Sopenharmony_ci	if (sta->sdata->vif.type == NL80211_IFTYPE_ADHOC &&
67562306a36Sopenharmony_ci	    !sta->sta.deflink.ht_cap.ht_supported) {
67662306a36Sopenharmony_ci		ht_dbg(sdata,
67762306a36Sopenharmony_ci		       "BA request denied - IBSS STA %pM does not advertise HT support\n",
67862306a36Sopenharmony_ci		       pubsta->addr);
67962306a36Sopenharmony_ci		return -EINVAL;
68062306a36Sopenharmony_ci	}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	spin_lock_bh(&sta->lock);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	/* we have tried too many times, receiver does not want A-MPDU */
68562306a36Sopenharmony_ci	if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
68662306a36Sopenharmony_ci		ret = -EBUSY;
68762306a36Sopenharmony_ci		goto err_unlock_sta;
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	/*
69162306a36Sopenharmony_ci	 * if we have tried more than HT_AGG_BURST_RETRIES times we
69262306a36Sopenharmony_ci	 * will spread our requests in time to avoid stalling connection
69362306a36Sopenharmony_ci	 * for too long
69462306a36Sopenharmony_ci	 */
69562306a36Sopenharmony_ci	if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_BURST_RETRIES &&
69662306a36Sopenharmony_ci	    time_before(jiffies, sta->ampdu_mlme.last_addba_req_time[tid] +
69762306a36Sopenharmony_ci			HT_AGG_RETRIES_PERIOD)) {
69862306a36Sopenharmony_ci		ht_dbg(sdata,
69962306a36Sopenharmony_ci		       "BA request denied - %d failed requests on %pM tid %u\n",
70062306a36Sopenharmony_ci		       sta->ampdu_mlme.addba_req_num[tid], sta->sta.addr, tid);
70162306a36Sopenharmony_ci		ret = -EBUSY;
70262306a36Sopenharmony_ci		goto err_unlock_sta;
70362306a36Sopenharmony_ci	}
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
70662306a36Sopenharmony_ci	/* check if the TID is not in aggregation flow already */
70762306a36Sopenharmony_ci	if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) {
70862306a36Sopenharmony_ci		ht_dbg(sdata,
70962306a36Sopenharmony_ci		       "BA request denied - session is not idle on %pM tid %u\n",
71062306a36Sopenharmony_ci		       sta->sta.addr, tid);
71162306a36Sopenharmony_ci		ret = -EAGAIN;
71262306a36Sopenharmony_ci		goto err_unlock_sta;
71362306a36Sopenharmony_ci	}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	/* prepare A-MPDU MLME for Tx aggregation */
71662306a36Sopenharmony_ci	tid_tx = kzalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
71762306a36Sopenharmony_ci	if (!tid_tx) {
71862306a36Sopenharmony_ci		ret = -ENOMEM;
71962306a36Sopenharmony_ci		goto err_unlock_sta;
72062306a36Sopenharmony_ci	}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	skb_queue_head_init(&tid_tx->pending);
72362306a36Sopenharmony_ci	__set_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	tid_tx->timeout = timeout;
72662306a36Sopenharmony_ci	tid_tx->sta = sta;
72762306a36Sopenharmony_ci	tid_tx->tid = tid;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	/* response timer */
73062306a36Sopenharmony_ci	timer_setup(&tid_tx->addba_resp_timer, sta_addba_resp_timer_expired, 0);
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	/* tx timer */
73362306a36Sopenharmony_ci	timer_setup(&tid_tx->session_timer,
73462306a36Sopenharmony_ci		    sta_tx_agg_session_timer_expired, TIMER_DEFERRABLE);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	/* assign a dialog token */
73762306a36Sopenharmony_ci	sta->ampdu_mlme.dialog_token_allocator++;
73862306a36Sopenharmony_ci	tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	/*
74162306a36Sopenharmony_ci	 * Finally, assign it to the start array; the work item will
74262306a36Sopenharmony_ci	 * collect it and move it to the normal array.
74362306a36Sopenharmony_ci	 */
74462306a36Sopenharmony_ci	sta->ampdu_mlme.tid_start_tx[tid] = tid_tx;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	/* this flow continues off the work */
74962306a36Sopenharmony_ci err_unlock_sta:
75062306a36Sopenharmony_ci	spin_unlock_bh(&sta->lock);
75162306a36Sopenharmony_ci	return ret;
75262306a36Sopenharmony_ci}
75362306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_start_tx_ba_session);
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistatic void ieee80211_agg_tx_operational(struct ieee80211_local *local,
75662306a36Sopenharmony_ci					 struct sta_info *sta, u16 tid)
75762306a36Sopenharmony_ci{
75862306a36Sopenharmony_ci	struct tid_ampdu_tx *tid_tx;
75962306a36Sopenharmony_ci	struct ieee80211_ampdu_params params = {
76062306a36Sopenharmony_ci		.sta = &sta->sta,
76162306a36Sopenharmony_ci		.action = IEEE80211_AMPDU_TX_OPERATIONAL,
76262306a36Sopenharmony_ci		.tid = tid,
76362306a36Sopenharmony_ci		.timeout = 0,
76462306a36Sopenharmony_ci		.ssn = 0,
76562306a36Sopenharmony_ci	};
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	lockdep_assert_held(&sta->ampdu_mlme.mtx);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
77062306a36Sopenharmony_ci	params.buf_size = tid_tx->buf_size;
77162306a36Sopenharmony_ci	params.amsdu = tid_tx->amsdu;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	ht_dbg(sta->sdata, "Aggregation is on for %pM tid %d\n",
77462306a36Sopenharmony_ci	       sta->sta.addr, tid);
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	drv_ampdu_action(local, sta->sdata, &params);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	/*
77962306a36Sopenharmony_ci	 * synchronize with TX path, while splicing the TX path
78062306a36Sopenharmony_ci	 * should block so it won't put more packets onto pending.
78162306a36Sopenharmony_ci	 */
78262306a36Sopenharmony_ci	spin_lock_bh(&sta->lock);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	ieee80211_agg_splice_packets(sta->sdata, tid_tx, tid);
78562306a36Sopenharmony_ci	/*
78662306a36Sopenharmony_ci	 * Now mark as operational. This will be visible
78762306a36Sopenharmony_ci	 * in the TX path, and lets it go lock-free in
78862306a36Sopenharmony_ci	 * the common case.
78962306a36Sopenharmony_ci	 */
79062306a36Sopenharmony_ci	set_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
79162306a36Sopenharmony_ci	ieee80211_agg_splice_finish(sta->sdata, tid);
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	spin_unlock_bh(&sta->lock);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	ieee80211_agg_start_txq(sta, tid, true);
79662306a36Sopenharmony_ci}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_civoid ieee80211_start_tx_ba_cb(struct sta_info *sta, int tid,
79962306a36Sopenharmony_ci			      struct tid_ampdu_tx *tid_tx)
80062306a36Sopenharmony_ci{
80162306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = sta->sdata;
80262306a36Sopenharmony_ci	struct ieee80211_local *local = sdata->local;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	lockdep_assert_held(&sta->ampdu_mlme.mtx);
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	if (WARN_ON(test_and_set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state)))
80762306a36Sopenharmony_ci		return;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state) ||
81062306a36Sopenharmony_ci	    test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state))
81162306a36Sopenharmony_ci		return;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	if (!test_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state)) {
81462306a36Sopenharmony_ci		ieee80211_send_addba_with_timeout(sta, tid_tx);
81562306a36Sopenharmony_ci		/* RESPONSE_RECEIVED state whould trigger the flow again */
81662306a36Sopenharmony_ci		return;
81762306a36Sopenharmony_ci	}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	if (test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state))
82062306a36Sopenharmony_ci		ieee80211_agg_tx_operational(local, sta, tid);
82162306a36Sopenharmony_ci}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_cistatic struct tid_ampdu_tx *
82462306a36Sopenharmony_ciieee80211_lookup_tid_tx(struct ieee80211_sub_if_data *sdata,
82562306a36Sopenharmony_ci			const u8 *ra, u16 tid, struct sta_info **sta)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	struct tid_ampdu_tx *tid_tx;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	if (tid >= IEEE80211_NUM_TIDS) {
83062306a36Sopenharmony_ci		ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n",
83162306a36Sopenharmony_ci		       tid, IEEE80211_NUM_TIDS);
83262306a36Sopenharmony_ci		return NULL;
83362306a36Sopenharmony_ci	}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	*sta = sta_info_get_bss(sdata, ra);
83662306a36Sopenharmony_ci	if (!*sta) {
83762306a36Sopenharmony_ci		ht_dbg(sdata, "Could not find station: %pM\n", ra);
83862306a36Sopenharmony_ci		return NULL;
83962306a36Sopenharmony_ci	}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	tid_tx = rcu_dereference((*sta)->ampdu_mlme.tid_tx[tid]);
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	if (WARN_ON(!tid_tx))
84462306a36Sopenharmony_ci		ht_dbg(sdata, "addBA was not requested!\n");
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	return tid_tx;
84762306a36Sopenharmony_ci}
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_civoid ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
85062306a36Sopenharmony_ci				      const u8 *ra, u16 tid)
85162306a36Sopenharmony_ci{
85262306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
85362306a36Sopenharmony_ci	struct ieee80211_local *local = sdata->local;
85462306a36Sopenharmony_ci	struct sta_info *sta;
85562306a36Sopenharmony_ci	struct tid_ampdu_tx *tid_tx;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	trace_api_start_tx_ba_cb(sdata, ra, tid);
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	rcu_read_lock();
86062306a36Sopenharmony_ci	tid_tx = ieee80211_lookup_tid_tx(sdata, ra, tid, &sta);
86162306a36Sopenharmony_ci	if (!tid_tx)
86262306a36Sopenharmony_ci		goto out;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	set_bit(HT_AGG_STATE_START_CB, &tid_tx->state);
86562306a36Sopenharmony_ci	ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
86662306a36Sopenharmony_ci out:
86762306a36Sopenharmony_ci	rcu_read_unlock();
86862306a36Sopenharmony_ci}
86962306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ciint __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
87262306a36Sopenharmony_ci				   enum ieee80211_agg_stop_reason reason)
87362306a36Sopenharmony_ci{
87462306a36Sopenharmony_ci	int ret;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	mutex_lock(&sta->ampdu_mlme.mtx);
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	ret = ___ieee80211_stop_tx_ba_session(sta, tid, reason);
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	mutex_unlock(&sta->ampdu_mlme.mtx);
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	return ret;
88362306a36Sopenharmony_ci}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ciint ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
88662306a36Sopenharmony_ci{
88762306a36Sopenharmony_ci	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
88862306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = sta->sdata;
88962306a36Sopenharmony_ci	struct ieee80211_local *local = sdata->local;
89062306a36Sopenharmony_ci	struct tid_ampdu_tx *tid_tx;
89162306a36Sopenharmony_ci	int ret = 0;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	trace_api_stop_tx_ba_session(pubsta, tid);
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	if (!local->ops->ampdu_action)
89662306a36Sopenharmony_ci		return -EINVAL;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	if (tid >= IEEE80211_NUM_TIDS)
89962306a36Sopenharmony_ci		return -EINVAL;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	spin_lock_bh(&sta->lock);
90262306a36Sopenharmony_ci	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	if (!tid_tx) {
90562306a36Sopenharmony_ci		ret = -ENOENT;
90662306a36Sopenharmony_ci		goto unlock;
90762306a36Sopenharmony_ci	}
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	WARN(sta->reserved_tid == tid,
91062306a36Sopenharmony_ci	     "Requested to stop BA session on reserved tid=%d", tid);
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
91362306a36Sopenharmony_ci		/* already in progress stopping it */
91462306a36Sopenharmony_ci		ret = 0;
91562306a36Sopenharmony_ci		goto unlock;
91662306a36Sopenharmony_ci	}
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	set_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state);
91962306a36Sopenharmony_ci	ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci unlock:
92262306a36Sopenharmony_ci	spin_unlock_bh(&sta->lock);
92362306a36Sopenharmony_ci	return ret;
92462306a36Sopenharmony_ci}
92562306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_civoid ieee80211_stop_tx_ba_cb(struct sta_info *sta, int tid,
92862306a36Sopenharmony_ci			     struct tid_ampdu_tx *tid_tx)
92962306a36Sopenharmony_ci{
93062306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = sta->sdata;
93162306a36Sopenharmony_ci	bool send_delba = false;
93262306a36Sopenharmony_ci	bool start_txq = false;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	ht_dbg(sdata, "Stopping Tx BA session for %pM tid %d\n",
93562306a36Sopenharmony_ci	       sta->sta.addr, tid);
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	spin_lock_bh(&sta->lock);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	if (!test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
94062306a36Sopenharmony_ci		ht_dbg(sdata,
94162306a36Sopenharmony_ci		       "unexpected callback to A-MPDU stop for %pM tid %d\n",
94262306a36Sopenharmony_ci		       sta->sta.addr, tid);
94362306a36Sopenharmony_ci		goto unlock_sta;
94462306a36Sopenharmony_ci	}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	if (tid_tx->stop_initiator == WLAN_BACK_INITIATOR && tid_tx->tx_stop)
94762306a36Sopenharmony_ci		send_delba = true;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	ieee80211_remove_tid_tx(sta, tid);
95062306a36Sopenharmony_ci	start_txq = true;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci unlock_sta:
95362306a36Sopenharmony_ci	spin_unlock_bh(&sta->lock);
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	if (start_txq)
95662306a36Sopenharmony_ci		ieee80211_agg_start_txq(sta, tid, false);
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	if (send_delba)
95962306a36Sopenharmony_ci		ieee80211_send_delba(sdata, sta->sta.addr, tid,
96062306a36Sopenharmony_ci			WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
96162306a36Sopenharmony_ci}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_civoid ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
96462306a36Sopenharmony_ci				     const u8 *ra, u16 tid)
96562306a36Sopenharmony_ci{
96662306a36Sopenharmony_ci	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
96762306a36Sopenharmony_ci	struct ieee80211_local *local = sdata->local;
96862306a36Sopenharmony_ci	struct sta_info *sta;
96962306a36Sopenharmony_ci	struct tid_ampdu_tx *tid_tx;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	trace_api_stop_tx_ba_cb(sdata, ra, tid);
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	rcu_read_lock();
97462306a36Sopenharmony_ci	tid_tx = ieee80211_lookup_tid_tx(sdata, ra, tid, &sta);
97562306a36Sopenharmony_ci	if (!tid_tx)
97662306a36Sopenharmony_ci		goto out;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	set_bit(HT_AGG_STATE_STOP_CB, &tid_tx->state);
97962306a36Sopenharmony_ci	ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
98062306a36Sopenharmony_ci out:
98162306a36Sopenharmony_ci	rcu_read_unlock();
98262306a36Sopenharmony_ci}
98362306a36Sopenharmony_ciEXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_civoid ieee80211_process_addba_resp(struct ieee80211_local *local,
98762306a36Sopenharmony_ci				  struct sta_info *sta,
98862306a36Sopenharmony_ci				  struct ieee80211_mgmt *mgmt,
98962306a36Sopenharmony_ci				  size_t len)
99062306a36Sopenharmony_ci{
99162306a36Sopenharmony_ci	struct tid_ampdu_tx *tid_tx;
99262306a36Sopenharmony_ci	struct ieee80211_txq *txq;
99362306a36Sopenharmony_ci	u16 capab, tid, buf_size;
99462306a36Sopenharmony_ci	bool amsdu;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
99762306a36Sopenharmony_ci	amsdu = capab & IEEE80211_ADDBA_PARAM_AMSDU_MASK;
99862306a36Sopenharmony_ci	tid = u16_get_bits(capab, IEEE80211_ADDBA_PARAM_TID_MASK);
99962306a36Sopenharmony_ci	buf_size = u16_get_bits(capab, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK);
100062306a36Sopenharmony_ci	buf_size = min(buf_size, local->hw.max_tx_aggregation_subframes);
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	txq = sta->sta.txq[tid];
100362306a36Sopenharmony_ci	if (!amsdu && txq)
100462306a36Sopenharmony_ci		set_bit(IEEE80211_TXQ_NO_AMSDU, &to_txq_info(txq)->flags);
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	mutex_lock(&sta->ampdu_mlme.mtx);
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
100962306a36Sopenharmony_ci	if (!tid_tx)
101062306a36Sopenharmony_ci		goto out;
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	if (mgmt->u.action.u.addba_resp.dialog_token != tid_tx->dialog_token) {
101362306a36Sopenharmony_ci		ht_dbg(sta->sdata, "wrong addBA response token, %pM tid %d\n",
101462306a36Sopenharmony_ci		       sta->sta.addr, tid);
101562306a36Sopenharmony_ci		goto out;
101662306a36Sopenharmony_ci	}
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	del_timer_sync(&tid_tx->addba_resp_timer);
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	ht_dbg(sta->sdata, "switched off addBA timer for %pM tid %d\n",
102162306a36Sopenharmony_ci	       sta->sta.addr, tid);
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	/*
102462306a36Sopenharmony_ci	 * addba_resp_timer may have fired before we got here, and
102562306a36Sopenharmony_ci	 * caused WANT_STOP to be set. If the stop then was already
102662306a36Sopenharmony_ci	 * processed further, STOPPING might be set.
102762306a36Sopenharmony_ci	 */
102862306a36Sopenharmony_ci	if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) ||
102962306a36Sopenharmony_ci	    test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
103062306a36Sopenharmony_ci		ht_dbg(sta->sdata,
103162306a36Sopenharmony_ci		       "got addBA resp for %pM tid %d but we already gave up\n",
103262306a36Sopenharmony_ci		       sta->sta.addr, tid);
103362306a36Sopenharmony_ci		goto out;
103462306a36Sopenharmony_ci	}
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	/*
103762306a36Sopenharmony_ci	 * IEEE 802.11-2007 7.3.1.14:
103862306a36Sopenharmony_ci	 * In an ADDBA Response frame, when the Status Code field
103962306a36Sopenharmony_ci	 * is set to 0, the Buffer Size subfield is set to a value
104062306a36Sopenharmony_ci	 * of at least 1.
104162306a36Sopenharmony_ci	 */
104262306a36Sopenharmony_ci	if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
104362306a36Sopenharmony_ci			== WLAN_STATUS_SUCCESS && buf_size) {
104462306a36Sopenharmony_ci		if (test_and_set_bit(HT_AGG_STATE_RESPONSE_RECEIVED,
104562306a36Sopenharmony_ci				     &tid_tx->state)) {
104662306a36Sopenharmony_ci			/* ignore duplicate response */
104762306a36Sopenharmony_ci			goto out;
104862306a36Sopenharmony_ci		}
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci		tid_tx->buf_size = buf_size;
105162306a36Sopenharmony_ci		tid_tx->amsdu = amsdu;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci		if (test_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state))
105462306a36Sopenharmony_ci			ieee80211_agg_tx_operational(local, sta, tid);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci		sta->ampdu_mlme.addba_req_num[tid] = 0;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci		tid_tx->timeout =
105962306a36Sopenharmony_ci			le16_to_cpu(mgmt->u.action.u.addba_resp.timeout);
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci		if (tid_tx->timeout) {
106262306a36Sopenharmony_ci			mod_timer(&tid_tx->session_timer,
106362306a36Sopenharmony_ci				  TU_TO_EXP_TIME(tid_tx->timeout));
106462306a36Sopenharmony_ci			tid_tx->last_tx = jiffies;
106562306a36Sopenharmony_ci		}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	} else {
106862306a36Sopenharmony_ci		___ieee80211_stop_tx_ba_session(sta, tid, AGG_STOP_DECLINED);
106962306a36Sopenharmony_ci	}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci out:
107262306a36Sopenharmony_ci	mutex_unlock(&sta->ampdu_mlme.mtx);
107362306a36Sopenharmony_ci}
1074