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