blob: c5c0c5271096ca7ae3369c2d99b0eeafe34bd413 [file] [log] [blame]
Johannes Berg44d414d2008-09-08 17:44:28 +02001/*
2 * HT handling
3 *
4 * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
Johannes Bergbacac542008-09-08 17:44:29 +02005 * Copyright 2002-2005, Instant802 Networks, Inc.
6 * Copyright 2005-2006, Devicescape Software, Inc.
Johannes Berg44d414d2008-09-08 17:44:28 +02007 * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
8 * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
9 * Copyright 2007-2008, Intel Corporation
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 */
15
16#include <linux/ieee80211.h>
17#include <net/wireless.h>
18#include <net/mac80211.h>
19#include "ieee80211_i.h"
20#include "sta_info.h"
Johannes Bergbacac542008-09-08 17:44:29 +020021#include "wme.h"
Johannes Berg44d414d2008-09-08 17:44:28 +020022
Johannes Bergae5eb022008-10-14 16:58:37 +020023void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
24 struct ieee80211_ht_cap *ht_cap_ie,
Johannes Bergd9fe60d2008-10-09 12:13:49 +020025 struct ieee80211_sta_ht_cap *ht_cap)
Johannes Berg44d414d2008-09-08 17:44:28 +020026{
Johannes Bergae5eb022008-10-14 16:58:37 +020027 u8 ampdu_info, tx_mcs_set_cap;
28 int i, max_tx_streams;
Johannes Berg44d414d2008-09-08 17:44:28 +020029
Johannes Bergd9fe60d2008-10-09 12:13:49 +020030 BUG_ON(!ht_cap);
Johannes Berg44d414d2008-09-08 17:44:28 +020031
Johannes Bergd9fe60d2008-10-09 12:13:49 +020032 memset(ht_cap, 0, sizeof(*ht_cap));
Johannes Berg44d414d2008-09-08 17:44:28 +020033
Johannes Bergae5eb022008-10-14 16:58:37 +020034 if (!ht_cap_ie)
35 return;
Johannes Berg44d414d2008-09-08 17:44:28 +020036
Johannes Bergae5eb022008-10-14 16:58:37 +020037 ht_cap->ht_supported = true;
Johannes Berg44d414d2008-09-08 17:44:28 +020038
Sujithf16f33d2008-11-14 16:27:53 +053039 ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info) & sband->ht_cap.cap;
Johannes Bergae5eb022008-10-14 16:58:37 +020040 ht_cap->cap &= ~IEEE80211_HT_CAP_SM_PS;
41 ht_cap->cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS;
Johannes Berg44d414d2008-09-08 17:44:28 +020042
Johannes Bergae5eb022008-10-14 16:58:37 +020043 ampdu_info = ht_cap_ie->ampdu_params_info;
44 ht_cap->ampdu_factor =
45 ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR;
46 ht_cap->ampdu_density =
47 (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
Johannes Bergd9fe60d2008-10-09 12:13:49 +020048
49 /* own MCS TX capabilities */
50 tx_mcs_set_cap = sband->ht_cap.mcs.tx_params;
51
Johannes Bergd9fe60d2008-10-09 12:13:49 +020052 /* can we TX with MCS rates? */
53 if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED))
Johannes Bergae5eb022008-10-14 16:58:37 +020054 return;
Johannes Bergd9fe60d2008-10-09 12:13:49 +020055
56 /* Counting from 0, therefore +1 */
57 if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF)
58 max_tx_streams =
59 ((tx_mcs_set_cap & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
60 >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1;
61 else
62 max_tx_streams = IEEE80211_HT_MCS_TX_MAX_STREAMS;
63
64 /*
65 * 802.11n D5.0 20.3.5 / 20.6 says:
66 * - indices 0 to 7 and 32 are single spatial stream
67 * - 8 to 31 are multiple spatial streams using equal modulation
68 * [8..15 for two streams, 16..23 for three and 24..31 for four]
69 * - remainder are multiple spatial streams using unequal modulation
70 */
71 for (i = 0; i < max_tx_streams; i++)
Johannes Bergae5eb022008-10-14 16:58:37 +020072 ht_cap->mcs.rx_mask[i] =
73 sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i];
Johannes Bergd9fe60d2008-10-09 12:13:49 +020074
75 if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION)
76 for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE;
77 i < IEEE80211_HT_MCS_MASK_LEN; i++)
Johannes Bergae5eb022008-10-14 16:58:37 +020078 ht_cap->mcs.rx_mask[i] =
Johannes Bergd9fe60d2008-10-09 12:13:49 +020079 sband->ht_cap.mcs.rx_mask[i] &
Johannes Bergae5eb022008-10-14 16:58:37 +020080 ht_cap_ie->mcs.rx_mask[i];
Johannes Bergd9fe60d2008-10-09 12:13:49 +020081
82 /* handle MCS rate 32 too */
Johannes Bergae5eb022008-10-14 16:58:37 +020083 if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
84 ht_cap->mcs.rx_mask[32/8] |= 1;
85}
Johannes Bergd9fe60d2008-10-09 12:13:49 +020086
Johannes Bergae5eb022008-10-14 16:58:37 +020087/*
88 * ieee80211_enable_ht should be called only after the operating band
89 * has been determined as ht configuration depends on the hw's
90 * HT abilities for a specific band.
91 */
92u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
93 struct ieee80211_ht_info *hti,
94 u16 ap_ht_cap_flags)
95{
96 struct ieee80211_local *local = sdata->local;
97 struct ieee80211_supported_band *sband;
98 struct ieee80211_bss_ht_conf ht;
99 u32 changed = 0;
100 bool enable_ht = true, ht_changed;
Sujith094d05d2008-12-12 11:57:43 +0530101 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
Johannes Bergae5eb022008-10-14 16:58:37 +0200102
103 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
104
105 memset(&ht, 0, sizeof(ht));
106
107 /* HT is not supported */
108 if (!sband->ht_cap.ht_supported)
109 enable_ht = false;
110
111 /* check that channel matches the right operating channel */
112 if (local->hw.conf.channel->center_freq !=
113 ieee80211_channel_to_frequency(hti->control_chan))
114 enable_ht = false;
115
Sujith094d05d2008-12-12 11:57:43 +0530116 if (enable_ht) {
117 channel_type = NL80211_CHAN_HT20;
118
119 if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
120 (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
121 (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
122 switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
123 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
124 channel_type = NL80211_CHAN_HT40PLUS;
125 break;
126 case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
127 channel_type = NL80211_CHAN_HT40MINUS;
128 break;
129 }
130 }
131 }
132
133 ht_changed = local->hw.conf.ht.enabled != enable_ht ||
134 channel_type != local->hw.conf.ht.channel_type;
135
136 local->oper_channel_type = channel_type;
Johannes Bergae5eb022008-10-14 16:58:37 +0200137 local->hw.conf.ht.enabled = enable_ht;
Sujith094d05d2008-12-12 11:57:43 +0530138
Johannes Bergae5eb022008-10-14 16:58:37 +0200139 if (ht_changed)
140 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT);
141
142 /* disable HT */
143 if (!enable_ht)
144 return 0;
Sujith094d05d2008-12-12 11:57:43 +0530145
Johannes Bergae5eb022008-10-14 16:58:37 +0200146 ht.operation_mode = le16_to_cpu(hti->operation_mode);
147
Johannes Bergd9fe60d2008-10-09 12:13:49 +0200148 /* if bss configuration changed store the new one */
Johannes Bergae5eb022008-10-14 16:58:37 +0200149 if (memcmp(&sdata->vif.bss_conf.ht, &ht, sizeof(ht))) {
Johannes Bergd9fe60d2008-10-09 12:13:49 +0200150 changed |= BSS_CHANGED_HT;
Johannes Bergae5eb022008-10-14 16:58:37 +0200151 sdata->vif.bss_conf.ht = ht;
Johannes Bergd9fe60d2008-10-09 12:13:49 +0200152 }
153
154 return changed;
Johannes Berg44d414d2008-09-08 17:44:28 +0200155}
156
Johannes Bergde1ede72008-09-09 14:42:50 +0200157static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
158 const u8 *da, u16 tid,
159 u8 dialog_token, u16 start_seq_num,
160 u16 agg_size, u16 timeout)
Johannes Berg44d414d2008-09-08 17:44:28 +0200161{
162 struct ieee80211_local *local = sdata->local;
163 struct ieee80211_if_sta *ifsta = &sdata->u.sta;
164 struct sk_buff *skb;
165 struct ieee80211_mgmt *mgmt;
166 u16 capab;
167
168 skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
169
170 if (!skb) {
171 printk(KERN_ERR "%s: failed to allocate buffer "
172 "for addba request frame\n", sdata->dev->name);
173 return;
174 }
175 skb_reserve(skb, local->hw.extra_tx_headroom);
176 mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
177 memset(mgmt, 0, 24);
178 memcpy(mgmt->da, da, ETH_ALEN);
179 memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
Johannes Berg05c914f2008-09-11 00:01:58 +0200180 if (sdata->vif.type == NL80211_IFTYPE_AP)
Johannes Berg44d414d2008-09-08 17:44:28 +0200181 memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
182 else
183 memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
184
185 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
186 IEEE80211_STYPE_ACTION);
187
188 skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
189
190 mgmt->u.action.category = WLAN_CATEGORY_BACK;
191 mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
192
193 mgmt->u.action.u.addba_req.dialog_token = dialog_token;
194 capab = (u16)(1 << 1); /* bit 1 aggregation policy */
195 capab |= (u16)(tid << 2); /* bit 5:2 TID number */
196 capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */
197
198 mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
199
200 mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
201 mgmt->u.action.u.addba_req.start_seq_num =
202 cpu_to_le16(start_seq_num << 4);
203
Johannes Berge50db652008-09-09 15:07:09 +0200204 ieee80211_tx_skb(sdata, skb, 0);
Johannes Berg44d414d2008-09-08 17:44:28 +0200205}
206
Johannes Bergde1ede72008-09-09 14:42:50 +0200207static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
208 u8 dialog_token, u16 status, u16 policy,
209 u16 buf_size, u16 timeout)
210{
211 struct ieee80211_if_sta *ifsta = &sdata->u.sta;
212 struct ieee80211_local *local = sdata->local;
213 struct sk_buff *skb;
214 struct ieee80211_mgmt *mgmt;
215 u16 capab;
216
217 skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
218
219 if (!skb) {
220 printk(KERN_DEBUG "%s: failed to allocate buffer "
221 "for addba resp frame\n", sdata->dev->name);
222 return;
223 }
224
225 skb_reserve(skb, local->hw.extra_tx_headroom);
226 mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
227 memset(mgmt, 0, 24);
228 memcpy(mgmt->da, da, ETH_ALEN);
229 memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
Johannes Berg05c914f2008-09-11 00:01:58 +0200230 if (sdata->vif.type == NL80211_IFTYPE_AP)
Johannes Bergde1ede72008-09-09 14:42:50 +0200231 memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
232 else
233 memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
234 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
235 IEEE80211_STYPE_ACTION);
236
237 skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
238 mgmt->u.action.category = WLAN_CATEGORY_BACK;
239 mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
240 mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
241
242 capab = (u16)(policy << 1); /* bit 1 aggregation policy */
243 capab |= (u16)(tid << 2); /* bit 5:2 TID number */
244 capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */
245
246 mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
247 mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
248 mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
249
Johannes Berge50db652008-09-09 15:07:09 +0200250 ieee80211_tx_skb(sdata, skb, 0);
Johannes Bergde1ede72008-09-09 14:42:50 +0200251}
252
253static void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
254 const u8 *da, u16 tid,
255 u16 initiator, u16 reason_code)
Johannes Berg44d414d2008-09-08 17:44:28 +0200256{
257 struct ieee80211_local *local = sdata->local;
258 struct ieee80211_if_sta *ifsta = &sdata->u.sta;
259 struct sk_buff *skb;
260 struct ieee80211_mgmt *mgmt;
261 u16 params;
262
263 skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
264
265 if (!skb) {
266 printk(KERN_ERR "%s: failed to allocate buffer "
267 "for delba frame\n", sdata->dev->name);
268 return;
269 }
270
271 skb_reserve(skb, local->hw.extra_tx_headroom);
272 mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
273 memset(mgmt, 0, 24);
274 memcpy(mgmt->da, da, ETH_ALEN);
275 memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
Johannes Berg05c914f2008-09-11 00:01:58 +0200276 if (sdata->vif.type == NL80211_IFTYPE_AP)
Johannes Berg44d414d2008-09-08 17:44:28 +0200277 memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
278 else
279 memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
280 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
281 IEEE80211_STYPE_ACTION);
282
283 skb_put(skb, 1 + sizeof(mgmt->u.action.u.delba));
284
285 mgmt->u.action.category = WLAN_CATEGORY_BACK;
286 mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA;
287 params = (u16)(initiator << 11); /* bit 11 initiator */
288 params |= (u16)(tid << 12); /* bit 15:12 TID number */
289
290 mgmt->u.action.u.delba.params = cpu_to_le16(params);
291 mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
292
Johannes Berge50db652008-09-09 15:07:09 +0200293 ieee80211_tx_skb(sdata, skb, 0);
Johannes Berg44d414d2008-09-08 17:44:28 +0200294}
295
296void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn)
297{
298 struct ieee80211_local *local = sdata->local;
299 struct sk_buff *skb;
300 struct ieee80211_bar *bar;
301 u16 bar_control = 0;
302
303 skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
304 if (!skb) {
305 printk(KERN_ERR "%s: failed to allocate buffer for "
306 "bar frame\n", sdata->dev->name);
307 return;
308 }
309 skb_reserve(skb, local->hw.extra_tx_headroom);
310 bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar));
311 memset(bar, 0, sizeof(*bar));
312 bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
313 IEEE80211_STYPE_BACK_REQ);
314 memcpy(bar->ra, ra, ETH_ALEN);
315 memcpy(bar->ta, sdata->dev->dev_addr, ETH_ALEN);
316 bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
317 bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
318 bar_control |= (u16)(tid << 12);
319 bar->control = cpu_to_le16(bar_control);
320 bar->start_seq_num = cpu_to_le16(ssn);
321
Johannes Berge50db652008-09-09 15:07:09 +0200322 ieee80211_tx_skb(sdata, skb, 0);
Johannes Berg44d414d2008-09-08 17:44:28 +0200323}
324
325void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid,
326 u16 initiator, u16 reason)
327{
328 struct ieee80211_local *local = sdata->local;
329 struct ieee80211_hw *hw = &local->hw;
330 struct sta_info *sta;
331 int ret, i;
Johannes Berg44d414d2008-09-08 17:44:28 +0200332
333 rcu_read_lock();
334
335 sta = sta_info_get(local, ra);
336 if (!sta) {
337 rcu_read_unlock();
338 return;
339 }
340
341 /* check if TID is in operational state */
342 spin_lock_bh(&sta->lock);
343 if (sta->ampdu_mlme.tid_state_rx[tid]
344 != HT_AGG_STATE_OPERATIONAL) {
345 spin_unlock_bh(&sta->lock);
346 rcu_read_unlock();
347 return;
348 }
349 sta->ampdu_mlme.tid_state_rx[tid] =
350 HT_AGG_STATE_REQ_STOP_BA_MSK |
351 (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
352 spin_unlock_bh(&sta->lock);
353
354 /* stop HW Rx aggregation. ampdu_action existence
355 * already verified in session init so we add the BUG_ON */
356 BUG_ON(!local->ops->ampdu_action);
357
358#ifdef CONFIG_MAC80211_HT_DEBUG
Johannes Berg0c68ae262008-10-27 15:56:10 -0700359 printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n",
360 ra, tid);
Johannes Berg44d414d2008-09-08 17:44:28 +0200361#endif /* CONFIG_MAC80211_HT_DEBUG */
362
363 ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
Johannes Berg17741cd2008-09-11 00:02:02 +0200364 &sta->sta, tid, NULL);
Johannes Berg44d414d2008-09-08 17:44:28 +0200365 if (ret)
366 printk(KERN_DEBUG "HW problem - can not stop rx "
367 "aggregation for tid %d\n", tid);
368
369 /* shutdown timer has not expired */
370 if (initiator != WLAN_BACK_TIMER)
371 del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
372
373 /* check if this is a self generated aggregation halt */
374 if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER)
375 ieee80211_send_delba(sdata, ra, tid, 0, reason);
376
377 /* free the reordering buffer */
378 for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) {
379 if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) {
380 /* release the reordered frames */
381 dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]);
382 sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--;
383 sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL;
384 }
385 }
386 /* free resources */
387 kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf);
388 kfree(sta->ampdu_mlme.tid_rx[tid]);
389 sta->ampdu_mlme.tid_rx[tid] = NULL;
390 sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE;
391
392 rcu_read_unlock();
393}
394
395
396/*
397 * After sending add Block Ack request we activated a timer until
398 * add Block Ack response will arrive from the recipient.
399 * If this timer expires sta_addba_resp_timer_expired will be executed.
400 */
Johannes Bergde1ede72008-09-09 14:42:50 +0200401static void sta_addba_resp_timer_expired(unsigned long data)
Johannes Berg44d414d2008-09-08 17:44:28 +0200402{
403 /* not an elegant detour, but there is no choice as the timer passes
404 * only one argument, and both sta_info and TID are needed, so init
405 * flow in sta_info_create gives the TID as data, while the timer_to_id
406 * array gives the sta through container_of */
407 u16 tid = *(u8 *)data;
408 struct sta_info *temp_sta = container_of((void *)data,
409 struct sta_info, timer_to_tid[tid]);
410
411 struct ieee80211_local *local = temp_sta->local;
412 struct ieee80211_hw *hw = &local->hw;
413 struct sta_info *sta;
414 u8 *state;
415
416 rcu_read_lock();
417
Johannes Berg17741cd2008-09-11 00:02:02 +0200418 sta = sta_info_get(local, temp_sta->sta.addr);
Johannes Berg44d414d2008-09-08 17:44:28 +0200419 if (!sta) {
420 rcu_read_unlock();
421 return;
422 }
423
424 state = &sta->ampdu_mlme.tid_state_tx[tid];
425 /* check if the TID waits for addBA response */
426 spin_lock_bh(&sta->lock);
427 if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
428 spin_unlock_bh(&sta->lock);
429 *state = HT_AGG_STATE_IDLE;
430#ifdef CONFIG_MAC80211_HT_DEBUG
431 printk(KERN_DEBUG "timer expired on tid %d but we are not "
432 "expecting addBA response there", tid);
433#endif
434 goto timer_expired_exit;
435 }
436
437#ifdef CONFIG_MAC80211_HT_DEBUG
438 printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
439#endif
440
441 /* go through the state check in stop_BA_session */
442 *state = HT_AGG_STATE_OPERATIONAL;
443 spin_unlock_bh(&sta->lock);
Johannes Berg17741cd2008-09-11 00:02:02 +0200444 ieee80211_stop_tx_ba_session(hw, temp_sta->sta.addr, tid,
Johannes Berg44d414d2008-09-08 17:44:28 +0200445 WLAN_BACK_INITIATOR);
446
447timer_expired_exit:
448 rcu_read_unlock();
449}
450
451void ieee80211_sta_tear_down_BA_sessions(struct ieee80211_sub_if_data *sdata, u8 *addr)
452{
453 struct ieee80211_local *local = sdata->local;
454 int i;
455
456 for (i = 0; i < STA_TID_NUM; i++) {
457 ieee80211_stop_tx_ba_session(&local->hw, addr, i,
458 WLAN_BACK_INITIATOR);
459 ieee80211_sta_stop_rx_ba_session(sdata, addr, i,
460 WLAN_BACK_RECIPIENT,
461 WLAN_REASON_QSTA_LEAVE_QBSS);
462 }
463}
464
Johannes Bergbacac542008-09-08 17:44:29 +0200465int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
466{
467 struct ieee80211_local *local = hw_to_local(hw);
468 struct sta_info *sta;
469 struct ieee80211_sub_if_data *sdata;
470 u16 start_seq_num;
471 u8 *state;
John W. Linville85b9e4f2009-01-12 14:37:44 -0500472 int ret = 0;
Johannes Bergbacac542008-09-08 17:44:29 +0200473
Sujith8b30b1f2008-10-24 09:55:27 +0530474 if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
Johannes Bergbacac542008-09-08 17:44:29 +0200475 return -EINVAL;
476
477#ifdef CONFIG_MAC80211_HT_DEBUG
Johannes Berg0c68ae262008-10-27 15:56:10 -0700478 printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
479 ra, tid);
Johannes Bergbacac542008-09-08 17:44:29 +0200480#endif /* CONFIG_MAC80211_HT_DEBUG */
481
482 rcu_read_lock();
483
484 sta = sta_info_get(local, ra);
485 if (!sta) {
486#ifdef CONFIG_MAC80211_HT_DEBUG
487 printk(KERN_DEBUG "Could not find the station\n");
488#endif
489 ret = -ENOENT;
490 goto exit;
491 }
492
493 spin_lock_bh(&sta->lock);
494
495 /* we have tried too many times, receiver does not want A-MPDU */
496 if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
497 ret = -EBUSY;
498 goto err_unlock_sta;
499 }
500
501 state = &sta->ampdu_mlme.tid_state_tx[tid];
502 /* check if the TID is not in aggregation flow already */
503 if (*state != HT_AGG_STATE_IDLE) {
504#ifdef CONFIG_MAC80211_HT_DEBUG
505 printk(KERN_DEBUG "BA request denied - session is not "
506 "idle on tid %u\n", tid);
507#endif /* CONFIG_MAC80211_HT_DEBUG */
508 ret = -EAGAIN;
509 goto err_unlock_sta;
510 }
511
512 /* prepare A-MPDU MLME for Tx aggregation */
513 sta->ampdu_mlme.tid_tx[tid] =
514 kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
515 if (!sta->ampdu_mlme.tid_tx[tid]) {
516#ifdef CONFIG_MAC80211_HT_DEBUG
517 if (net_ratelimit())
518 printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
519 tid);
520#endif
521 ret = -ENOMEM;
522 goto err_unlock_sta;
523 }
524 /* Tx timer */
525 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
526 sta_addba_resp_timer_expired;
527 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data =
528 (unsigned long)&sta->timer_to_tid[tid];
529 init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
530
Sujith8b30b1f2008-10-24 09:55:27 +0530531 if (hw->ampdu_queues) {
532 /* create a new queue for this aggregation */
533 ret = ieee80211_ht_agg_queue_add(local, sta, tid);
Johannes Bergbacac542008-09-08 17:44:29 +0200534
Sujith8b30b1f2008-10-24 09:55:27 +0530535 /* case no queue is available to aggregation
536 * don't switch to aggregation */
537 if (ret) {
Johannes Bergbacac542008-09-08 17:44:29 +0200538#ifdef CONFIG_MAC80211_HT_DEBUG
Sujith8b30b1f2008-10-24 09:55:27 +0530539 printk(KERN_DEBUG "BA request denied - "
540 "queue unavailable for tid %d\n", tid);
Johannes Bergbacac542008-09-08 17:44:29 +0200541#endif /* CONFIG_MAC80211_HT_DEBUG */
Sujith8b30b1f2008-10-24 09:55:27 +0530542 goto err_unlock_queue;
543 }
Johannes Bergbacac542008-09-08 17:44:29 +0200544 }
545 sdata = sta->sdata;
546
547 /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
548 * call back right away, it must see that the flow has begun */
549 *state |= HT_ADDBA_REQUESTED_MSK;
550
551 /* This is slightly racy because the queue isn't stopped */
552 start_seq_num = sta->tid_seq[tid];
553
554 if (local->ops->ampdu_action)
555 ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
Johannes Berg17741cd2008-09-11 00:02:02 +0200556 &sta->sta, tid, &start_seq_num);
Johannes Bergbacac542008-09-08 17:44:29 +0200557
558 if (ret) {
559 /* No need to requeue the packets in the agg queue, since we
560 * held the tx lock: no packet could be enqueued to the newly
561 * allocated queue */
Sujith8b30b1f2008-10-24 09:55:27 +0530562 if (hw->ampdu_queues)
563 ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
Johannes Bergbacac542008-09-08 17:44:29 +0200564#ifdef CONFIG_MAC80211_HT_DEBUG
565 printk(KERN_DEBUG "BA request denied - HW unavailable for"
566 " tid %d\n", tid);
567#endif /* CONFIG_MAC80211_HT_DEBUG */
568 *state = HT_AGG_STATE_IDLE;
569 goto err_unlock_queue;
570 }
571
572 /* Will put all the packets in the new SW queue */
Sujith8b30b1f2008-10-24 09:55:27 +0530573 if (hw->ampdu_queues)
574 ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
Johannes Bergbacac542008-09-08 17:44:29 +0200575 spin_unlock_bh(&sta->lock);
576
577 /* send an addBA request */
578 sta->ampdu_mlme.dialog_token_allocator++;
579 sta->ampdu_mlme.tid_tx[tid]->dialog_token =
580 sta->ampdu_mlme.dialog_token_allocator;
581 sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
582
583
584 ieee80211_send_addba_request(sta->sdata, ra, tid,
585 sta->ampdu_mlme.tid_tx[tid]->dialog_token,
586 sta->ampdu_mlme.tid_tx[tid]->ssn,
587 0x40, 5000);
588 /* activate the timer for the recipient's addBA response */
589 sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
590 jiffies + ADDBA_RESP_INTERVAL;
591 add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
592#ifdef CONFIG_MAC80211_HT_DEBUG
593 printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
594#endif
595 goto exit;
596
597err_unlock_queue:
598 kfree(sta->ampdu_mlme.tid_tx[tid]);
599 sta->ampdu_mlme.tid_tx[tid] = NULL;
600 ret = -EBUSY;
601err_unlock_sta:
602 spin_unlock_bh(&sta->lock);
603exit:
604 rcu_read_unlock();
605 return ret;
606}
607EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
608
609int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
610 u8 *ra, u16 tid,
611 enum ieee80211_back_parties initiator)
612{
613 struct ieee80211_local *local = hw_to_local(hw);
614 struct sta_info *sta;
615 u8 *state;
616 int ret = 0;
Johannes Bergbacac542008-09-08 17:44:29 +0200617
618 if (tid >= STA_TID_NUM)
619 return -EINVAL;
620
621 rcu_read_lock();
622 sta = sta_info_get(local, ra);
623 if (!sta) {
624 rcu_read_unlock();
625 return -ENOENT;
626 }
627
628 /* check if the TID is in aggregation */
629 state = &sta->ampdu_mlme.tid_state_tx[tid];
630 spin_lock_bh(&sta->lock);
631
632 if (*state != HT_AGG_STATE_OPERATIONAL) {
633 ret = -ENOENT;
634 goto stop_BA_exit;
635 }
636
637#ifdef CONFIG_MAC80211_HT_DEBUG
Johannes Berg0c68ae262008-10-27 15:56:10 -0700638 printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
639 ra, tid);
Johannes Bergbacac542008-09-08 17:44:29 +0200640#endif /* CONFIG_MAC80211_HT_DEBUG */
641
Sujith8b30b1f2008-10-24 09:55:27 +0530642 if (hw->ampdu_queues)
643 ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]);
Johannes Bergbacac542008-09-08 17:44:29 +0200644
645 *state = HT_AGG_STATE_REQ_STOP_BA_MSK |
646 (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
647
648 if (local->ops->ampdu_action)
649 ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP,
Johannes Berg17741cd2008-09-11 00:02:02 +0200650 &sta->sta, tid, NULL);
Johannes Bergbacac542008-09-08 17:44:29 +0200651
652 /* case HW denied going back to legacy */
653 if (ret) {
654 WARN_ON(ret != -EBUSY);
655 *state = HT_AGG_STATE_OPERATIONAL;
Sujith8b30b1f2008-10-24 09:55:27 +0530656 if (hw->ampdu_queues)
657 ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
Johannes Bergbacac542008-09-08 17:44:29 +0200658 goto stop_BA_exit;
659 }
660
661stop_BA_exit:
662 spin_unlock_bh(&sta->lock);
663 rcu_read_unlock();
664 return ret;
665}
666EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
667
668void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
669{
670 struct ieee80211_local *local = hw_to_local(hw);
671 struct sta_info *sta;
672 u8 *state;
Johannes Bergbacac542008-09-08 17:44:29 +0200673
674 if (tid >= STA_TID_NUM) {
675#ifdef CONFIG_MAC80211_HT_DEBUG
676 printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
677 tid, STA_TID_NUM);
678#endif
679 return;
680 }
681
682 rcu_read_lock();
683 sta = sta_info_get(local, ra);
684 if (!sta) {
685 rcu_read_unlock();
686#ifdef CONFIG_MAC80211_HT_DEBUG
Johannes Berg0c68ae262008-10-27 15:56:10 -0700687 printk(KERN_DEBUG "Could not find station: %pM\n", ra);
Johannes Bergbacac542008-09-08 17:44:29 +0200688#endif
689 return;
690 }
691
692 state = &sta->ampdu_mlme.tid_state_tx[tid];
693 spin_lock_bh(&sta->lock);
694
695 if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
696#ifdef CONFIG_MAC80211_HT_DEBUG
697 printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
698 *state);
699#endif
700 spin_unlock_bh(&sta->lock);
701 rcu_read_unlock();
702 return;
703 }
704
705 WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK);
706
707 *state |= HT_ADDBA_DRV_READY_MSK;
708
709 if (*state == HT_AGG_STATE_OPERATIONAL) {
710#ifdef CONFIG_MAC80211_HT_DEBUG
711 printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
712#endif
Sujith8b30b1f2008-10-24 09:55:27 +0530713 if (hw->ampdu_queues)
714 ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
Johannes Bergbacac542008-09-08 17:44:29 +0200715 }
716 spin_unlock_bh(&sta->lock);
717 rcu_read_unlock();
718}
719EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
720
721void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
722{
723 struct ieee80211_local *local = hw_to_local(hw);
724 struct sta_info *sta;
725 u8 *state;
726 int agg_queue;
Johannes Bergbacac542008-09-08 17:44:29 +0200727
728 if (tid >= STA_TID_NUM) {
729#ifdef CONFIG_MAC80211_HT_DEBUG
730 printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
731 tid, STA_TID_NUM);
732#endif
733 return;
734 }
735
736#ifdef CONFIG_MAC80211_HT_DEBUG
Johannes Berg0c68ae262008-10-27 15:56:10 -0700737 printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n",
738 ra, tid);
Johannes Bergbacac542008-09-08 17:44:29 +0200739#endif /* CONFIG_MAC80211_HT_DEBUG */
740
741 rcu_read_lock();
742 sta = sta_info_get(local, ra);
743 if (!sta) {
744#ifdef CONFIG_MAC80211_HT_DEBUG
Johannes Berg0c68ae262008-10-27 15:56:10 -0700745 printk(KERN_DEBUG "Could not find station: %pM\n", ra);
Johannes Bergbacac542008-09-08 17:44:29 +0200746#endif
747 rcu_read_unlock();
748 return;
749 }
750 state = &sta->ampdu_mlme.tid_state_tx[tid];
751
752 /* NOTE: no need to use sta->lock in this state check, as
753 * ieee80211_stop_tx_ba_session will let only one stop call to
754 * pass through per sta/tid
755 */
756 if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
757#ifdef CONFIG_MAC80211_HT_DEBUG
758 printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
759#endif
760 rcu_read_unlock();
761 return;
762 }
763
764 if (*state & HT_AGG_STATE_INITIATOR_MSK)
765 ieee80211_send_delba(sta->sdata, ra, tid,
766 WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
767
Sujith8b30b1f2008-10-24 09:55:27 +0530768 if (hw->ampdu_queues) {
769 agg_queue = sta->tid_to_tx_q[tid];
770 ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
Johannes Bergbacac542008-09-08 17:44:29 +0200771
Sujith8b30b1f2008-10-24 09:55:27 +0530772 /* We just requeued the all the frames that were in the
773 * removed queue, and since we might miss a softirq we do
774 * netif_schedule_queue. ieee80211_wake_queue is not used
775 * here as this queue is not necessarily stopped
776 */
777 netif_schedule_queue(netdev_get_tx_queue(local->mdev,
778 agg_queue));
779 }
Johannes Bergbacac542008-09-08 17:44:29 +0200780 spin_lock_bh(&sta->lock);
781 *state = HT_AGG_STATE_IDLE;
782 sta->ampdu_mlme.addba_req_num[tid] = 0;
783 kfree(sta->ampdu_mlme.tid_tx[tid]);
784 sta->ampdu_mlme.tid_tx[tid] = NULL;
785 spin_unlock_bh(&sta->lock);
786
787 rcu_read_unlock();
788}
789EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
790
791void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
792 const u8 *ra, u16 tid)
793{
794 struct ieee80211_local *local = hw_to_local(hw);
795 struct ieee80211_ra_tid *ra_tid;
796 struct sk_buff *skb = dev_alloc_skb(0);
797
798 if (unlikely(!skb)) {
799#ifdef CONFIG_MAC80211_HT_DEBUG
800 if (net_ratelimit())
801 printk(KERN_WARNING "%s: Not enough memory, "
802 "dropping start BA session", skb->dev->name);
803#endif
804 return;
805 }
806 ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
807 memcpy(&ra_tid->ra, ra, ETH_ALEN);
808 ra_tid->tid = tid;
809
810 skb->pkt_type = IEEE80211_ADDBA_MSG;
811 skb_queue_tail(&local->skb_queue, skb);
812 tasklet_schedule(&local->tasklet);
813}
814EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
815
816void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
817 const u8 *ra, u16 tid)
818{
819 struct ieee80211_local *local = hw_to_local(hw);
820 struct ieee80211_ra_tid *ra_tid;
821 struct sk_buff *skb = dev_alloc_skb(0);
822
823 if (unlikely(!skb)) {
824#ifdef CONFIG_MAC80211_HT_DEBUG
825 if (net_ratelimit())
826 printk(KERN_WARNING "%s: Not enough memory, "
827 "dropping stop BA session", skb->dev->name);
828#endif
829 return;
830 }
831 ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
832 memcpy(&ra_tid->ra, ra, ETH_ALEN);
833 ra_tid->tid = tid;
834
835 skb->pkt_type = IEEE80211_DELBA_MSG;
836 skb_queue_tail(&local->skb_queue, skb);
837 tasklet_schedule(&local->tasklet);
838}
839EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
Johannes Bergde1ede72008-09-09 14:42:50 +0200840
841/*
842 * After accepting the AddBA Request we activated a timer,
843 * resetting it after each frame that arrives from the originator.
844 * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
845 */
846static void sta_rx_agg_session_timer_expired(unsigned long data)
847{
848 /* not an elegant detour, but there is no choice as the timer passes
849 * only one argument, and various sta_info are needed here, so init
850 * flow in sta_info_create gives the TID as data, while the timer_to_id
851 * array gives the sta through container_of */
852 u8 *ptid = (u8 *)data;
853 u8 *timer_to_id = ptid - *ptid;
854 struct sta_info *sta = container_of(timer_to_id, struct sta_info,
855 timer_to_tid[0]);
856
857#ifdef CONFIG_MAC80211_HT_DEBUG
858 printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
859#endif
Johannes Berg17741cd2008-09-11 00:02:02 +0200860 ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
Johannes Bergde1ede72008-09-09 14:42:50 +0200861 (u16)*ptid, WLAN_BACK_TIMER,
862 WLAN_REASON_QSTA_TIMEOUT);
863}
864
865void ieee80211_process_addba_request(struct ieee80211_local *local,
866 struct sta_info *sta,
867 struct ieee80211_mgmt *mgmt,
868 size_t len)
869{
870 struct ieee80211_hw *hw = &local->hw;
871 struct ieee80211_conf *conf = &hw->conf;
872 struct tid_ampdu_rx *tid_agg_rx;
873 u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status;
874 u8 dialog_token;
875 int ret = -EOPNOTSUPP;
Johannes Bergde1ede72008-09-09 14:42:50 +0200876
877 /* extract session parameters from addba request frame */
878 dialog_token = mgmt->u.action.u.addba_req.dialog_token;
879 timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
880 start_seq_num =
881 le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
882
883 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
884 ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
885 tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
886 buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
887
888 status = WLAN_STATUS_REQUEST_DECLINED;
889
890 /* sanity check for incoming parameters:
891 * check if configuration can support the BA policy
892 * and if buffer size does not exceeds max value */
Johannes Bergae5eb022008-10-14 16:58:37 +0200893 /* XXX: check own ht delayed BA capability?? */
Johannes Bergde1ede72008-09-09 14:42:50 +0200894 if (((ba_policy != 1)
Johannes Bergae5eb022008-10-14 16:58:37 +0200895 && (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA)))
Johannes Bergde1ede72008-09-09 14:42:50 +0200896 || (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
897 status = WLAN_STATUS_INVALID_QOS_PARAM;
898#ifdef CONFIG_MAC80211_HT_DEBUG
899 if (net_ratelimit())
900 printk(KERN_DEBUG "AddBA Req with bad params from "
Johannes Berg0c68ae262008-10-27 15:56:10 -0700901 "%pM on tid %u. policy %d, buffer size %d\n",
902 mgmt->sa, tid, ba_policy,
Johannes Bergde1ede72008-09-09 14:42:50 +0200903 buf_size);
904#endif /* CONFIG_MAC80211_HT_DEBUG */
905 goto end_no_lock;
906 }
907 /* determine default buffer size */
908 if (buf_size == 0) {
909 struct ieee80211_supported_band *sband;
910
911 sband = local->hw.wiphy->bands[conf->channel->band];
912 buf_size = IEEE80211_MIN_AMPDU_BUF;
Johannes Bergd9fe60d2008-10-09 12:13:49 +0200913 buf_size = buf_size << sband->ht_cap.ampdu_factor;
Johannes Bergde1ede72008-09-09 14:42:50 +0200914 }
915
916
917 /* examine state machine */
918 spin_lock_bh(&sta->lock);
919
920 if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) {
921#ifdef CONFIG_MAC80211_HT_DEBUG
922 if (net_ratelimit())
923 printk(KERN_DEBUG "unexpected AddBA Req from "
Johannes Berg0c68ae262008-10-27 15:56:10 -0700924 "%pM on tid %u\n",
925 mgmt->sa, tid);
Johannes Bergde1ede72008-09-09 14:42:50 +0200926#endif /* CONFIG_MAC80211_HT_DEBUG */
927 goto end;
928 }
929
930 /* prepare A-MPDU MLME for Rx aggregation */
931 sta->ampdu_mlme.tid_rx[tid] =
932 kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
933 if (!sta->ampdu_mlme.tid_rx[tid]) {
934#ifdef CONFIG_MAC80211_HT_DEBUG
935 if (net_ratelimit())
936 printk(KERN_ERR "allocate rx mlme to tid %d failed\n",
937 tid);
938#endif
939 goto end;
940 }
941 /* rx timer */
942 sta->ampdu_mlme.tid_rx[tid]->session_timer.function =
943 sta_rx_agg_session_timer_expired;
944 sta->ampdu_mlme.tid_rx[tid]->session_timer.data =
945 (unsigned long)&sta->timer_to_tid[tid];
946 init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
947
948 tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
949
950 /* prepare reordering buffer */
951 tid_agg_rx->reorder_buf =
952 kmalloc(buf_size * sizeof(struct sk_buff *), GFP_ATOMIC);
953 if (!tid_agg_rx->reorder_buf) {
954#ifdef CONFIG_MAC80211_HT_DEBUG
955 if (net_ratelimit())
956 printk(KERN_ERR "can not allocate reordering buffer "
957 "to tid %d\n", tid);
958#endif
959 kfree(sta->ampdu_mlme.tid_rx[tid]);
960 goto end;
961 }
962 memset(tid_agg_rx->reorder_buf, 0,
963 buf_size * sizeof(struct sk_buff *));
964
965 if (local->ops->ampdu_action)
966 ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START,
Johannes Berg17741cd2008-09-11 00:02:02 +0200967 &sta->sta, tid, &start_seq_num);
Johannes Bergde1ede72008-09-09 14:42:50 +0200968#ifdef CONFIG_MAC80211_HT_DEBUG
969 printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
970#endif /* CONFIG_MAC80211_HT_DEBUG */
971
972 if (ret) {
973 kfree(tid_agg_rx->reorder_buf);
974 kfree(tid_agg_rx);
975 sta->ampdu_mlme.tid_rx[tid] = NULL;
976 goto end;
977 }
978
979 /* change state and send addba resp */
980 sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL;
981 tid_agg_rx->dialog_token = dialog_token;
982 tid_agg_rx->ssn = start_seq_num;
983 tid_agg_rx->head_seq_num = start_seq_num;
984 tid_agg_rx->buf_size = buf_size;
985 tid_agg_rx->timeout = timeout;
986 tid_agg_rx->stored_mpdu_num = 0;
987 status = WLAN_STATUS_SUCCESS;
988end:
989 spin_unlock_bh(&sta->lock);
990
991end_no_lock:
Johannes Berg17741cd2008-09-11 00:02:02 +0200992 ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
Johannes Bergde1ede72008-09-09 14:42:50 +0200993 dialog_token, status, 1, buf_size, timeout);
994}
995
996void ieee80211_process_addba_resp(struct ieee80211_local *local,
997 struct sta_info *sta,
998 struct ieee80211_mgmt *mgmt,
999 size_t len)
1000{
1001 struct ieee80211_hw *hw = &local->hw;
1002 u16 capab;
Sujith8469cde2008-10-29 10:19:28 +05301003 u16 tid, start_seq_num;
Johannes Bergde1ede72008-09-09 14:42:50 +02001004 u8 *state;
1005
1006 capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
1007 tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
1008
1009 state = &sta->ampdu_mlme.tid_state_tx[tid];
1010
1011 spin_lock_bh(&sta->lock);
1012
1013 if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
1014 spin_unlock_bh(&sta->lock);
1015 return;
1016 }
1017
1018 if (mgmt->u.action.u.addba_resp.dialog_token !=
1019 sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
1020 spin_unlock_bh(&sta->lock);
1021#ifdef CONFIG_MAC80211_HT_DEBUG
1022 printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
1023#endif /* CONFIG_MAC80211_HT_DEBUG */
1024 return;
1025 }
1026
1027 del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
1028#ifdef CONFIG_MAC80211_HT_DEBUG
1029 printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
1030#endif /* CONFIG_MAC80211_HT_DEBUG */
1031 if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
1032 == WLAN_STATUS_SUCCESS) {
1033 *state |= HT_ADDBA_RECEIVED_MSK;
1034 sta->ampdu_mlme.addba_req_num[tid] = 0;
1035
Sujith8b30b1f2008-10-24 09:55:27 +05301036 if (*state == HT_AGG_STATE_OPERATIONAL &&
1037 local->hw.ampdu_queues)
Johannes Bergde1ede72008-09-09 14:42:50 +02001038 ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
1039
Sujith8469cde2008-10-29 10:19:28 +05301040 if (local->ops->ampdu_action) {
1041 (void)local->ops->ampdu_action(hw,
1042 IEEE80211_AMPDU_TX_RESUME,
1043 &sta->sta, tid, &start_seq_num);
1044 }
1045#ifdef CONFIG_MAC80211_HT_DEBUG
1046 printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid);
1047#endif /* CONFIG_MAC80211_HT_DEBUG */
Johannes Bergde1ede72008-09-09 14:42:50 +02001048 spin_unlock_bh(&sta->lock);
1049 } else {
1050 sta->ampdu_mlme.addba_req_num[tid]++;
1051 /* this will allow the state check in stop_BA_session */
1052 *state = HT_AGG_STATE_OPERATIONAL;
1053 spin_unlock_bh(&sta->lock);
Johannes Berg17741cd2008-09-11 00:02:02 +02001054 ieee80211_stop_tx_ba_session(hw, sta->sta.addr, tid,
Johannes Bergde1ede72008-09-09 14:42:50 +02001055 WLAN_BACK_INITIATOR);
1056 }
1057}
1058
1059void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
1060 struct sta_info *sta,
1061 struct ieee80211_mgmt *mgmt, size_t len)
1062{
1063 struct ieee80211_local *local = sdata->local;
1064 u16 tid, params;
1065 u16 initiator;
Johannes Bergde1ede72008-09-09 14:42:50 +02001066
1067 params = le16_to_cpu(mgmt->u.action.u.delba.params);
1068 tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
1069 initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11;
1070
1071#ifdef CONFIG_MAC80211_HT_DEBUG
1072 if (net_ratelimit())
Johannes Berg0c68ae262008-10-27 15:56:10 -07001073 printk(KERN_DEBUG "delba from %pM (%s) tid %d reason code %d\n",
1074 mgmt->sa, initiator ? "initiator" : "recipient", tid,
Johannes Bergde1ede72008-09-09 14:42:50 +02001075 mgmt->u.action.u.delba.reason_code);
1076#endif /* CONFIG_MAC80211_HT_DEBUG */
1077
1078 if (initiator == WLAN_BACK_INITIATOR)
Johannes Berg17741cd2008-09-11 00:02:02 +02001079 ieee80211_sta_stop_rx_ba_session(sdata, sta->sta.addr, tid,
Johannes Bergde1ede72008-09-09 14:42:50 +02001080 WLAN_BACK_INITIATOR, 0);
1081 else { /* WLAN_BACK_RECIPIENT */
1082 spin_lock_bh(&sta->lock);
1083 sta->ampdu_mlme.tid_state_tx[tid] =
1084 HT_AGG_STATE_OPERATIONAL;
1085 spin_unlock_bh(&sta->lock);
Johannes Berg17741cd2008-09-11 00:02:02 +02001086 ieee80211_stop_tx_ba_session(&local->hw, sta->sta.addr, tid,
Johannes Bergde1ede72008-09-09 14:42:50 +02001087 WLAN_BACK_RECIPIENT);
1088 }
1089}