Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/linux-arm-soc
[cascardo/linux.git] / net / mac80211 / sta_info.c
index 13e8c30..b83870b 100644 (file)
@@ -67,7 +67,8 @@ static int sta_info_hash_del(struct ieee80211_local *local,
 {
        struct sta_info *s;
 
-       s = local->sta_hash[STA_HASH(sta->sta.addr)];
+       s = rcu_dereference_protected(local->sta_hash[STA_HASH(sta->sta.addr)],
+                                     lockdep_is_held(&local->sta_lock));
        if (!s)
                return -ENOENT;
        if (s == sta) {
@@ -76,9 +77,11 @@ static int sta_info_hash_del(struct ieee80211_local *local,
                return 0;
        }
 
-       while (s->hnext && s->hnext != sta)
-               s = s->hnext;
-       if (s->hnext) {
+       while (rcu_access_pointer(s->hnext) &&
+              rcu_access_pointer(s->hnext) != sta)
+               s = rcu_dereference_protected(s->hnext,
+                                       lockdep_is_held(&local->sta_lock));
+       if (rcu_access_pointer(s->hnext)) {
                rcu_assign_pointer(s->hnext, sta->hnext);
                return 0;
        }
@@ -228,6 +231,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
+       struct timespec uptime;
        int i;
 
        sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp);
@@ -245,6 +249,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
        sta->sdata = sdata;
        sta->last_rx = jiffies;
 
+       do_posix_clock_monotonic_gettime(&uptime);
+       sta->last_connected = uptime.tv_sec;
        ewma_init(&sta->avg_signal, 1024, 8);
 
        if (sta_prepare_rate_control(local, sta, gfp)) {
@@ -271,7 +277,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
 #ifdef CONFIG_MAC80211_MESH
-       sta->plink_state = PLINK_LISTEN;
+       sta->plink_state = NL80211_PLINK_LISTEN;
        init_timer(&sta->plink_timer);
 #endif
 
@@ -584,7 +590,6 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
 {
        unsigned long flags;
        struct sk_buff *skb;
-       struct ieee80211_sub_if_data *sdata;
 
        if (skb_queue_empty(&sta->ps_tx_buf))
                return false;
@@ -601,7 +606,6 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
                if (!skb)
                        break;
 
-               sdata = sta->sdata;
                local->total_ps_buffered--;
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
                printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n",
@@ -609,7 +613,8 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
 #endif
                dev_kfree_skb(skb);
 
-               if (skb_queue_empty(&sta->ps_tx_buf))
+               if (skb_queue_empty(&sta->ps_tx_buf) &&
+                   !test_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF))
                        sta_info_clear_tim_bit(sta);
        }
 
@@ -650,10 +655,12 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
        if (ret)
                return ret;
 
+       mutex_lock(&local->key_mtx);
        for (i = 0; i < NUM_DEFAULT_KEYS; i++)
-               ieee80211_key_free(local, sta->gtk[i]);
+               __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i]));
        if (sta->ptk)
-               ieee80211_key_free(local, sta->ptk);
+               __ieee80211_key_free(key_mtx_dereference(local, sta->ptk));
+       mutex_unlock(&local->key_mtx);
 
        sta->dead = true;
 
@@ -698,6 +705,8 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
        cancel_work_sync(&sta->drv_unblock_wk);
 
+       cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL);
+
        rate_control_remove_sta_debugfs(sta);
        ieee80211_sta_debugfs_remove(sta);
 
@@ -766,9 +775,8 @@ static void sta_info_cleanup(unsigned long data)
        if (!timer_needed)
                return;
 
-       local->sta_cleanup.expires =
-               round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
-       add_timer(&local->sta_cleanup);
+       mod_timer(&local->sta_cleanup,
+                 round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL));
 }
 
 void sta_info_init(struct ieee80211_local *local)
@@ -781,14 +789,6 @@ void sta_info_init(struct ieee80211_local *local)
 
        setup_timer(&local->sta_cleanup, sta_info_cleanup,
                    (unsigned long)local);
-       local->sta_cleanup.expires =
-               round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
-}
-
-int sta_info_start(struct ieee80211_local *local)
-{
-       add_timer(&local->sta_cleanup);
-       return 0;
 }
 
 void sta_info_stop(struct ieee80211_local *local)
@@ -900,6 +900,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
        struct ieee80211_local *local = sdata->local;
        int sent, buffered;
 
+       clear_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
        if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
                drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta);
 
@@ -992,3 +993,12 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
                ieee80211_queue_work(hw, &sta->drv_unblock_wk);
 }
 EXPORT_SYMBOL(ieee80211_sta_block_awake);
+
+void ieee80211_sta_set_tim(struct ieee80211_sta *pubsta)
+{
+       struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+
+       set_sta_flags(sta, WLAN_STA_PS_DRIVER_BUF);
+       sta_info_set_tim_bit(sta);
+}
+EXPORT_SYMBOL(ieee80211_sta_set_tim);