1 /* 2 * HT handling 3 * 4 * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi> 5 * Copyright 2002-2005, Instant802 Networks, Inc. 6 * Copyright 2005-2006, Devicescape Software, Inc. 7 * 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 <linux/slab.h> 18 #include <net/mac80211.h> 19 #include "ieee80211_i.h" 20 #include "driver-ops.h" 21 22 static void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, 23 u16 initiator, u16 reason, 24 bool from_timer) 25 { 26 struct ieee80211_local *local = sta->local; 27 struct tid_ampdu_rx *tid_rx; 28 int i; 29 30 spin_lock_bh(&sta->lock); 31 32 /* check if TID is in operational state */ 33 if (!sta->ampdu_mlme.tid_active_rx[tid]) { 34 spin_unlock_bh(&sta->lock); 35 return; 36 } 37 38 sta->ampdu_mlme.tid_active_rx[tid] = false; 39 40 tid_rx = sta->ampdu_mlme.tid_rx[tid]; 41 42 #ifdef CONFIG_MAC80211_HT_DEBUG 43 printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n", 44 sta->sta.addr, tid); 45 #endif /* CONFIG_MAC80211_HT_DEBUG */ 46 47 if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP, 48 &sta->sta, tid, NULL)) 49 printk(KERN_DEBUG "HW problem - can not stop rx " 50 "aggregation for tid %d\n", tid); 51 52 /* check if this is a self generated aggregation halt */ 53 if (initiator == WLAN_BACK_RECIPIENT) 54 ieee80211_send_delba(sta->sdata, sta->sta.addr, 55 tid, 0, reason); 56 57 /* free the reordering buffer */ 58 for (i = 0; i < tid_rx->buf_size; i++) { 59 if (tid_rx->reorder_buf[i]) { 60 /* release the reordered frames */ 61 dev_kfree_skb(tid_rx->reorder_buf[i]); 62 tid_rx->stored_mpdu_num--; 63 tid_rx->reorder_buf[i] = NULL; 64 } 65 } 66 67 /* free resources */ 68 kfree(tid_rx->reorder_buf); 69 kfree(tid_rx->reorder_time); 70 sta->ampdu_mlme.tid_rx[tid] = NULL; 71 72 spin_unlock_bh(&sta->lock); 73 74 if (!from_timer) 75 del_timer_sync(&tid_rx->session_timer); 76 kfree(tid_rx); 77 } 78 79 void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, 80 u16 initiator, u16 reason) 81 { 82 ___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason, false); 83 } 84 85 /* 86 * After accepting the AddBA Request we activated a timer, 87 * resetting it after each frame that arrives from the originator. 88 */ 89 static void sta_rx_agg_session_timer_expired(unsigned long data) 90 { 91 /* not an elegant detour, but there is no choice as the timer passes 92 * only one argument, and various sta_info are needed here, so init 93 * flow in sta_info_create gives the TID as data, while the timer_to_id 94 * array gives the sta through container_of */ 95 u8 *ptid = (u8 *)data; 96 u8 *timer_to_id = ptid - *ptid; 97 struct sta_info *sta = container_of(timer_to_id, struct sta_info, 98 timer_to_tid[0]); 99 100 #ifdef CONFIG_MAC80211_HT_DEBUG 101 printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); 102 #endif 103 ___ieee80211_stop_rx_ba_session(sta, *ptid, WLAN_BACK_RECIPIENT, 104 WLAN_REASON_QSTA_TIMEOUT, true); 105 } 106 107 static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid, 108 u8 dialog_token, u16 status, u16 policy, 109 u16 buf_size, u16 timeout) 110 { 111 struct ieee80211_local *local = sdata->local; 112 struct sk_buff *skb; 113 struct ieee80211_mgmt *mgmt; 114 u16 capab; 115 116 skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom); 117 118 if (!skb) { 119 printk(KERN_DEBUG "%s: failed to allocate buffer " 120 "for addba resp frame\n", sdata->name); 121 return; 122 } 123 124 skb_reserve(skb, local->hw.extra_tx_headroom); 125 mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); 126 memset(mgmt, 0, 24); 127 memcpy(mgmt->da, da, ETH_ALEN); 128 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); 129 if (sdata->vif.type == NL80211_IFTYPE_AP || 130 sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 131 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); 132 else if (sdata->vif.type == NL80211_IFTYPE_STATION) 133 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); 134 135 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 136 IEEE80211_STYPE_ACTION); 137 138 skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp)); 139 mgmt->u.action.category = WLAN_CATEGORY_BACK; 140 mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP; 141 mgmt->u.action.u.addba_resp.dialog_token = dialog_token; 142 143 capab = (u16)(policy << 1); /* bit 1 aggregation policy */ 144 capab |= (u16)(tid << 2); /* bit 5:2 TID number */ 145 capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */ 146 147 mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab); 148 mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout); 149 mgmt->u.action.u.addba_resp.status = cpu_to_le16(status); 150 151 ieee80211_tx_skb(sdata, skb); 152 } 153 154 void ieee80211_process_addba_request(struct ieee80211_local *local, 155 struct sta_info *sta, 156 struct ieee80211_mgmt *mgmt, 157 size_t len) 158 { 159 struct ieee80211_hw *hw = &local->hw; 160 struct ieee80211_conf *conf = &hw->conf; 161 struct tid_ampdu_rx *tid_agg_rx; 162 u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status; 163 u8 dialog_token; 164 int ret = -EOPNOTSUPP; 165 166 /* extract session parameters from addba request frame */ 167 dialog_token = mgmt->u.action.u.addba_req.dialog_token; 168 timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout); 169 start_seq_num = 170 le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4; 171 172 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); 173 ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1; 174 tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; 175 buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; 176 177 status = WLAN_STATUS_REQUEST_DECLINED; 178 179 if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) { 180 #ifdef CONFIG_MAC80211_HT_DEBUG 181 printk(KERN_DEBUG "Suspend in progress. " 182 "Denying ADDBA request\n"); 183 #endif 184 goto end_no_lock; 185 } 186 187 /* sanity check for incoming parameters: 188 * check if configuration can support the BA policy 189 * and if buffer size does not exceeds max value */ 190 /* XXX: check own ht delayed BA capability?? */ 191 if (((ba_policy != 1) && 192 (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) || 193 (buf_size > IEEE80211_MAX_AMPDU_BUF)) { 194 status = WLAN_STATUS_INVALID_QOS_PARAM; 195 #ifdef CONFIG_MAC80211_HT_DEBUG 196 if (net_ratelimit()) 197 printk(KERN_DEBUG "AddBA Req with bad params from " 198 "%pM on tid %u. policy %d, buffer size %d\n", 199 mgmt->sa, tid, ba_policy, 200 buf_size); 201 #endif /* CONFIG_MAC80211_HT_DEBUG */ 202 goto end_no_lock; 203 } 204 /* determine default buffer size */ 205 if (buf_size == 0) { 206 struct ieee80211_supported_band *sband; 207 208 sband = local->hw.wiphy->bands[conf->channel->band]; 209 buf_size = IEEE80211_MIN_AMPDU_BUF; 210 buf_size = buf_size << sband->ht_cap.ampdu_factor; 211 } 212 213 214 /* examine state machine */ 215 spin_lock_bh(&sta->lock); 216 217 if (sta->ampdu_mlme.tid_active_rx[tid]) { 218 #ifdef CONFIG_MAC80211_HT_DEBUG 219 if (net_ratelimit()) 220 printk(KERN_DEBUG "unexpected AddBA Req from " 221 "%pM on tid %u\n", 222 mgmt->sa, tid); 223 #endif /* CONFIG_MAC80211_HT_DEBUG */ 224 goto end; 225 } 226 227 /* prepare A-MPDU MLME for Rx aggregation */ 228 sta->ampdu_mlme.tid_rx[tid] = 229 kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC); 230 if (!sta->ampdu_mlme.tid_rx[tid]) { 231 #ifdef CONFIG_MAC80211_HT_DEBUG 232 if (net_ratelimit()) 233 printk(KERN_ERR "allocate rx mlme to tid %d failed\n", 234 tid); 235 #endif 236 goto end; 237 } 238 /* rx timer */ 239 sta->ampdu_mlme.tid_rx[tid]->session_timer.function = 240 sta_rx_agg_session_timer_expired; 241 sta->ampdu_mlme.tid_rx[tid]->session_timer.data = 242 (unsigned long)&sta->timer_to_tid[tid]; 243 init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer); 244 245 tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; 246 247 /* prepare reordering buffer */ 248 tid_agg_rx->reorder_buf = 249 kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC); 250 tid_agg_rx->reorder_time = 251 kcalloc(buf_size, sizeof(unsigned long), GFP_ATOMIC); 252 if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) { 253 #ifdef CONFIG_MAC80211_HT_DEBUG 254 if (net_ratelimit()) 255 printk(KERN_ERR "can not allocate reordering buffer " 256 "to tid %d\n", tid); 257 #endif 258 kfree(tid_agg_rx->reorder_buf); 259 kfree(tid_agg_rx->reorder_time); 260 kfree(sta->ampdu_mlme.tid_rx[tid]); 261 sta->ampdu_mlme.tid_rx[tid] = NULL; 262 goto end; 263 } 264 265 ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START, 266 &sta->sta, tid, &start_seq_num); 267 #ifdef CONFIG_MAC80211_HT_DEBUG 268 printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); 269 #endif /* CONFIG_MAC80211_HT_DEBUG */ 270 271 if (ret) { 272 kfree(tid_agg_rx->reorder_buf); 273 kfree(tid_agg_rx); 274 sta->ampdu_mlme.tid_rx[tid] = NULL; 275 goto end; 276 } 277 278 /* change state and send addba resp */ 279 sta->ampdu_mlme.tid_active_rx[tid] = true; 280 tid_agg_rx->dialog_token = dialog_token; 281 tid_agg_rx->ssn = start_seq_num; 282 tid_agg_rx->head_seq_num = start_seq_num; 283 tid_agg_rx->buf_size = buf_size; 284 tid_agg_rx->timeout = timeout; 285 tid_agg_rx->stored_mpdu_num = 0; 286 status = WLAN_STATUS_SUCCESS; 287 end: 288 spin_unlock_bh(&sta->lock); 289 290 end_no_lock: 291 ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid, 292 dialog_token, status, 1, buf_size, timeout); 293 } 294