00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00039 #include <linux/ieee80211.h>
00040 #include <linux/slab.h>
00041 #include <linux/export.h>
00042 #include <net/mac80211.h>
00043 #include "ieee80211_i.h"
00044 #include "driver-ops.h"
00045
00046 static void ieee80211_free_tid_rx(struct rcu_head *h)
00047 {
00048 struct tid_ampdu_rx *tid_rx =
00049 container_of(h, struct tid_ampdu_rx, rcu_head);
00050 int i;
00051
00052 del_timer_sync(&tid_rx->reorder_timer);
00053
00054 for (i = 0; i < tid_rx->buf_size; i++)
00055 dev_kfree_skb(tid_rx->reorder_buf[i]);
00056 kfree(tid_rx->reorder_buf);
00057 kfree(tid_rx->reorder_time);
00058 kfree(tid_rx);
00059 }
00060
00061 void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
00062 u16 initiator, u16 reason, bool tx)
00063 {
00064 struct ieee80211_local *local = sta->local;
00065 struct tid_ampdu_rx *tid_rx;
00066
00067 lockdep_assert_held(&sta->ampdu_mlme.mtx);
00068
00069 tid_rx = rcu_dereference_protected(sta->ampdu_mlme.tid_rx[tid],
00070 lockdep_is_held(&sta->ampdu_mlme.mtx));
00071
00072 if (!tid_rx)
00073 return;
00074
00075 RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL);
00076
00077 #ifdef CONFIG_MAC80211_HT_DEBUG
00078 printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n",
00079 sta->sta.addr, tid);
00080 #endif
00081
00082 if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,
00083 &sta->sta, tid, NULL, 0))
00084 printk(KERN_DEBUG "HW problem - can not stop rx "
00085 "aggregation for tid %d\n", tid);
00086
00087
00088 if (initiator == WLAN_BACK_RECIPIENT && tx)
00089 ieee80211_send_delba(sta->sdata, sta->sta.addr,
00090 tid, 0, reason);
00091
00092 del_timer_sync(&tid_rx->session_timer);
00093
00094 call_rcu(&tid_rx->rcu_head, ieee80211_free_tid_rx);
00095 }
00096
00097 void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
00098 u16 initiator, u16 reason, bool tx)
00099 {
00100 mutex_lock(&sta->ampdu_mlme.mtx);
00101 ___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason, tx);
00102 mutex_unlock(&sta->ampdu_mlme.mtx);
00103 }
00104
00105 void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap,
00106 const u8 *addr)
00107 {
00108 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
00109 struct sta_info *sta;
00110 int i;
00111
00112 rcu_read_lock();
00113 sta = sta_info_get(sdata, addr);
00114 if (!sta) {
00115 rcu_read_unlock();
00116 return;
00117 }
00118
00119 for (i = 0; i < STA_TID_NUM; i++)
00120 if (ba_rx_bitmap & BIT(i))
00121 set_bit(i, sta->ampdu_mlme.tid_rx_stop_requested);
00122
00123 ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
00124 rcu_read_unlock();
00125 }
00126 EXPORT_SYMBOL(ieee80211_stop_rx_ba_session);
00127
00128
00129
00130
00131
00132 static void sta_rx_agg_session_timer_expired(unsigned long data)
00133 {
00134
00135
00136
00137
00138 u8 *ptid = (u8 *)data;
00139 u8 *timer_to_id = ptid - *ptid;
00140 struct sta_info *sta = container_of(timer_to_id, struct sta_info,
00141 timer_to_tid[0]);
00142
00143 #ifdef CONFIG_MAC80211_HT_DEBUG
00144 printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
00145 #endif
00146 set_bit(*ptid, sta->ampdu_mlme.tid_rx_timer_expired);
00147 ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
00148 }
00149
00150 static void sta_rx_agg_reorder_timer_expired(unsigned long data)
00151 {
00152 u8 *ptid = (u8 *)data;
00153 u8 *timer_to_id = ptid - *ptid;
00154 struct sta_info *sta = container_of(timer_to_id, struct sta_info,
00155 timer_to_tid[0]);
00156
00157 rcu_read_lock();
00158 ieee80211_release_reorder_timeout(sta, *ptid);
00159 rcu_read_unlock();
00160 }
00161
00162 static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
00163 u8 dialog_token, u16 status, u16 policy,
00164 u16 buf_size, u16 timeout)
00165 {
00166 struct ieee80211_local *local = sdata->local;
00167 struct sk_buff *skb;
00168 struct ieee80211_mgmt *mgmt;
00169 u16 capab;
00170
00171 skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
00172 if (!skb)
00173 return;
00174
00175 skb_reserve(skb, local->hw.extra_tx_headroom);
00176 mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
00177 memset(mgmt, 0, 24);
00178 memcpy(mgmt->da, da, ETH_ALEN);
00179 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
00180 if (sdata->vif.type == NL80211_IFTYPE_AP ||
00181 sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
00182 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
00183 else if (sdata->vif.type == NL80211_IFTYPE_STATION)
00184 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
00185
00186 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
00187 IEEE80211_STYPE_ACTION);
00188
00189 skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp));
00190 mgmt->u.action.category = WLAN_CATEGORY_BACK;
00191 mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
00192 mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
00193
00194 capab = (u16)(policy << 1);
00195 capab |= (u16)(tid << 2);
00196 capab |= (u16)(buf_size << 6);
00197
00198 mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab);
00199 mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
00200 mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
00201
00202 ieee80211_tx_skb(sdata, skb);
00203 }
00204
00205 void ieee80211_process_addba_request(struct ieee80211_local *local,
00206 struct sta_info *sta,
00207 struct ieee80211_mgmt *mgmt,
00208 size_t len)
00209 {
00210 struct tid_ampdu_rx *tid_agg_rx;
00211 u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status;
00212 u8 dialog_token;
00213 int ret = -EOPNOTSUPP;
00214
00215
00216 dialog_token = mgmt->u.action.u.addba_req.dialog_token;
00217 timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
00218 start_seq_num =
00219 le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4;
00220
00221 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
00222 ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1;
00223 tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
00224 buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
00225
00226 status = WLAN_STATUS_REQUEST_DECLINED;
00227
00228 if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
00229 #ifdef CONFIG_MAC80211_HT_DEBUG
00230 printk(KERN_DEBUG "Suspend in progress. "
00231 "Denying ADDBA request\n");
00232 #endif
00233 goto end_no_lock;
00234 }
00235
00236
00237
00238
00239
00240 if (((ba_policy != 1) &&
00241 (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) ||
00242 (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
00243 status = WLAN_STATUS_INVALID_QOS_PARAM;
00244 #ifdef CONFIG_MAC80211_HT_DEBUG
00245 if (net_ratelimit())
00246 printk(KERN_DEBUG "AddBA Req with bad params from "
00247 "%pM on tid %u. policy %d, buffer size %d\n",
00248 mgmt->sa, tid, ba_policy,
00249 buf_size);
00250 #endif
00251 goto end_no_lock;
00252 }
00253
00254 if (buf_size == 0)
00255 buf_size = IEEE80211_MAX_AMPDU_BUF;
00256
00257
00258 if (buf_size > local->hw.max_rx_aggregation_subframes)
00259 buf_size = local->hw.max_rx_aggregation_subframes;
00260
00261
00262 mutex_lock(&sta->ampdu_mlme.mtx);
00263
00264 if (sta->ampdu_mlme.tid_rx[tid]) {
00265 #ifdef CONFIG_MAC80211_HT_DEBUG
00266 if (net_ratelimit())
00267 printk(KERN_DEBUG "unexpected AddBA Req from "
00268 "%pM on tid %u\n",
00269 mgmt->sa, tid);
00270 #endif
00271
00272
00273 ___ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
00274 WLAN_STATUS_UNSPECIFIED_QOS,
00275 false);
00276 }
00277
00278
00279 tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL);
00280 if (!tid_agg_rx)
00281 goto end;
00282
00283 spin_lock_init(&tid_agg_rx->reorder_lock);
00284
00285
00286 tid_agg_rx->session_timer.function = sta_rx_agg_session_timer_expired;
00287 tid_agg_rx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
00288 init_timer(&tid_agg_rx->session_timer);
00289
00290
00291 tid_agg_rx->reorder_timer.function = sta_rx_agg_reorder_timer_expired;
00292 tid_agg_rx->reorder_timer.data = (unsigned long)&sta->timer_to_tid[tid];
00293 init_timer(&tid_agg_rx->reorder_timer);
00294
00295
00296 tid_agg_rx->reorder_buf =
00297 kcalloc(buf_size, sizeof(struct sk_buff *), GFP_KERNEL);
00298 tid_agg_rx->reorder_time =
00299 kcalloc(buf_size, sizeof(unsigned long), GFP_KERNEL);
00300 if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) {
00301 kfree(tid_agg_rx->reorder_buf);
00302 kfree(tid_agg_rx->reorder_time);
00303 kfree(tid_agg_rx);
00304 goto end;
00305 }
00306
00307 ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START,
00308 &sta->sta, tid, &start_seq_num, 0);
00309 #ifdef CONFIG_MAC80211_HT_DEBUG
00310 printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
00311 #endif
00312
00313 if (ret) {
00314 kfree(tid_agg_rx->reorder_buf);
00315 kfree(tid_agg_rx->reorder_time);
00316 kfree(tid_agg_rx);
00317 goto end;
00318 }
00319
00320
00321 tid_agg_rx->dialog_token = dialog_token;
00322 tid_agg_rx->ssn = start_seq_num;
00323 tid_agg_rx->head_seq_num = start_seq_num;
00324 tid_agg_rx->buf_size = buf_size;
00325 tid_agg_rx->timeout = timeout;
00326 tid_agg_rx->stored_mpdu_num = 0;
00327 status = WLAN_STATUS_SUCCESS;
00328
00329
00330 rcu_assign_pointer(sta->ampdu_mlme.tid_rx[tid], tid_agg_rx);
00331
00332 if (timeout)
00333 mod_timer(&tid_agg_rx->session_timer, TU_TO_EXP_TIME(timeout));
00334
00335 end:
00336 mutex_unlock(&sta->ampdu_mlme.mtx);
00337
00338 end_no_lock:
00339 ieee80211_send_addba_resp(sta->sdata, sta->sta.addr, tid,
00340 dialog_token, status, 1, buf_size, timeout);
00341 }