Commit 7852e361 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

mac80211: remove dummy STA support

The dummy STA support was added because I didn't
want to change the driver API at the time. Now
that we have state transitions triggering station
add/remove in the driver, we only call add once a
station reaches ASSOCIATED, so we can remove the
dummy station stuff again.

While at it, tighten the RX check and accept only
port control (EAP) frames from the AP station if
it's not associated yet -- in other cases there's
no race.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent a4ec45a4
......@@ -1581,7 +1581,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
* station info was already allocated and inserted before
* the association and should be available to us
*/
sta = sta_info_get_rx(sdata, cbss->bssid);
sta = sta_info_get(sdata, cbss->bssid);
if (WARN_ON(!sta)) {
mutex_unlock(&sdata->local->sta_mtx);
return false;
......@@ -1648,14 +1648,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
return false;
}
/* sta_info_reinsert will also unlock the mutex lock */
err = sta_info_reinsert(sta);
sta = NULL;
if (err) {
printk(KERN_DEBUG "%s: failed to insert STA entry for"
" the AP (error %d)\n", sdata->name, err);
return false;
}
mutex_unlock(&sdata->local->sta_mtx);
/*
* Always handle WMM once after association regardless
......@@ -2536,12 +2529,10 @@ static int ieee80211_pre_assoc(struct ieee80211_sub_if_data *sdata,
if (!sta)
return -ENOMEM;
sta->dummy = true;
err = sta_info_insert(sta);
sta = NULL;
if (err) {
printk(KERN_DEBUG "%s: failed to insert Dummy STA entry for"
printk(KERN_DEBUG "%s: failed to insert STA entry for"
" the AP (error %d)\n", sdata->name, err);
return err;
}
......
......@@ -859,7 +859,12 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
rx->sdata->vif.type != NL80211_IFTYPE_WDS &&
(!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) {
if (rx->sta && rx->sta->dummy &&
/*
* accept port control frames from the AP even when it's not
* yet marked ASSOC to prevent a race where we don't set the
* assoc bit quickly enough before it sends the first frame
*/
if (rx->sta && rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
ieee80211_is_data_present(hdr->frame_control)) {
u16 ethertype;
u8 *payload;
......@@ -2949,7 +2954,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
if (ieee80211_is_data(fc)) {
prev_sta = NULL;
for_each_sta_info_rx(local, hdr->addr2, sta, tmp) {
for_each_sta_info(local, hdr->addr2, sta, tmp) {
if (!prev_sta) {
prev_sta = sta;
continue;
......@@ -2993,7 +2998,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
continue;
}
rx.sta = sta_info_get_bss_rx(prev, hdr->addr2);
rx.sta = sta_info_get_bss(prev, hdr->addr2);
rx.sdata = prev;
ieee80211_prepare_and_rx_handle(&rx, skb, false);
......@@ -3001,7 +3006,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
}
if (prev) {
rx.sta = sta_info_get_bss_rx(prev, hdr->addr2);
rx.sta = sta_info_get_bss(prev, hdr->addr2);
rx.sdata = prev;
if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
......
......@@ -97,25 +97,6 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
lockdep_is_held(&local->sta_mtx));
while (sta) {
if (sta->sdata == sdata && !sta->dummy &&
memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
break;
sta = rcu_dereference_check(sta->hnext,
lockdep_is_held(&local->sta_mtx));
}
return sta;
}
/* get a station info entry even if it is a dummy station*/
struct sta_info *sta_info_get_rx(struct ieee80211_sub_if_data *sdata,
const u8 *addr)
{
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
lockdep_is_held(&local->sta_mtx));
while (sta) {
......@@ -138,30 +119,6 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
lockdep_is_held(&local->sta_mtx));
while (sta) {
if ((sta->sdata == sdata ||
(sta->sdata->bss && sta->sdata->bss == sdata->bss)) &&
!sta->dummy &&
memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
break;
sta = rcu_dereference_check(sta->hnext,
lockdep_is_held(&local->sta_mtx));
}
return sta;
}
/*
* Get sta info either from the specified interface
* or from one of its vlans (including dummy stations)
*/
struct sta_info *sta_info_get_bss_rx(struct ieee80211_sub_if_data *sdata,
const u8 *addr)
{
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
lockdep_is_held(&local->sta_mtx));
while (sta) {
......@@ -397,66 +354,43 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
{
struct ieee80211_local *local = sta->local;
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct sta_info *exist_sta;
bool dummy_reinsert = false;
struct station_info sinfo;
int err = 0;
lockdep_assert_held(&local->sta_mtx);
/*
* check if STA exists already.
* only accept a scenario of a second call to sta_info_insert_finish
* with a dummy station entry that was inserted earlier
* in that case - assume that the dummy station flag should
* be removed.
*/
exist_sta = sta_info_get_bss_rx(sdata, sta->sta.addr);
if (exist_sta) {
if (exist_sta == sta && sta->dummy) {
dummy_reinsert = true;
} else {
err = -EEXIST;
goto out_err;
}
}
if (!sta->dummy || dummy_reinsert) {
/* notify driver */
err = sta_info_insert_drv_state(local, sdata, sta);
if (err)
goto out_err;
/* check if STA exists already */
if (sta_info_get_bss(sdata, sta->sta.addr)) {
err = -EEXIST;
goto out_err;
}
if (!dummy_reinsert) {
local->num_sta++;
local->sta_generation++;
smp_mb();
/* notify driver */
err = sta_info_insert_drv_state(local, sdata, sta);
if (err)
goto out_err;
/* make the station visible */
sta_info_hash_add(local, sta);
local->num_sta++;
local->sta_generation++;
smp_mb();
list_add(&sta->list, &local->sta_list);
/* make the station visible */
sta_info_hash_add(local, sta);
set_sta_flag(sta, WLAN_STA_INSERTED);
} else {
sta->dummy = false;
}
list_add(&sta->list, &local->sta_list);
if (!sta->dummy) {
struct station_info sinfo;
set_sta_flag(sta, WLAN_STA_INSERTED);
ieee80211_sta_debugfs_add(sta);
rate_control_add_sta_debugfs(sta);
ieee80211_sta_debugfs_add(sta);
rate_control_add_sta_debugfs(sta);
memset(&sinfo, 0, sizeof(sinfo));
sinfo.filled = 0;
sinfo.generation = local->sta_generation;
cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
}
memset(&sinfo, 0, sizeof(sinfo));
sinfo.filled = 0;
sinfo.generation = local->sta_generation;
cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
wiphy_debug(local->hw.wiphy, "Inserted %sSTA %pM\n",
sta->dummy ? "dummy " : "", sta->sta.addr);
wiphy_debug(local->hw.wiphy, "Inserted STA %pM\n", sta->sta.addr);
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
/* move reference to rcu-protected */
......@@ -508,25 +442,6 @@ int sta_info_insert(struct sta_info *sta)
return err;
}
/* Caller must hold sta->local->sta_mtx */
int sta_info_reinsert(struct sta_info *sta)
{
struct ieee80211_local *local = sta->local;
int err = 0;
err = sta_info_insert_check(sta);
if (err) {
mutex_unlock(&local->sta_mtx);
return err;
}
might_sleep();
err = sta_info_insert_finish(sta);
rcu_read_unlock();
return err;
}
static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid)
{
/*
......@@ -873,7 +788,7 @@ int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, const u8 *addr)
int ret;
mutex_lock(&sdata->local->sta_mtx);
sta = sta_info_get_rx(sdata, addr);
sta = sta_info_get(sdata, addr);
ret = __sta_info_destroy(sta);
mutex_unlock(&sdata->local->sta_mtx);
......@@ -887,7 +802,7 @@ int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata,
int ret;
mutex_lock(&sdata->local->sta_mtx);
sta = sta_info_get_bss_rx(sdata, addr);
sta = sta_info_get_bss(sdata, addr);
ret = __sta_info_destroy(sta);
mutex_unlock(&sdata->local->sta_mtx);
......
......@@ -265,8 +265,6 @@ struct sta_ampdu_mlme {
* @dead: set to true when sta is unlinked
* @uploaded: set to true when sta is uploaded to the driver
* @lost_packets: number of consecutive lost packets
* @dummy: indicate a dummy station created for receiving
* EAP frames before association
* @sta: station information we share with the driver
* @sta_state: duplicates information about station state (for debug)
* @beacon_loss_count: number of times beacon loss has triggered
......@@ -364,9 +362,6 @@ struct sta_info {
unsigned int lost_packets;
unsigned int beacon_loss_count;
/* should be right in front of sta to be in the same cache line */
bool dummy;
/* keep last! */
struct ieee80211_sta sta;
};
......@@ -468,15 +463,9 @@ rcu_dereference_protected_tid_tx(struct sta_info *sta, int tid)
struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
const u8 *addr);
struct sta_info *sta_info_get_rx(struct ieee80211_sub_if_data *sdata,
const u8 *addr);
struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
const u8 *addr);
struct sta_info *sta_info_get_bss_rx(struct ieee80211_sub_if_data *sdata,
const u8 *addr);
static inline
void for_each_sta_info_type_check(struct ieee80211_local *local,
const u8 *addr,
......@@ -485,23 +474,7 @@ void for_each_sta_info_type_check(struct ieee80211_local *local,
{
}
#define for_each_sta_info(local, _addr, _sta, nxt) \
for ( /* initialise loop */ \
_sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\
nxt = _sta ? rcu_dereference(_sta->hnext) : NULL; \
/* typecheck */ \
for_each_sta_info_type_check(local, (_addr), _sta, nxt),\
/* continue condition */ \
_sta; \
/* advance loop */ \
_sta = nxt, \
nxt = _sta ? rcu_dereference(_sta->hnext) : NULL \
) \
/* run code only if address matches and it's not a dummy sta */ \
if (memcmp(_sta->sta.addr, (_addr), ETH_ALEN) == 0 && \
!_sta->dummy)
#define for_each_sta_info_rx(local, _addr, _sta, nxt) \
#define for_each_sta_info(local, _addr, _sta, nxt) \
for ( /* initialise loop */ \
_sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\
nxt = _sta ? rcu_dereference(_sta->hnext) : NULL; \
......@@ -540,7 +513,6 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta);
*/
int sta_info_insert(struct sta_info *sta);
int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU);
int sta_info_reinsert(struct sta_info *sta);
int __must_check __sta_info_destroy(struct sta_info *sta);
int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment