agg-tx.c
Go to the documentation of this file.
00001 /*
00002  * HT handling
00003  *
00004  * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
00005  * Copyright 2002-2005, Instant802 Networks, Inc.
00006  * Copyright 2005-2006, Devicescape Software, Inc.
00007  * Copyright 2006-2007  Jiri Benc <jbenc@suse.cz>
00008  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
00009  * Copyright 2007-2010, Intel Corporation
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License version 2 as
00013  * published by the Free Software Foundation.
00014  */
00015 
00016 #include <linux/ieee80211.h>
00017 #include <linux/slab.h>
00018 #include <linux/export.h>
00019 #include <net/mac80211.h>
00020 #include "ieee80211_i.h"
00021 #include "driver-ops.h"
00022 #include "wme.h"
00023 
00062 static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
00063                                          const u8 *da, u16 tid,
00064                                          u8 dialog_token, u16 start_seq_num,
00065                                          u16 agg_size, u16 timeout)
00066 {
00067         struct ieee80211_local *local = sdata->local;
00068         struct sk_buff *skb;
00069         struct ieee80211_mgmt *mgmt;
00070         u16 capab;
00071 
00072         skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
00073 
00074         if (!skb)
00075                 return;
00076 
00077         skb_reserve(skb, local->hw.extra_tx_headroom);
00078         mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
00079         memset(mgmt, 0, 24);
00080         memcpy(mgmt->da, da, ETH_ALEN);
00081         memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
00082         if (sdata->vif.type == NL80211_IFTYPE_AP ||
00083             sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
00084             sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
00085                 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
00086         else if (sdata->vif.type == NL80211_IFTYPE_STATION)
00087                 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
00088         else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
00089                 memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
00090 
00091         mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
00092                                           IEEE80211_STYPE_ACTION);
00093 
00094         skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
00095 
00096         mgmt->u.action.category = WLAN_CATEGORY_BACK;
00097         mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
00098 
00099         mgmt->u.action.u.addba_req.dialog_token = dialog_token;
00100         capab = (u16)(1 << 1);          /* bit 1 aggregation policy */
00101         capab |= (u16)(tid << 2);       /* bit 5:2 TID number */
00102         capab |= (u16)(agg_size << 6);  /* bit 15:6 max size of aggergation */
00103 
00104         mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
00105 
00106         mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
00107         mgmt->u.action.u.addba_req.start_seq_num =
00108                                         cpu_to_le16(start_seq_num << 4);
00109 
00110         ieee80211_tx_skb_tid(sdata, skb, tid);
00111 }
00112 
00113 void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn)
00114 {
00115         struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
00116         struct ieee80211_local *local = sdata->local;
00117         struct sk_buff *skb;
00118         struct ieee80211_bar *bar;
00119         u16 bar_control = 0;
00120 
00121         skb = dev_alloc_skb(sizeof(*bar) + local->hw.extra_tx_headroom);
00122         if (!skb)
00123                 return;
00124 
00125         skb_reserve(skb, local->hw.extra_tx_headroom);
00126         bar = (struct ieee80211_bar *)skb_put(skb, sizeof(*bar));
00127         memset(bar, 0, sizeof(*bar));
00128         bar->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
00129                                          IEEE80211_STYPE_BACK_REQ);
00130         memcpy(bar->ra, ra, ETH_ALEN);
00131         memcpy(bar->ta, sdata->vif.addr, ETH_ALEN);
00132         bar_control |= (u16)IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL;
00133         bar_control |= (u16)IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA;
00134         bar_control |= (u16)(tid << IEEE80211_BAR_CTRL_TID_INFO_SHIFT);
00135         bar->control = cpu_to_le16(bar_control);
00136         bar->start_seq_num = cpu_to_le16(ssn);
00137 
00138         IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
00139         ieee80211_tx_skb_tid(sdata, skb, tid);
00140 }
00141 EXPORT_SYMBOL(ieee80211_send_bar);
00142 
00143 void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
00144                              struct tid_ampdu_tx *tid_tx)
00145 {
00146         lockdep_assert_held(&sta->ampdu_mlme.mtx);
00147         lockdep_assert_held(&sta->lock);
00148         rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
00149 }
00150 
00151 int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
00152                                     enum ieee80211_back_parties initiator,
00153                                     bool tx)
00154 {
00155         struct ieee80211_local *local = sta->local;
00156         struct tid_ampdu_tx *tid_tx;
00157         int ret;
00158 
00159         lockdep_assert_held(&sta->ampdu_mlme.mtx);
00160 
00161         spin_lock_bh(&sta->lock);
00162 
00163         tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
00164         if (!tid_tx) {
00165                 spin_unlock_bh(&sta->lock);
00166                 return -ENOENT;
00167         }
00168 
00169         /* if we're already stopping ignore any new requests to stop */
00170         if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
00171                 spin_unlock_bh(&sta->lock);
00172                 return -EALREADY;
00173         }
00174 
00175         if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
00176                 /* not even started yet! */
00177                 ieee80211_assign_tid_tx(sta, tid, NULL);
00178                 spin_unlock_bh(&sta->lock);
00179                 kfree_rcu(tid_tx, rcu_head);
00180                 return 0;
00181         }
00182 
00183         set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
00184 
00185         spin_unlock_bh(&sta->lock);
00186 
00187 #ifdef CONFIG_MAC80211_HT_DEBUG
00188         printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n",
00189                sta->sta.addr, tid);
00190 #endif /* CONFIG_MAC80211_HT_DEBUG */
00191 
00192         del_timer_sync(&tid_tx->addba_resp_timer);
00193         del_timer_sync(&tid_tx->session_timer);
00194 
00195         /*
00196          * After this packets are no longer handed right through
00197          * to the driver but are put onto tid_tx->pending instead,
00198          * with locking to ensure proper access.
00199          */
00200         clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
00201 
00202         /*
00203          * There might be a few packets being processed right now (on
00204          * another CPU) that have already gotten past the aggregation
00205          * check when it was still OPERATIONAL and consequently have
00206          * IEEE80211_TX_CTL_AMPDU set. In that case, this code might
00207          * call into the driver at the same time or even before the
00208          * TX paths calls into it, which could confuse the driver.
00209          *
00210          * Wait for all currently running TX paths to finish before
00211          * telling the driver. New packets will not go through since
00212          * the aggregation session is no longer OPERATIONAL.
00213          */
00214         synchronize_net();
00215 
00216         tid_tx->stop_initiator = initiator;
00217         tid_tx->tx_stop = tx;
00218 
00219         ret = drv_ampdu_action(local, sta->sdata,
00220                                IEEE80211_AMPDU_TX_STOP,
00221                                &sta->sta, tid, NULL, 0);
00222 
00223         /* HW shall not deny going back to legacy */
00224         if (WARN_ON(ret)) {
00225                 /*
00226                  * We may have pending packets get stuck in this case...
00227                  * Not bothering with a workaround for now.
00228                  */
00229         }
00230 
00231         return ret;
00232 }
00233 
00234 /*
00235  * After sending add Block Ack request we activated a timer until
00236  * add Block Ack response will arrive from the recipient.
00237  * If this timer expires sta_addba_resp_timer_expired will be executed.
00238  */
00239 static void sta_addba_resp_timer_expired(unsigned long data)
00240 {
00241         /* not an elegant detour, but there is no choice as the timer passes
00242          * only one argument, and both sta_info and TID are needed, so init
00243          * flow in sta_info_create gives the TID as data, while the timer_to_id
00244          * array gives the sta through container_of */
00245         u16 tid = *(u8 *)data;
00246         struct sta_info *sta = container_of((void *)data,
00247                 struct sta_info, timer_to_tid[tid]);
00248         struct tid_ampdu_tx *tid_tx;
00249 
00250         /* check if the TID waits for addBA response */
00251         rcu_read_lock();
00252         tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
00253         if (!tid_tx ||
00254             test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) {
00255                 rcu_read_unlock();
00256 #ifdef CONFIG_MAC80211_HT_DEBUG
00257                 printk(KERN_DEBUG "timer expired on tid %d but we are not "
00258                                 "(or no longer) expecting addBA response there\n",
00259                         tid);
00260 #endif
00261                 return;
00262         }
00263 
00264 #ifdef CONFIG_MAC80211_HT_DEBUG
00265         printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
00266 #endif
00267 
00268         ieee80211_stop_tx_ba_session(&sta->sta, tid);
00269         rcu_read_unlock();
00270 }
00271 
00272 static inline int ieee80211_ac_from_tid(int tid)
00273 {
00274         return ieee802_1d_to_ac[tid & 7];
00275 }
00276 
00277 /*
00278  * When multiple aggregation sessions on multiple stations
00279  * are being created/destroyed simultaneously, we need to
00280  * refcount the global queue stop caused by that in order
00281  * to not get into a situation where one of the aggregation
00282  * setup or teardown re-enables queues before the other is
00283  * ready to handle that.
00284  *
00285  * These two functions take care of this issue by keeping
00286  * a global "agg_queue_stop" refcount.
00287  */
00288 static void __acquires(agg_queue)
00289 ieee80211_stop_queue_agg(struct ieee80211_sub_if_data *sdata, int tid)
00290 {
00291         int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
00292 
00293         if (atomic_inc_return(&sdata->local->agg_queue_stop[queue]) == 1)
00294                 ieee80211_stop_queue_by_reason(
00295                         &sdata->local->hw, queue,
00296                         IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
00297         __acquire(agg_queue);
00298 }
00299 
00300 static void __releases(agg_queue)
00301 ieee80211_wake_queue_agg(struct ieee80211_sub_if_data *sdata, int tid)
00302 {
00303         int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
00304 
00305         if (atomic_dec_return(&sdata->local->agg_queue_stop[queue]) == 0)
00306                 ieee80211_wake_queue_by_reason(
00307                         &sdata->local->hw, queue,
00308                         IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
00309         __release(agg_queue);
00310 }
00311 
00312 /*
00313  * splice packets from the STA's pending to the local pending,
00314  * requires a call to ieee80211_agg_splice_finish later
00315  */
00316 static void __acquires(agg_queue)
00317 ieee80211_agg_splice_packets(struct ieee80211_sub_if_data *sdata,
00318                              struct tid_ampdu_tx *tid_tx, u16 tid)
00319 {
00320         struct ieee80211_local *local = sdata->local;
00321         int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
00322         unsigned long flags;
00323 
00324         ieee80211_stop_queue_agg(sdata, tid);
00325 
00326         if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates"
00327                           " from the pending queue\n", tid))
00328                 return;
00329 
00330         if (!skb_queue_empty(&tid_tx->pending)) {
00331                 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
00332                 /* copy over remaining packets */
00333                 skb_queue_splice_tail_init(&tid_tx->pending,
00334                                            &local->pending[queue]);
00335                 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
00336         }
00337 }
00338 
00339 static void __releases(agg_queue)
00340 ieee80211_agg_splice_finish(struct ieee80211_sub_if_data *sdata, u16 tid)
00341 {
00342         ieee80211_wake_queue_agg(sdata, tid);
00343 }
00344 
00345 void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
00346 {
00347         struct tid_ampdu_tx *tid_tx;
00348         struct ieee80211_local *local = sta->local;
00349         struct ieee80211_sub_if_data *sdata = sta->sdata;
00350         u16 start_seq_num;
00351         int ret;
00352 
00353         tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
00354 
00355         /*
00356          * Start queuing up packets for this aggregation session.
00357          * We're going to release them once the driver is OK with
00358          * that.
00359          */
00360         clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
00361 
00362         /*
00363          * Make sure no packets are being processed. This ensures that
00364          * we have a valid starting sequence number and that in-flight
00365          * packets have been flushed out and no packets for this TID
00366          * will go into the driver during the ampdu_action call.
00367          */
00368         synchronize_net();
00369 
00370         start_seq_num = sta->tid_seq[tid] >> 4;
00371 
00372         ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
00373                                &sta->sta, tid, &start_seq_num, 0);
00374         if (ret) {
00375 #ifdef CONFIG_MAC80211_HT_DEBUG
00376                 printk(KERN_DEBUG "BA request denied - HW unavailable for"
00377                                         " tid %d\n", tid);
00378 #endif
00379                 spin_lock_bh(&sta->lock);
00380                 ieee80211_agg_splice_packets(sdata, tid_tx, tid);
00381                 ieee80211_assign_tid_tx(sta, tid, NULL);
00382                 ieee80211_agg_splice_finish(sdata, tid);
00383                 spin_unlock_bh(&sta->lock);
00384 
00385                 kfree_rcu(tid_tx, rcu_head);
00386                 return;
00387         }
00388 
00389         /* activate the timer for the recipient's addBA response */
00390         mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL);
00391 #ifdef CONFIG_MAC80211_HT_DEBUG
00392         printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
00393 #endif
00394 
00395         spin_lock_bh(&sta->lock);
00396         sta->ampdu_mlme.last_addba_req_time[tid] = jiffies;
00397         sta->ampdu_mlme.addba_req_num[tid]++;
00398         spin_unlock_bh(&sta->lock);
00399 
00400         /* send AddBA request */
00401         ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
00402                                      tid_tx->dialog_token, start_seq_num,
00403                                      local->hw.max_tx_aggregation_subframes,
00404                                      tid_tx->timeout);
00405 }
00406 
00407 /*
00408  * After accepting the AddBA Response we activated a timer,
00409  * resetting it after each frame that we send.
00410  */
00411 static void sta_tx_agg_session_timer_expired(unsigned long data)
00412 {
00413         /* not an elegant detour, but there is no choice as the timer passes
00414          * only one argument, and various sta_info are needed here, so init
00415          * flow in sta_info_create gives the TID as data, while the timer_to_id
00416          * array gives the sta through container_of */
00417         u8 *ptid = (u8 *)data;
00418         u8 *timer_to_id = ptid - *ptid;
00419         struct sta_info *sta = container_of(timer_to_id, struct sta_info,
00420                                          timer_to_tid[0]);
00421         struct tid_ampdu_tx *tid_tx;
00422         unsigned long timeout;
00423 
00424         rcu_read_lock();
00425         tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[*ptid]);
00426         if (!tid_tx || test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
00427                 rcu_read_unlock();
00428                 return;
00429         }
00430 
00431         timeout = tid_tx->last_tx + TU_TO_JIFFIES(tid_tx->timeout);
00432         if (time_is_after_jiffies(timeout)) {
00433                 mod_timer(&tid_tx->session_timer, timeout);
00434                 rcu_read_unlock();
00435                 return;
00436         }
00437 
00438         rcu_read_unlock();
00439 
00440 #ifdef CONFIG_MAC80211_HT_DEBUG
00441         printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid);
00442 #endif
00443 
00444         ieee80211_stop_tx_ba_session(&sta->sta, *ptid);
00445 }
00446 
00447 int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
00448                                   u16 timeout)
00449 {
00450         struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
00451         struct ieee80211_sub_if_data *sdata = sta->sdata;
00452         struct ieee80211_local *local = sdata->local;
00453         struct tid_ampdu_tx *tid_tx;
00454         int ret = 0;
00455 
00456         trace_api_start_tx_ba_session(pubsta, tid);
00457 
00458         if (WARN_ON(!local->ops->ampdu_action))
00459                 return -EINVAL;
00460 
00461         if ((tid >= STA_TID_NUM) ||
00462             !(local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) ||
00463             (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW))
00464                 return -EINVAL;
00465 
00466 #ifdef CONFIG_MAC80211_HT_DEBUG
00467         printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
00468                pubsta->addr, tid);
00469 #endif /* CONFIG_MAC80211_HT_DEBUG */
00470 
00471         if (sdata->vif.type != NL80211_IFTYPE_STATION &&
00472             sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
00473             sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
00474             sdata->vif.type != NL80211_IFTYPE_AP &&
00475             sdata->vif.type != NL80211_IFTYPE_ADHOC)
00476                 return -EINVAL;
00477 
00478         if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
00479 #ifdef CONFIG_MAC80211_HT_DEBUG
00480                 printk(KERN_DEBUG "BA sessions blocked. "
00481                        "Denying BA session request\n");
00482 #endif
00483                 return -EINVAL;
00484         }
00485 
00486         /*
00487          * 802.11n-2009 11.5.1.1: If the initiating STA is an HT STA, is a
00488          * member of an IBSS, and has no other existing Block Ack agreement
00489          * with the recipient STA, then the initiating STA shall transmit a
00490          * Probe Request frame to the recipient STA and shall not transmit an
00491          * ADDBA Request frame unless it receives a Probe Response frame
00492          * from the recipient within dot11ADDBAFailureTimeout.
00493          *
00494          * The probe request mechanism for ADDBA is currently not implemented,
00495          * but we only build up Block Ack session with HT STAs. This information
00496          * is set when we receive a bss info from a probe response or a beacon.
00497          */
00498         if (sta->sdata->vif.type == NL80211_IFTYPE_ADHOC &&
00499             !sta->sta.ht_cap.ht_supported) {
00500 #ifdef CONFIG_MAC80211_HT_DEBUG
00501                 printk(KERN_DEBUG "BA request denied - IBSS STA %pM"
00502                        "does not advertise HT support\n", pubsta->addr);
00503 #endif /* CONFIG_MAC80211_HT_DEBUG */
00504                 return -EINVAL;
00505         }
00506 
00507         spin_lock_bh(&sta->lock);
00508 
00509         /* we have tried too many times, receiver does not want A-MPDU */
00510         if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
00511                 ret = -EBUSY;
00512                 goto err_unlock_sta;
00513         }
00514 
00515         /*
00516          * if we have tried more than HT_AGG_BURST_RETRIES times we
00517          * will spread our requests in time to avoid stalling connection
00518          * for too long
00519          */
00520         if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_BURST_RETRIES &&
00521             time_before(jiffies, sta->ampdu_mlme.last_addba_req_time[tid] +
00522                         HT_AGG_RETRIES_PERIOD)) {
00523 #ifdef CONFIG_MAC80211_HT_DEBUG
00524                 printk(KERN_DEBUG "BA request denied - "
00525                        "waiting a grace period after %d failed requests "
00526                        "on tid %u\n",
00527                        sta->ampdu_mlme.addba_req_num[tid], tid);
00528 #endif /* CONFIG_MAC80211_HT_DEBUG */
00529                 ret = -EBUSY;
00530                 goto err_unlock_sta;
00531         }
00532 
00533         tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
00534         /* check if the TID is not in aggregation flow already */
00535         if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) {
00536 #ifdef CONFIG_MAC80211_HT_DEBUG
00537                 printk(KERN_DEBUG "BA request denied - session is not "
00538                                  "idle on tid %u\n", tid);
00539 #endif /* CONFIG_MAC80211_HT_DEBUG */
00540                 ret = -EAGAIN;
00541                 goto err_unlock_sta;
00542         }
00543 
00544         /* prepare A-MPDU MLME for Tx aggregation */
00545         tid_tx = kzalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
00546         if (!tid_tx) {
00547                 ret = -ENOMEM;
00548                 goto err_unlock_sta;
00549         }
00550 
00551         skb_queue_head_init(&tid_tx->pending);
00552         __set_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
00553 
00554         tid_tx->timeout = timeout;
00555 
00556         /* response timer */
00557         tid_tx->addba_resp_timer.function = sta_addba_resp_timer_expired;
00558         tid_tx->addba_resp_timer.data = (unsigned long)&sta->timer_to_tid[tid];
00559         init_timer(&tid_tx->addba_resp_timer);
00560 
00561         /* tx timer */
00562         tid_tx->session_timer.function = sta_tx_agg_session_timer_expired;
00563         tid_tx->session_timer.data = (unsigned long)&sta->timer_to_tid[tid];
00564         init_timer_deferrable(&tid_tx->session_timer);
00565 
00566         /* assign a dialog token */
00567         sta->ampdu_mlme.dialog_token_allocator++;
00568         tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator;
00569 
00570         /*
00571          * Finally, assign it to the start array; the work item will
00572          * collect it and move it to the normal array.
00573          */
00574         sta->ampdu_mlme.tid_start_tx[tid] = tid_tx;
00575 
00576         ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
00577 
00578         /* this flow continues off the work */
00579  err_unlock_sta:
00580         spin_unlock_bh(&sta->lock);
00581         return ret;
00582 }
00583 EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
00584 
00585 static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
00586                                          struct sta_info *sta, u16 tid)
00587 {
00588         struct tid_ampdu_tx *tid_tx;
00589 
00590         lockdep_assert_held(&sta->ampdu_mlme.mtx);
00591 
00592         tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
00593 
00594 #ifdef CONFIG_MAC80211_HT_DEBUG
00595         printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid);
00596 #endif
00597 
00598         drv_ampdu_action(local, sta->sdata,
00599                          IEEE80211_AMPDU_TX_OPERATIONAL,
00600                          &sta->sta, tid, NULL, tid_tx->buf_size);
00601 
00602         /*
00603          * synchronize with TX path, while splicing the TX path
00604          * should block so it won't put more packets onto pending.
00605          */
00606         spin_lock_bh(&sta->lock);
00607 
00608         ieee80211_agg_splice_packets(sta->sdata, tid_tx, tid);
00609         /*
00610          * Now mark as operational. This will be visible
00611          * in the TX path, and lets it go lock-free in
00612          * the common case.
00613          */
00614         set_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
00615         ieee80211_agg_splice_finish(sta->sdata, tid);
00616 
00617         spin_unlock_bh(&sta->lock);
00618 }
00619 
00620 void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
00621 {
00622         struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
00623         struct ieee80211_local *local = sdata->local;
00624         struct sta_info *sta;
00625         struct tid_ampdu_tx *tid_tx;
00626 
00627         trace_api_start_tx_ba_cb(sdata, ra, tid);
00628 
00629         if (tid >= STA_TID_NUM) {
00630 #ifdef CONFIG_MAC80211_HT_DEBUG
00631                 printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
00632                                 tid, STA_TID_NUM);
00633 #endif
00634                 return;
00635         }
00636 
00637         mutex_lock(&local->sta_mtx);
00638         sta = sta_info_get_bss(sdata, ra);
00639         if (!sta) {
00640                 mutex_unlock(&local->sta_mtx);
00641 #ifdef CONFIG_MAC80211_HT_DEBUG
00642                 printk(KERN_DEBUG "Could not find station: %pM\n", ra);
00643 #endif
00644                 return;
00645         }
00646 
00647         mutex_lock(&sta->ampdu_mlme.mtx);
00648         tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
00649 
00650         if (WARN_ON(!tid_tx)) {
00651 #ifdef CONFIG_MAC80211_HT_DEBUG
00652                 printk(KERN_DEBUG "addBA was not requested!\n");
00653 #endif
00654                 goto unlock;
00655         }
00656 
00657         if (WARN_ON(test_and_set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state)))
00658                 goto unlock;
00659 
00660         if (test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state))
00661                 ieee80211_agg_tx_operational(local, sta, tid);
00662 
00663  unlock:
00664         mutex_unlock(&sta->ampdu_mlme.mtx);
00665         mutex_unlock(&local->sta_mtx);
00666 }
00667 
00668 void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
00669                                       const u8 *ra, u16 tid)
00670 {
00671         struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
00672         struct ieee80211_local *local = sdata->local;
00673         struct ieee80211_ra_tid *ra_tid;
00674         struct sk_buff *skb = dev_alloc_skb(0);
00675 
00676         if (unlikely(!skb))
00677                 return;
00678 
00679         ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
00680         memcpy(&ra_tid->ra, ra, ETH_ALEN);
00681         ra_tid->tid = tid;
00682 
00683         skb->pkt_type = IEEE80211_SDATA_QUEUE_AGG_START;
00684         skb_queue_tail(&sdata->skb_queue, skb);
00685         ieee80211_queue_work(&local->hw, &sdata->work);
00686 }
00687 EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
00688 
00689 int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
00690                                    enum ieee80211_back_parties initiator,
00691                                    bool tx)
00692 {
00693         int ret;
00694 
00695         mutex_lock(&sta->ampdu_mlme.mtx);
00696 
00697         ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator, tx);
00698 
00699         mutex_unlock(&sta->ampdu_mlme.mtx);
00700 
00701         return ret;
00702 }
00703 
00704 int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
00705 {
00706         struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
00707         struct ieee80211_sub_if_data *sdata = sta->sdata;
00708         struct ieee80211_local *local = sdata->local;
00709         struct tid_ampdu_tx *tid_tx;
00710         int ret = 0;
00711 
00712         trace_api_stop_tx_ba_session(pubsta, tid);
00713 
00714         if (!local->ops->ampdu_action)
00715                 return -EINVAL;
00716 
00717         if (tid >= STA_TID_NUM)
00718                 return -EINVAL;
00719 
00720         spin_lock_bh(&sta->lock);
00721         tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
00722 
00723         if (!tid_tx) {
00724                 ret = -ENOENT;
00725                 goto unlock;
00726         }
00727 
00728         if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
00729                 /* already in progress stopping it */
00730                 ret = 0;
00731                 goto unlock;
00732         }
00733 
00734         set_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state);
00735         ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
00736 
00737  unlock:
00738         spin_unlock_bh(&sta->lock);
00739         return ret;
00740 }
00741 EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
00742 
00743 void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
00744 {
00745         struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
00746         struct ieee80211_local *local = sdata->local;
00747         struct sta_info *sta;
00748         struct tid_ampdu_tx *tid_tx;
00749 
00750         trace_api_stop_tx_ba_cb(sdata, ra, tid);
00751 
00752         if (tid >= STA_TID_NUM) {
00753 #ifdef CONFIG_MAC80211_HT_DEBUG
00754                 printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
00755                                 tid, STA_TID_NUM);
00756 #endif
00757                 return;
00758         }
00759 
00760 #ifdef CONFIG_MAC80211_HT_DEBUG
00761         printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n",
00762                ra, tid);
00763 #endif /* CONFIG_MAC80211_HT_DEBUG */
00764 
00765         mutex_lock(&local->sta_mtx);
00766 
00767         sta = sta_info_get_bss(sdata, ra);
00768         if (!sta) {
00769 #ifdef CONFIG_MAC80211_HT_DEBUG
00770                 printk(KERN_DEBUG "Could not find station: %pM\n", ra);
00771 #endif
00772                 goto unlock;
00773         }
00774 
00775         mutex_lock(&sta->ampdu_mlme.mtx);
00776         spin_lock_bh(&sta->lock);
00777         tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
00778 
00779         if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
00780 #ifdef CONFIG_MAC80211_HT_DEBUG
00781                 printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
00782 #endif
00783                 goto unlock_sta;
00784         }
00785 
00786         if (tid_tx->stop_initiator == WLAN_BACK_INITIATOR && tid_tx->tx_stop)
00787                 ieee80211_send_delba(sta->sdata, ra, tid,
00788                         WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
00789 
00790         /*
00791          * When we get here, the TX path will not be lockless any more wrt.
00792          * aggregation, since the OPERATIONAL bit has long been cleared.
00793          * Thus it will block on getting the lock, if it occurs. So if we
00794          * stop the queue now, we will not get any more packets, and any
00795          * that might be being processed will wait for us here, thereby
00796          * guaranteeing that no packets go to the tid_tx pending queue any
00797          * more.
00798          */
00799 
00800         ieee80211_agg_splice_packets(sta->sdata, tid_tx, tid);
00801 
00802         /* future packets must not find the tid_tx struct any more */
00803         ieee80211_assign_tid_tx(sta, tid, NULL);
00804 
00805         ieee80211_agg_splice_finish(sta->sdata, tid);
00806 
00807         kfree_rcu(tid_tx, rcu_head);
00808 
00809  unlock_sta:
00810         spin_unlock_bh(&sta->lock);
00811         mutex_unlock(&sta->ampdu_mlme.mtx);
00812  unlock:
00813         mutex_unlock(&local->sta_mtx);
00814 }
00815 
00816 void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
00817                                      const u8 *ra, u16 tid)
00818 {
00819         struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
00820         struct ieee80211_local *local = sdata->local;
00821         struct ieee80211_ra_tid *ra_tid;
00822         struct sk_buff *skb = dev_alloc_skb(0);
00823 
00824         if (unlikely(!skb))
00825                 return;
00826 
00827         ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
00828         memcpy(&ra_tid->ra, ra, ETH_ALEN);
00829         ra_tid->tid = tid;
00830 
00831         skb->pkt_type = IEEE80211_SDATA_QUEUE_AGG_STOP;
00832         skb_queue_tail(&sdata->skb_queue, skb);
00833         ieee80211_queue_work(&local->hw, &sdata->work);
00834 }
00835 EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
00836 
00837 
00838 void ieee80211_process_addba_resp(struct ieee80211_local *local,
00839                                   struct sta_info *sta,
00840                                   struct ieee80211_mgmt *mgmt,
00841                                   size_t len)
00842 {
00843         struct tid_ampdu_tx *tid_tx;
00844         u16 capab, tid;
00845         u8 buf_size;
00846 
00847         capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
00848         tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
00849         buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
00850 
00851         mutex_lock(&sta->ampdu_mlme.mtx);
00852 
00853         tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
00854         if (!tid_tx)
00855                 goto out;
00856 
00857         if (mgmt->u.action.u.addba_resp.dialog_token != tid_tx->dialog_token) {
00858 #ifdef CONFIG_MAC80211_HT_DEBUG
00859                 printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
00860 #endif
00861                 goto out;
00862         }
00863 
00864         del_timer_sync(&tid_tx->addba_resp_timer);
00865 
00866 #ifdef CONFIG_MAC80211_HT_DEBUG
00867         printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid);
00868 #endif
00869 
00870         /*
00871          * addba_resp_timer may have fired before we got here, and
00872          * caused WANT_STOP to be set. If the stop then was already
00873          * processed further, STOPPING might be set.
00874          */
00875         if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) ||
00876             test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
00877 #ifdef CONFIG_MAC80211_HT_DEBUG
00878                 printk(KERN_DEBUG
00879                        "got addBA resp for tid %d but we already gave up\n",
00880                        tid);
00881 #endif
00882                 goto out;
00883         }
00884 
00885         /*
00886          * IEEE 802.11-2007 7.3.1.14:
00887          * In an ADDBA Response frame, when the Status Code field
00888          * is set to 0, the Buffer Size subfield is set to a value
00889          * of at least 1.
00890          */
00891         if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
00892                         == WLAN_STATUS_SUCCESS && buf_size) {
00893                 if (test_and_set_bit(HT_AGG_STATE_RESPONSE_RECEIVED,
00894                                      &tid_tx->state)) {
00895                         /* ignore duplicate response */
00896                         goto out;
00897                 }
00898 
00899                 tid_tx->buf_size = buf_size;
00900 
00901                 if (test_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state))
00902                         ieee80211_agg_tx_operational(local, sta, tid);
00903 
00904                 sta->ampdu_mlme.addba_req_num[tid] = 0;
00905 
00906                 if (tid_tx->timeout) {
00907                         mod_timer(&tid_tx->session_timer,
00908                                   TU_TO_EXP_TIME(tid_tx->timeout));
00909                         tid_tx->last_tx = jiffies;
00910                 }
00911 
00912         } else {
00913                 ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR,
00914                                                 true);
00915         }
00916 
00917  out:
00918         mutex_unlock(&sta->ampdu_mlme.mtx);
00919 }


ros_rt_wmp
Author(s): Danilo Tardioli, dantard@unizar.es
autogenerated on Fri Jan 3 2014 12:07:54