- patches.arch/x86_mce_intel_decode_physical_address.patch:
[linux-flexiantxendom0-3.2.10.git] / net / mac80211 / sta_info.c
index fb12cec..ba9360a 100644 (file)
@@ -250,9 +250,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
                 * enable session_timer's data differentiation. refer to
                 * sta_rx_agg_session_timer_expired for useage */
                sta->timer_to_tid[i] = i;
-               /* rx */
-               sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE;
-               sta->ampdu_mlme.tid_rx[i] = NULL;
                /* tx */
                sta->ampdu_mlme.tid_state_tx[i] = HT_AGG_STATE_IDLE;
                sta->ampdu_mlme.tid_tx[i] = NULL;
@@ -262,7 +259,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
        skb_queue_head_init(&sta->tx_filtered);
 
        for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
-               sta->last_seq_ctrl[i] = cpu_to_le16(USHORT_MAX);
+               sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX);
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
        printk(KERN_DEBUG "%s: Allocated STA %pM\n",
@@ -578,7 +575,7 @@ static int sta_info_buffer_expired(struct sta_info *sta,
 }
 
 
-static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
+static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
                                             struct sta_info *sta)
 {
        unsigned long flags;
@@ -586,7 +583,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
        struct ieee80211_sub_if_data *sdata;
 
        if (skb_queue_empty(&sta->ps_tx_buf))
-               return;
+               return false;
 
        for (;;) {
                spin_lock_irqsave(&sta->ps_tx_buf.lock, flags);
@@ -611,6 +608,8 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
                if (skb_queue_empty(&sta->ps_tx_buf))
                        sta_info_clear_tim_bit(sta);
        }
+
+       return true;
 }
 
 static int __must_check __sta_info_destroy(struct sta_info *sta)
@@ -619,7 +618,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
        struct ieee80211_sub_if_data *sdata;
        struct sk_buff *skb;
        unsigned long flags;
-       int ret, i;
+       int ret;
 
        might_sleep();
 
@@ -629,6 +628,15 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
        local = sta->local;
        sdata = sta->sdata;
 
+       /*
+        * Before removing the station from the driver and
+        * rate control, it might still start new aggregation
+        * sessions -- block that to make sure the tear-down
+        * will be sufficient.
+        */
+       set_sta_flags(sta, WLAN_STA_BLOCK_BA);
+       ieee80211_sta_tear_down_BA_sessions(sta);
+
        spin_lock_irqsave(&local->sta_lock, flags);
        ret = sta_info_hash_del(local, sta);
        /* this might still be the pending list ... which is fine */
@@ -645,9 +653,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
                 * may mean it is removed from hardware which requires that
                 * the key->sta pointer is still valid, so flush the key todo
                 * list here.
-                *
-                * ieee80211_key_todo() will synchronize_rcu() so after this
-                * nothing can reference this sta struct any more.
                 */
                ieee80211_key_todo();
 
@@ -679,11 +684,17 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
                sdata = sta->sdata;
        }
 
+       /*
+        * At this point, after we wait for an RCU grace period,
+        * neither mac80211 nor the driver can reference this
+        * sta struct any more except by still existing timers
+        * associated with this station that we clean up below.
+        */
+       synchronize_rcu();
+
 #ifdef CONFIG_MAC80211_MESH
-       if (ieee80211_vif_is_mesh(&sdata->vif)) {
+       if (ieee80211_vif_is_mesh(&sdata->vif))
                mesh_accept_plinks_update(sdata);
-               del_timer(&sta->plink_timer);
-       }
 #endif
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -710,50 +721,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
        while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL)
                dev_kfree_skb_any(skb);
 
-       for (i = 0; i <  STA_TID_NUM; i++) {
-               struct tid_ampdu_rx *tid_rx;
-               struct tid_ampdu_tx *tid_tx;
-
-               spin_lock_bh(&sta->lock);
-               tid_rx = sta->ampdu_mlme.tid_rx[i];
-               /* Make sure timer won't free the tid_rx struct, see below */
-               if (tid_rx)
-                       tid_rx->shutdown = true;
-
-               spin_unlock_bh(&sta->lock);
-
-               /*
-                * Outside spinlock - shutdown is true now so that the timer
-                * won't free tid_rx, we have to do that now. Can't let the
-                * timer do it because we have to sync the timer outside the
-                * lock that it takes itself.
-                */
-               if (tid_rx) {
-                       del_timer_sync(&tid_rx->session_timer);
-                       kfree(tid_rx);
-               }
-
-               /*
-                * No need to do such complications for TX agg sessions, the
-                * path leading to freeing the tid_tx struct goes via a call
-                * from the driver, and thus needs to look up the sta struct
-                * again, which cannot be found when we get here. Hence, we
-                * just need to delete the timer and free the aggregation
-                * info; we won't be telling the peer about it then but that
-                * doesn't matter if we're not talking to it again anyway.
-                */
-               tid_tx = sta->ampdu_mlme.tid_tx[i];
-               if (tid_tx) {
-                       del_timer_sync(&tid_tx->addba_resp_timer);
-                       /*
-                        * STA removed while aggregation session being
-                        * started? Bit odd, but purge frames anyway.
-                        */
-                       skb_queue_purge(&tid_tx->pending);
-                       kfree(tid_tx);
-               }
-       }
-
        __sta_info_free(local, sta);
 
        return 0;
@@ -790,15 +757,20 @@ static void sta_info_cleanup(unsigned long data)
 {
        struct ieee80211_local *local = (struct ieee80211_local *) data;
        struct sta_info *sta;
+       bool timer_needed = false;
 
        rcu_read_lock();
        list_for_each_entry_rcu(sta, &local->sta_list, list)
-               sta_info_cleanup_expire_buffered(local, sta);
+               if (sta_info_cleanup_expire_buffered(local, sta))
+                       timer_needed = true;
        rcu_read_unlock();
 
        if (local->quiescing)
                return;
 
+       if (!timer_needed)
+               return;
+
        local->sta_cleanup.expires =
                round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
        add_timer(&local->sta_cleanup);
@@ -883,8 +855,12 @@ struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw,
        struct sta_info *sta, *nxt;
 
        /* Just return a random station ... first in list ... */
-       for_each_sta_info(hw_to_local(hw), addr, sta, nxt)
+       for_each_sta_info(hw_to_local(hw), addr, sta, nxt) {
+               if (!sta->uploaded)
+                       return NULL;
                return &sta->sta;
+       }
+
        return NULL;
 }
 EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw);
@@ -892,14 +868,19 @@ EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw);
 struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif,
                                         const u8 *addr)
 {
-       struct ieee80211_sub_if_data *sdata;
+       struct sta_info *sta;
 
        if (!vif)
                return NULL;
 
-       sdata = vif_to_sdata(vif);
+       sta = sta_info_get_bss(vif_to_sdata(vif), addr);
+       if (!sta)
+               return NULL;
+
+       if (!sta->uploaded)
+               return NULL;
 
-       return ieee80211_find_sta_by_hw(&sdata->local->hw, addr);
+       return &sta->sta;
 }
 EXPORT_SYMBOL(ieee80211_find_sta);
 
@@ -992,6 +973,8 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
 {
        struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
 
+       trace_api_sta_block_awake(sta->local, pubsta, block);
+
        if (block)
                set_sta_flags(sta, WLAN_STA_PS_DRIVER);
        else