caif_dev: fix sparse warnings for caif_flow_cb
[cascardo/linux.git] / net / mac80211 / sta_info.c
index ca9fde1..a79ce82 100644 (file)
@@ -104,12 +104,24 @@ static void cleanup_single_sta(struct sta_info *sta)
         * 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.
+        *
+        * Note though that this still uses the sdata and even
+        * calls the driver in AP and mesh mode, so interfaces
+        * of those types mush use call sta_info_flush_cleanup()
+        * (typically via sta_info_flush()) before deconfiguring
+        * the driver.
+        *
+        * In station mode, nothing happens here so it doesn't
+        * have to (and doesn't) do that, this is intentional to
+        * speed up roaming.
         */
 
        if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
                if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
                    sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                        ps = &sdata->bss->ps;
+               else if (ieee80211_vif_is_mesh(&sdata->vif))
+                       ps = &sdata->u.mesh.ps;
                else
                        return;
 
@@ -125,13 +137,8 @@ static void cleanup_single_sta(struct sta_info *sta)
                ieee80211_purge_tx_queue(&local->hw, &sta->tx_filtered[ac]);
        }
 
-#ifdef CONFIG_MAC80211_MESH
-       if (ieee80211_vif_is_mesh(&sdata->vif)) {
-               mesh_accept_plinks_update(sdata);
-               mesh_plink_deactivate(sta);
-               del_timer_sync(&sta->plink_timer);
-       }
-#endif
+       if (ieee80211_vif_is_mesh(&sdata->vif))
+               mesh_sta_cleanup(sta);
 
        cancel_work_sync(&sta->drv_unblock_wk);
 
@@ -368,12 +375,9 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
        for (i = 0; i < IEEE80211_NUM_TIDS; i++)
                sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX);
 
-       sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
+       sta->sta.smps_mode = IEEE80211_SMPS_OFF;
 
-#ifdef CONFIG_MAC80211_MESH
-       sta->plink_state = NL80211_PLINK_LISTEN;
-       init_timer(&sta->plink_timer);
-#endif
+       sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
 
        return sta;
 }
@@ -569,7 +573,6 @@ void sta_info_recalc_tim(struct sta_info *sta)
 {
        struct ieee80211_local *local = sta->local;
        struct ps_data *ps;
-       unsigned long flags;
        bool indicate_tim = false;
        u8 ignore_for_tim = sta->sta.uapsd_queues;
        int ac;
@@ -582,6 +585,12 @@ void sta_info_recalc_tim(struct sta_info *sta)
 
                ps = &sta->sdata->bss->ps;
                id = sta->sta.aid;
+#ifdef CONFIG_MAC80211_MESH
+       } else if (ieee80211_vif_is_mesh(&sta->sdata->vif)) {
+               ps = &sta->sdata->u.mesh.ps;
+               /* TIM map only for PLID <= IEEE80211_MAX_AID */
+               id = le16_to_cpu(sta->plid) % IEEE80211_MAX_AID;
+#endif
        } else {
                return;
        }
@@ -620,7 +629,7 @@ void sta_info_recalc_tim(struct sta_info *sta)
        }
 
  done:
-       spin_lock_irqsave(&local->tim_lock, flags);
+       spin_lock_bh(&local->tim_lock);
 
        if (indicate_tim)
                __bss_tim_set(ps->tim, id);
@@ -633,7 +642,7 @@ void sta_info_recalc_tim(struct sta_info *sta)
                local->tim_in_locked_section = false;
        }
 
-       spin_unlock_irqrestore(&local->tim_lock, flags);
+       spin_unlock_bh(&local->tim_lock);
 }
 
 static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb)
@@ -740,8 +749,9 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
        bool have_buffered = false;
        int ac;
 
-       /* This is only necessary for stations on BSS interfaces */
-       if (!sta->sdata->bss)
+       /* This is only necessary for stations on BSS/MBSS interfaces */
+       if (!sta->sdata->bss &&
+           !ieee80211_vif_is_mesh(&sta->sdata->vif))
                return false;
 
        for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
@@ -774,7 +784,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
         * will be sufficient.
         */
        set_sta_flag(sta, WLAN_STA_BLOCK_BA);
-       ieee80211_sta_tear_down_BA_sessions(sta, false);
+       ieee80211_sta_tear_down_BA_sessions(sta, AGG_STOP_DESTROY_STA);
 
        ret = sta_info_hash_del(local, sta);
        if (ret)
@@ -885,20 +895,12 @@ void sta_info_init(struct ieee80211_local *local)
 void sta_info_stop(struct ieee80211_local *local)
 {
        del_timer_sync(&local->sta_cleanup);
-       sta_info_flush(local, NULL);
 }
 
-/**
- * sta_info_flush - flush matching STA entries from the STA table
- *
- * Returns the number of removed STA entries.
- *
- * @local: local interface data
- * @sdata: matching rule for the net device (sta->dev) or %NULL to match all STAs
- */
-int sta_info_flush(struct ieee80211_local *local,
-                  struct ieee80211_sub_if_data *sdata)
+
+int sta_info_flush_defer(struct ieee80211_sub_if_data *sdata)
 {
+       struct ieee80211_local *local = sdata->local;
        struct sta_info *sta, *tmp;
        int ret = 0;
 
@@ -906,30 +908,22 @@ int sta_info_flush(struct ieee80211_local *local,
 
        mutex_lock(&local->sta_mtx);
        list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
-               if (!sdata || sdata == sta->sdata) {
+               if (sdata == sta->sdata) {
                        WARN_ON(__sta_info_destroy(sta));
                        ret++;
                }
        }
        mutex_unlock(&local->sta_mtx);
 
-       rcu_barrier();
-
-       if (sdata) {
-               ieee80211_cleanup_sdata_stas(sdata);
-               cancel_work_sync(&sdata->cleanup_stations_wk);
-       } else {
-               mutex_lock(&local->iflist_mtx);
-               list_for_each_entry(sdata, &local->interfaces, list) {
-                       ieee80211_cleanup_sdata_stas(sdata);
-                       cancel_work_sync(&sdata->cleanup_stations_wk);
-               }
-               mutex_unlock(&local->iflist_mtx);
-       }
-
        return ret;
 }
 
+void sta_info_flush_cleanup(struct ieee80211_sub_if_data *sdata)
+{
+       ieee80211_cleanup_sdata_stas(sdata);
+       cancel_work_sync(&sdata->cleanup_stations_wk);
+}
+
 void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
                          unsigned long exp_time)
 {
@@ -945,6 +939,11 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
                if (time_after(jiffies, sta->last_rx + exp_time)) {
                        sta_dbg(sta->sdata, "expiring inactive STA %pM\n",
                                sta->sta.addr);
+
+                       if (ieee80211_vif_is_mesh(&sdata->vif) &&
+                           test_sta_flag(sta, WLAN_STA_PS_STA))
+                               atomic_dec(&sdata->u.mesh.ps.num_sta_ps);
+
                        WARN_ON(__sta_info_destroy(sta));
                }
        }
@@ -1003,6 +1002,8 @@ static void clear_sta_ps_flags(void *_sta)
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
            sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                ps = &sdata->bss->ps;
+       else if (ieee80211_vif_is_mesh(&sdata->vif))
+               ps = &sdata->u.mesh.ps;
        else
                return;
 
@@ -1120,6 +1121,8 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
 
        drv_allow_buffered_frames(local, sta, BIT(tid), 1, reason, false);
 
+       skb->dev = sdata->dev;
+
        rcu_read_lock();
        chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
        if (WARN_ON(!chanctx_conf)) {