xref: /openbmc/linux/net/mac80211/ht.c (revision 44d414dbff9d5bf46fc09f2e68567b5848cbbfd3)
1*44d414dbSJohannes Berg /*
2*44d414dbSJohannes Berg  * HT handling
3*44d414dbSJohannes Berg  *
4*44d414dbSJohannes Berg  * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
5*44d414dbSJohannes Berg  * Copyright 2004, Instant802 Networks, Inc.
6*44d414dbSJohannes Berg  * Copyright 2005, Devicescape Software, Inc.
7*44d414dbSJohannes Berg  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
8*44d414dbSJohannes Berg  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
9*44d414dbSJohannes Berg  * Copyright 2007-2008, Intel Corporation
10*44d414dbSJohannes Berg  *
11*44d414dbSJohannes Berg  * This program is free software; you can redistribute it and/or modify
12*44d414dbSJohannes Berg  * it under the terms of the GNU General Public License version 2 as
13*44d414dbSJohannes Berg  * published by the Free Software Foundation.
14*44d414dbSJohannes Berg  */
15*44d414dbSJohannes Berg 
16*44d414dbSJohannes Berg #include <linux/ieee80211.h>
17*44d414dbSJohannes Berg #include <net/wireless.h>
18*44d414dbSJohannes Berg #include <net/mac80211.h>
19*44d414dbSJohannes Berg #include "ieee80211_i.h"
20*44d414dbSJohannes Berg #include "sta_info.h"
21*44d414dbSJohannes Berg 
22*44d414dbSJohannes Berg int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
23*44d414dbSJohannes Berg 				   struct ieee80211_ht_info *ht_info)
24*44d414dbSJohannes Berg {
25*44d414dbSJohannes Berg 
26*44d414dbSJohannes Berg 	if (ht_info == NULL)
27*44d414dbSJohannes Berg 		return -EINVAL;
28*44d414dbSJohannes Berg 
29*44d414dbSJohannes Berg 	memset(ht_info, 0, sizeof(*ht_info));
30*44d414dbSJohannes Berg 
31*44d414dbSJohannes Berg 	if (ht_cap_ie) {
32*44d414dbSJohannes Berg 		u8 ampdu_info = ht_cap_ie->ampdu_params_info;
33*44d414dbSJohannes Berg 
34*44d414dbSJohannes Berg 		ht_info->ht_supported = 1;
35*44d414dbSJohannes Berg 		ht_info->cap = le16_to_cpu(ht_cap_ie->cap_info);
36*44d414dbSJohannes Berg 		ht_info->ampdu_factor =
37*44d414dbSJohannes Berg 			ampdu_info & IEEE80211_HT_CAP_AMPDU_FACTOR;
38*44d414dbSJohannes Berg 		ht_info->ampdu_density =
39*44d414dbSJohannes Berg 			(ampdu_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2;
40*44d414dbSJohannes Berg 		memcpy(ht_info->supp_mcs_set, ht_cap_ie->supp_mcs_set, 16);
41*44d414dbSJohannes Berg 	} else
42*44d414dbSJohannes Berg 		ht_info->ht_supported = 0;
43*44d414dbSJohannes Berg 
44*44d414dbSJohannes Berg 	return 0;
45*44d414dbSJohannes Berg }
46*44d414dbSJohannes Berg 
47*44d414dbSJohannes Berg int ieee80211_ht_addt_info_ie_to_ht_bss_info(
48*44d414dbSJohannes Berg 			struct ieee80211_ht_addt_info *ht_add_info_ie,
49*44d414dbSJohannes Berg 			struct ieee80211_ht_bss_info *bss_info)
50*44d414dbSJohannes Berg {
51*44d414dbSJohannes Berg 	if (bss_info == NULL)
52*44d414dbSJohannes Berg 		return -EINVAL;
53*44d414dbSJohannes Berg 
54*44d414dbSJohannes Berg 	memset(bss_info, 0, sizeof(*bss_info));
55*44d414dbSJohannes Berg 
56*44d414dbSJohannes Berg 	if (ht_add_info_ie) {
57*44d414dbSJohannes Berg 		u16 op_mode;
58*44d414dbSJohannes Berg 		op_mode = le16_to_cpu(ht_add_info_ie->operation_mode);
59*44d414dbSJohannes Berg 
60*44d414dbSJohannes Berg 		bss_info->primary_channel = ht_add_info_ie->control_chan;
61*44d414dbSJohannes Berg 		bss_info->bss_cap = ht_add_info_ie->ht_param;
62*44d414dbSJohannes Berg 		bss_info->bss_op_mode = (u8)(op_mode & 0xff);
63*44d414dbSJohannes Berg 	}
64*44d414dbSJohannes Berg 
65*44d414dbSJohannes Berg 	return 0;
66*44d414dbSJohannes Berg }
67*44d414dbSJohannes Berg 
68*44d414dbSJohannes Berg void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, const u8 *da,
69*44d414dbSJohannes Berg 				u16 tid, u8 dialog_token, u16 start_seq_num,
70*44d414dbSJohannes Berg 				u16 agg_size, u16 timeout)
71*44d414dbSJohannes Berg {
72*44d414dbSJohannes Berg 	struct ieee80211_local *local = sdata->local;
73*44d414dbSJohannes Berg 	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
74*44d414dbSJohannes Berg 	struct sk_buff *skb;
75*44d414dbSJohannes Berg 	struct ieee80211_mgmt *mgmt;
76*44d414dbSJohannes Berg 	u16 capab;
77*44d414dbSJohannes Berg 
78*44d414dbSJohannes Berg 	skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
79*44d414dbSJohannes Berg 
80*44d414dbSJohannes Berg 	if (!skb) {
81*44d414dbSJohannes Berg 		printk(KERN_ERR "%s: failed to allocate buffer "
82*44d414dbSJohannes Berg 				"for addba request frame\n", sdata->dev->name);
83*44d414dbSJohannes Berg 		return;
84*44d414dbSJohannes Berg 	}
85*44d414dbSJohannes Berg 	skb_reserve(skb, local->hw.extra_tx_headroom);
86*44d414dbSJohannes Berg 	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
87*44d414dbSJohannes Berg 	memset(mgmt, 0, 24);
88*44d414dbSJohannes Berg 	memcpy(mgmt->da, da, ETH_ALEN);
89*44d414dbSJohannes Berg 	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
90*44d414dbSJohannes Berg 	if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
91*44d414dbSJohannes Berg 		memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
92*44d414dbSJohannes Berg 	else
93*44d414dbSJohannes Berg 		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
94*44d414dbSJohannes Berg 
95*44d414dbSJohannes Berg 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
96*44d414dbSJohannes Berg 					  IEEE80211_STYPE_ACTION);
97*44d414dbSJohannes Berg 
98*44d414dbSJohannes Berg 	skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
99*44d414dbSJohannes Berg 
100*44d414dbSJohannes Berg 	mgmt->u.action.category = WLAN_CATEGORY_BACK;
101*44d414dbSJohannes Berg 	mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
102*44d414dbSJohannes Berg 
103*44d414dbSJohannes Berg 	mgmt->u.action.u.addba_req.dialog_token = dialog_token;
104*44d414dbSJohannes Berg 	capab = (u16)(1 << 1);		/* bit 1 aggregation policy */
105*44d414dbSJohannes Berg 	capab |= (u16)(tid << 2); 	/* bit 5:2 TID number */
106*44d414dbSJohannes Berg 	capab |= (u16)(agg_size << 6);	/* bit 15:6 max size of aggergation */
107*44d414dbSJohannes Berg 
108*44d414dbSJohannes Berg 	mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
109*44d414dbSJohannes Berg 
110*44d414dbSJohannes Berg 	mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
111*44d414dbSJohannes Berg 	mgmt->u.action.u.addba_req.start_seq_num =
112*44d414dbSJohannes Berg 					cpu_to_le16(start_seq_num << 4);
113*44d414dbSJohannes Berg 
114*44d414dbSJohannes Berg 	ieee80211_sta_tx(sdata, skb, 0);
115*44d414dbSJohannes Berg }
116*44d414dbSJohannes Berg 
117*44d414dbSJohannes Berg void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, const u8 *da, u16 tid,
118*44d414dbSJohannes Berg 			  u16 initiator, u16 reason_code)
119*44d414dbSJohannes Berg {
120*44d414dbSJohannes Berg 	struct ieee80211_local *local = sdata->local;
121*44d414dbSJohannes Berg 	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
122*44d414dbSJohannes Berg 	struct sk_buff *skb;
123*44d414dbSJohannes Berg 	struct ieee80211_mgmt *mgmt;
124*44d414dbSJohannes Berg 	u16 params;
125*44d414dbSJohannes Berg 
126*44d414dbSJohannes Berg 	skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
127*44d414dbSJohannes Berg 
128*44d414dbSJohannes Berg 	if (!skb) {
129*44d414dbSJohannes Berg 		printk(KERN_ERR "%s: failed to allocate buffer "
130*44d414dbSJohannes Berg 					"for delba frame\n", sdata->dev->name);
131*44d414dbSJohannes Berg 		return;
132*44d414dbSJohannes Berg 	}
133*44d414dbSJohannes Berg 
134*44d414dbSJohannes Berg 	skb_reserve(skb, local->hw.extra_tx_headroom);
135*44d414dbSJohannes Berg 	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
136*44d414dbSJohannes Berg 	memset(mgmt, 0, 24);
137*44d414dbSJohannes Berg 	memcpy(mgmt->da, da, ETH_ALEN);
138*44d414dbSJohannes Berg 	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
139*44d414dbSJohannes Berg 	if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
140*44d414dbSJohannes Berg 		memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
141*44d414dbSJohannes Berg 	else
142*44d414dbSJohannes Berg 		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
143*44d414dbSJohannes Berg 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
144*44d414dbSJohannes Berg 					  IEEE80211_STYPE_ACTION);
145*44d414dbSJohannes Berg 
146*44d414dbSJohannes Berg 	skb_put(skb, 1 + sizeof(mgmt->u.action.u.delba));
147*44d414dbSJohannes Berg 
148*44d414dbSJohannes Berg 	mgmt->u.action.category = WLAN_CATEGORY_BACK;
149*44d414dbSJohannes Berg 	mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA;
150*44d414dbSJohannes Berg 	params = (u16)(initiator << 11); 	/* bit 11 initiator */
151*44d414dbSJohannes Berg 	params |= (u16)(tid << 12); 		/* bit 15:12 TID number */
152*44d414dbSJohannes Berg 
153*44d414dbSJohannes Berg 	mgmt->u.action.u.delba.params = cpu_to_le16(params);
154*44d414dbSJohannes Berg 	mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
155*44d414dbSJohannes Berg 
156*44d414dbSJohannes Berg 	ieee80211_sta_tx(sdata, skb, 0);
157*44d414dbSJohannes Berg }
158*44d414dbSJohannes Berg 
159*44d414dbSJohannes Berg void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn)
160*44d414dbSJohannes Berg {
161*44d414dbSJohannes Berg 	struct ieee80211_local *local = sdata->local;
162*44d414dbSJohannes Berg 	struct sk_buff *skb;
163*44d414dbSJohannes Berg 	struct ieee80211_bar *bar;
164*44d414dbSJohannes Berg 	u16 bar_control = 0;
165*44d414dbSJohannes Berg 
166*44d414dbSJohannes Berg 	skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
167*44d414dbSJohannes Berg 	if (!skb) {
168*44d414dbSJohannes Berg 		printk(KERN_ERR "%s: failed to allocate buffer for "
169*44d414dbSJohannes Berg 			"bar frame\n", sdata->dev->name);
170*44d414dbSJohannes Berg 		return;
171*44d414dbSJohannes Berg 	}
172*44d414dbSJohannes Berg 	skb_reserve(skb, local->hw.extra_tx_headroom);
173*44d414dbSJohannes Berg 	bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar));
174*44d414dbSJohannes Berg 	memset(bar, 0, sizeof(*bar));
175*44d414dbSJohannes Berg 	bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
176*44d414dbSJohannes Berg 					 IEEE80211_STYPE_BACK_REQ);
177*44d414dbSJohannes Berg 	memcpy(bar->ra, ra, ETH_ALEN);
178*44d414dbSJohannes Berg 	memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN);
179*44d414dbSJohannes Berg 	bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
180*44d414dbSJohannes Berg 	bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
181*44d414dbSJohannes Berg 	bar_control |= (u16)(tid << 12);
182*44d414dbSJohannes Berg 	bar->control = cpu_to_le16(bar_control);
183*44d414dbSJohannes Berg 	bar->start_seq_num = cpu_to_le16(ssn);
184*44d414dbSJohannes Berg 
185*44d414dbSJohannes Berg 	ieee80211_sta_tx(sdata, skb, 0);
186*44d414dbSJohannes Berg }
187*44d414dbSJohannes Berg 
188*44d414dbSJohannes Berg void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid,
189*44d414dbSJohannes Berg 					u16 initiator, u16 reason)
190*44d414dbSJohannes Berg {
191*44d414dbSJohannes Berg 	struct ieee80211_local *local = sdata->local;
192*44d414dbSJohannes Berg 	struct ieee80211_hw *hw = &local->hw;
193*44d414dbSJohannes Berg 	struct sta_info *sta;
194*44d414dbSJohannes Berg 	int ret, i;
195*44d414dbSJohannes Berg 	DECLARE_MAC_BUF(mac);
196*44d414dbSJohannes Berg 
197*44d414dbSJohannes Berg 	rcu_read_lock();
198*44d414dbSJohannes Berg 
199*44d414dbSJohannes Berg 	sta = sta_info_get(local, ra);
200*44d414dbSJohannes Berg 	if (!sta) {
201*44d414dbSJohannes Berg 		rcu_read_unlock();
202*44d414dbSJohannes Berg 		return;
203*44d414dbSJohannes Berg 	}
204*44d414dbSJohannes Berg 
205*44d414dbSJohannes Berg 	/* check if TID is in operational state */
206*44d414dbSJohannes Berg 	spin_lock_bh(&sta->lock);
207*44d414dbSJohannes Berg 	if (sta->ampdu_mlme.tid_state_rx[tid]
208*44d414dbSJohannes Berg 				!= HT_AGG_STATE_OPERATIONAL) {
209*44d414dbSJohannes Berg 		spin_unlock_bh(&sta->lock);
210*44d414dbSJohannes Berg 		rcu_read_unlock();
211*44d414dbSJohannes Berg 		return;
212*44d414dbSJohannes Berg 	}
213*44d414dbSJohannes Berg 	sta->ampdu_mlme.tid_state_rx[tid] =
214*44d414dbSJohannes Berg 		HT_AGG_STATE_REQ_STOP_BA_MSK |
215*44d414dbSJohannes Berg 		(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
216*44d414dbSJohannes Berg 	spin_unlock_bh(&sta->lock);
217*44d414dbSJohannes Berg 
218*44d414dbSJohannes Berg 	/* stop HW Rx aggregation. ampdu_action existence
219*44d414dbSJohannes Berg 	 * already verified in session init so we add the BUG_ON */
220*44d414dbSJohannes Berg 	BUG_ON(!local->ops->ampdu_action);
221*44d414dbSJohannes Berg 
222*44d414dbSJohannes Berg #ifdef CONFIG_MAC80211_HT_DEBUG
223*44d414dbSJohannes Berg 	printk(KERN_DEBUG "Rx BA session stop requested for %s tid %u\n",
224*44d414dbSJohannes Berg 				print_mac(mac, ra), tid);
225*44d414dbSJohannes Berg #endif /* CONFIG_MAC80211_HT_DEBUG */
226*44d414dbSJohannes Berg 
227*44d414dbSJohannes Berg 	ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
228*44d414dbSJohannes Berg 					ra, tid, NULL);
229*44d414dbSJohannes Berg 	if (ret)
230*44d414dbSJohannes Berg 		printk(KERN_DEBUG "HW problem - can not stop rx "
231*44d414dbSJohannes Berg 				"aggregation for tid %d\n", tid);
232*44d414dbSJohannes Berg 
233*44d414dbSJohannes Berg 	/* shutdown timer has not expired */
234*44d414dbSJohannes Berg 	if (initiator != WLAN_BACK_TIMER)
235*44d414dbSJohannes Berg 		del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
236*44d414dbSJohannes Berg 
237*44d414dbSJohannes Berg 	/* check if this is a self generated aggregation halt */
238*44d414dbSJohannes Berg 	if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER)
239*44d414dbSJohannes Berg 		ieee80211_send_delba(sdata, ra, tid, 0, reason);
240*44d414dbSJohannes Berg 
241*44d414dbSJohannes Berg 	/* free the reordering buffer */
242*44d414dbSJohannes Berg 	for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) {
243*44d414dbSJohannes Berg 		if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) {
244*44d414dbSJohannes Berg 			/* release the reordered frames */
245*44d414dbSJohannes Berg 			dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]);
246*44d414dbSJohannes Berg 			sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--;
247*44d414dbSJohannes Berg 			sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL;
248*44d414dbSJohannes Berg 		}
249*44d414dbSJohannes Berg 	}
250*44d414dbSJohannes Berg 	/* free resources */
251*44d414dbSJohannes Berg 	kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf);
252*44d414dbSJohannes Berg 	kfree(sta->ampdu_mlme.tid_rx[tid]);
253*44d414dbSJohannes Berg 	sta->ampdu_mlme.tid_rx[tid] = NULL;
254*44d414dbSJohannes Berg 	sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE;
255*44d414dbSJohannes Berg 
256*44d414dbSJohannes Berg 	rcu_read_unlock();
257*44d414dbSJohannes Berg }
258*44d414dbSJohannes Berg 
259*44d414dbSJohannes Berg 
260*44d414dbSJohannes Berg /*
261*44d414dbSJohannes Berg  * After sending add Block Ack request we activated a timer until
262*44d414dbSJohannes Berg  * add Block Ack response will arrive from the recipient.
263*44d414dbSJohannes Berg  * If this timer expires sta_addba_resp_timer_expired will be executed.
264*44d414dbSJohannes Berg  */
265*44d414dbSJohannes Berg void sta_addba_resp_timer_expired(unsigned long data)
266*44d414dbSJohannes Berg {
267*44d414dbSJohannes Berg 	/* not an elegant detour, but there is no choice as the timer passes
268*44d414dbSJohannes Berg 	 * only one argument, and both sta_info and TID are needed, so init
269*44d414dbSJohannes Berg 	 * flow in sta_info_create gives the TID as data, while the timer_to_id
270*44d414dbSJohannes Berg 	 * array gives the sta through container_of */
271*44d414dbSJohannes Berg 	u16 tid = *(u8 *)data;
272*44d414dbSJohannes Berg 	struct sta_info *temp_sta = container_of((void *)data,
273*44d414dbSJohannes Berg 		struct sta_info, timer_to_tid[tid]);
274*44d414dbSJohannes Berg 
275*44d414dbSJohannes Berg 	struct ieee80211_local *local = temp_sta->local;
276*44d414dbSJohannes Berg 	struct ieee80211_hw *hw = &local->hw;
277*44d414dbSJohannes Berg 	struct sta_info *sta;
278*44d414dbSJohannes Berg 	u8 *state;
279*44d414dbSJohannes Berg 
280*44d414dbSJohannes Berg 	rcu_read_lock();
281*44d414dbSJohannes Berg 
282*44d414dbSJohannes Berg 	sta = sta_info_get(local, temp_sta->addr);
283*44d414dbSJohannes Berg 	if (!sta) {
284*44d414dbSJohannes Berg 		rcu_read_unlock();
285*44d414dbSJohannes Berg 		return;
286*44d414dbSJohannes Berg 	}
287*44d414dbSJohannes Berg 
288*44d414dbSJohannes Berg 	state = &sta->ampdu_mlme.tid_state_tx[tid];
289*44d414dbSJohannes Berg 	/* check if the TID waits for addBA response */
290*44d414dbSJohannes Berg 	spin_lock_bh(&sta->lock);
291*44d414dbSJohannes Berg 	if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
292*44d414dbSJohannes Berg 		spin_unlock_bh(&sta->lock);
293*44d414dbSJohannes Berg 		*state = HT_AGG_STATE_IDLE;
294*44d414dbSJohannes Berg #ifdef CONFIG_MAC80211_HT_DEBUG
295*44d414dbSJohannes Berg 		printk(KERN_DEBUG "timer expired on tid %d but we are not "
296*44d414dbSJohannes Berg 				"expecting addBA response there", tid);
297*44d414dbSJohannes Berg #endif
298*44d414dbSJohannes Berg 		goto timer_expired_exit;
299*44d414dbSJohannes Berg 	}
300*44d414dbSJohannes Berg 
301*44d414dbSJohannes Berg #ifdef CONFIG_MAC80211_HT_DEBUG
302*44d414dbSJohannes Berg 	printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
303*44d414dbSJohannes Berg #endif
304*44d414dbSJohannes Berg 
305*44d414dbSJohannes Berg 	/* go through the state check in stop_BA_session */
306*44d414dbSJohannes Berg 	*state = HT_AGG_STATE_OPERATIONAL;
307*44d414dbSJohannes Berg 	spin_unlock_bh(&sta->lock);
308*44d414dbSJohannes Berg 	ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid,
309*44d414dbSJohannes Berg 				     WLAN_BACK_INITIATOR);
310*44d414dbSJohannes Berg 
311*44d414dbSJohannes Berg timer_expired_exit:
312*44d414dbSJohannes Berg 	rcu_read_unlock();
313*44d414dbSJohannes Berg }
314*44d414dbSJohannes Berg 
315*44d414dbSJohannes Berg void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr)
316*44d414dbSJohannes Berg {
317*44d414dbSJohannes Berg 	struct ieee80211_local *local = sdata->local;
318*44d414dbSJohannes Berg 	int i;
319*44d414dbSJohannes Berg 
320*44d414dbSJohannes Berg 	for (i = 0; i <  STA_TID_NUM; i++) {
321*44d414dbSJohannes Berg 		ieee80211_stop_tx_ba_session(&local->hw, addr, i,
322*44d414dbSJohannes Berg 					     WLAN_BACK_INITIATOR);
323*44d414dbSJohannes Berg 		ieee80211_sta_stop_rx_ba_session(sdata, addr, i,
324*44d414dbSJohannes Berg 						 WLAN_BACK_RECIPIENT,
325*44d414dbSJohannes Berg 						 WLAN_REASON_QSTA_LEAVE_QBSS);
326*44d414dbSJohannes Berg 	}
327*44d414dbSJohannes Berg }
328*44d414dbSJohannes Berg 
329