summaryrefslogtreecommitdiffstats
path: root/net/mac80211/sta_info.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r--net/mac80211/sta_info.c91
1 files changed, 47 insertions, 44 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index ca9fde1..a79ce82 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -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)) {
OpenPOWER on IntegriCloud