#include <net/mac80211.h>
#include "ieee80211_i.h"
-#include "ieee80211_rate.h"
+#include "rate.h"
#include "sta_info.h"
#include "debugfs_sta.h"
#include "mesh.h"
*
* In order to remove a STA info structure, the caller needs to first
* unlink it (sta_info_unlink()) from the list and hash tables and
- * then destroy it while holding the RTNL; sta_info_destroy() will wait
- * for an RCU grace period to elapse before actually freeing it. Due to
- * the pinning and the possibility of multiple callers trying to remove
- * the same STA info at the same time, sta_info_unlink() can clear the
- * STA info pointer it is passed to indicate that the STA info is owned
- * by somebody else now.
+ * then destroy it; sta_info_destroy() will wait for an RCU grace period
+ * to elapse before actually freeing it. Due to the pinning and the
+ * possibility of multiple callers trying to remove the same STA info at
+ * the same time, sta_info_unlink() can clear the STA info pointer it is
+ * passed to indicate that the STA info is owned by somebody else now.
*
* If sta_info_unlink() did not clear the pointer then the caller owns
* the STA info structure now and is responsible of destroying it with
- * a call to sta_info_destroy(), not before RCU synchronisation, of
- * course. Note that sta_info_destroy() must be protected by the RTNL.
+ * a call to sta_info_destroy().
*
* In all other cases, there is no concept of ownership on a STA entry,
* each structure is owned by the global hash table/list until it is
struct sk_buff *skb;
int i;
- ASSERT_RTNL();
might_sleep();
if (!sta)
mesh_plink_deactivate(sta);
#endif
- if (sta->key) {
- /*
- * NOTE: This will call synchronize_rcu() internally to
- * make sure no key references can be in use. We rely on
- * that when we take this branch to make sure nobody can
- * reference this STA struct any longer!
- */
- ieee80211_key_free(sta->key);
- WARN_ON(sta->key);
- } else {
- /*
- * Make sure that nobody can reference this STA struct
- * any longer.
- */
- synchronize_rcu();
- }
+ /*
+ * We have only unlinked the key, and actually destroying it
+ * 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();
#ifdef CONFIG_MAC80211_MESH
if (ieee80211_vif_is_mesh(&sta->sdata->vif))
dev_kfree_skb_any(skb);
for (i = 0; i < STA_TID_NUM; i++) {
- spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
+ spin_lock_bh(&sta->lock);
if (sta->ampdu_mlme.tid_rx[i])
del_timer_sync(&sta->ampdu_mlme.tid_rx[i]->session_timer);
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
if (sta->ampdu_mlme.tid_tx[i])
del_timer_sync(&sta->ampdu_mlme.tid_tx[i]->addba_resp_timer);
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
}
__sta_info_free(local, sta);
if (!sta)
return NULL;
+ spin_lock_init(&sta->lock);
+ spin_lock_init(&sta->flaglock);
+
memcpy(sta->addr, addr, ETH_ALEN);
sta->local = local;
sta->sdata = sdata;
return NULL;
}
- spin_lock_init(&sta->ampdu_mlme.ampdu_rx);
- spin_lock_init(&sta->ampdu_mlme.ampdu_tx);
for (i = 0; i < STA_TID_NUM; i++) {
/* timer_to_tid must be initialized with identity mapping to
* enable session_timer's data differentiation. refer to
* sta_rx_agg_session_timer_expired for useage */
sta->timer_to_tid[i] = i;
/* tid to tx queue: initialize according to HW (0 is valid) */
- sta->tid_to_tx_q[i] = local->hw.queues;
+ sta->tid_to_tx_q[i] = ieee80211_num_queues(&local->hw);
/* rx */
sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE;
sta->ampdu_mlme.tid_rx[i] = NULL;
#ifdef CONFIG_MAC80211_MESH
sta->plink_state = PLINK_LISTEN;
- spin_lock_init(&sta->plink_lock);
init_timer(&sta->plink_timer);
#endif
return;
}
+ if ((*sta)->key) {
+ ieee80211_key_free((*sta)->key);
+ WARN_ON((*sta)->key);
+ }
+
list_del(&(*sta)->list);
- if ((*sta)->flags & WLAN_STA_PS) {
- (*sta)->flags &= ~WLAN_STA_PS;
+ if (test_and_clear_sta_flags(*sta, WLAN_STA_PS)) {
if (sdata->bss)
atomic_dec(&sdata->bss->num_sta_ps);
__sta_info_clear_tim_bit(sdata->bss, *sta);
struct sta_info *sta,
struct sk_buff *skb)
{
- struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_tx_info *info;
int timeout;
if (!skb)
return 0;
- pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+ info = IEEE80211_SKB_CB(skb);
/* Timeout: (2 * listen_interval * beacon_int * 1024 / 1000000) sec */
timeout = (sta->listen_interval * local->hw.conf.beacon_int * 32 /
15625) * HZ;
if (timeout < STA_TX_BUFFER_EXPIRE)
timeout = STA_TX_BUFFER_EXPIRE;
- return time_after(jiffies, pkt_data->jiffies + timeout);
+ return time_after(jiffies, info->control.jiffies + timeout);
}
sdata = sta->sdata;
local->total_ps_buffered--;
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "Buffered frame expired (STA "
"%s)\n", print_mac(mac, sta->addr));
+#endif
dev_kfree_skb(skb);
if (skb_queue_empty(&sta->ps_tx_buf))
}
#endif
-void __ieee80211_run_pending_flush(struct ieee80211_local *local)
+static void __ieee80211_run_pending_flush(struct ieee80211_local *local)
{
struct sta_info *sta;
unsigned long flags;