Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 265683
b: refs/heads/master
c: 8c71df7
h: refs/heads/master
i:
  265681: 850afed
  265679: baec33e
v: v3
  • Loading branch information
Guy Eilam authored and John W. Linville committed Aug 26, 2011
1 parent 9f8bbf1 commit e8f963c
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 54 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: df766267c8d8d71acb0b23575250cac718c6b711
refs/heads/master: 8c71df7a2f6a5345d6cad34e810c50edeca81521
148 changes: 95 additions & 53 deletions trunk/net/mac80211/sta_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -368,93 +368,90 @@ static void sta_info_finish_work(struct work_struct *work)
mutex_unlock(&local->sta_mtx);
}

int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
static int sta_info_insert_check(struct sta_info *sta)
{
struct ieee80211_local *local = sta->local;
struct ieee80211_sub_if_data *sdata = sta->sdata;
unsigned long flags;
int err = 0;

/*
* Can't be a WARN_ON because it can be triggered through a race:
* something inserts a STA (on one CPU) without holding the RTNL
* and another CPU turns off the net device.
*/
if (unlikely(!ieee80211_sdata_running(sdata))) {
err = -ENETDOWN;
rcu_read_lock();
goto out_free;
}
if (unlikely(!ieee80211_sdata_running(sdata)))
return -ENETDOWN;

if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->vif.addr) == 0 ||
is_multicast_ether_addr(sta->sta.addr))) {
err = -EINVAL;
is_multicast_ether_addr(sta->sta.addr)))
return -EINVAL;

return 0;
}

static int sta_info_insert_ibss(struct sta_info *sta) __acquires(RCU)
{
struct ieee80211_local *local = sta->local;
struct ieee80211_sub_if_data *sdata = sta->sdata;
unsigned long flags;

spin_lock_irqsave(&local->sta_lock, flags);
/* check if STA exists already */
if (sta_info_get_bss(sdata, sta->sta.addr)) {
spin_unlock_irqrestore(&local->sta_lock, flags);
rcu_read_lock();
goto out_free;
return -EEXIST;
}

/*
* In ad-hoc mode, we sometimes need to insert stations
* from tasklet context from the RX path. To avoid races,
* always do so in that case -- see the comment below.
*/
if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
spin_lock_irqsave(&local->sta_lock, flags);
/* check if STA exists already */
if (sta_info_get_bss(sdata, sta->sta.addr)) {
spin_unlock_irqrestore(&local->sta_lock, flags);
rcu_read_lock();
err = -EEXIST;
goto out_free;
}

local->num_sta++;
local->sta_generation++;
smp_mb();
sta_info_hash_add(local, sta);
local->num_sta++;
local->sta_generation++;
smp_mb();
sta_info_hash_add(local, sta);

list_add_tail(&sta->list, &local->sta_pending_list);
list_add_tail(&sta->list, &local->sta_pending_list);

rcu_read_lock();
spin_unlock_irqrestore(&local->sta_lock, flags);
rcu_read_lock();
spin_unlock_irqrestore(&local->sta_lock, flags);

#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
wiphy_debug(local->hw.wiphy, "Added IBSS STA %pM\n",
sta->sta.addr);
wiphy_debug(local->hw.wiphy, "Added IBSS STA %pM\n",
sta->sta.addr);
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */

ieee80211_queue_work(&local->hw, &local->sta_finish_work);
ieee80211_queue_work(&local->hw, &local->sta_finish_work);

return 0;
}
return 0;
}

/*
* should be called with sta_mtx locked
* this function replaces the mutex lock
* with a RCU lock
*/
static int sta_info_insert_non_ibss(struct sta_info *sta) __acquires(RCU)
{
struct ieee80211_local *local = sta->local;
struct ieee80211_sub_if_data *sdata = sta->sdata;
unsigned long flags;
int err = 0;

lockdep_assert_held(&local->sta_mtx);

/*
* On first glance, this will look racy, because the code
* below this point, which inserts a station with sleeping,
* in this function, which inserts a station with sleeping,
* unlocks the sta_lock between checking existence in the
* hash table and inserting into it.
*
* However, it is not racy against itself because it keeps
* the mutex locked. It still seems to race against the
* above code that atomically inserts the station... That,
* however, is not true because the above code can only
* be invoked for IBSS interfaces, and the below code will
* not be -- and the two do not race against each other as
* the hash table also keys off the interface.
* the mutex locked.
*/

might_sleep();

mutex_lock(&local->sta_mtx);

spin_lock_irqsave(&local->sta_lock, flags);
/* check if STA exists already */
if (sta_info_get_bss(sdata, sta->sta.addr)) {
spin_unlock_irqrestore(&local->sta_lock, flags);
mutex_unlock(&local->sta_mtx);
rcu_read_lock();
err = -EEXIST;
goto out_free;
return -EEXIST;
}

spin_unlock_irqrestore(&local->sta_lock, flags);
Expand All @@ -463,7 +460,7 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
if (err) {
mutex_unlock(&local->sta_mtx);
rcu_read_lock();
goto out_free;
return err;
}

#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
Expand All @@ -477,6 +474,51 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
if (ieee80211_vif_is_mesh(&sdata->vif))
mesh_accept_plinks_update(sdata);

return 0;
}

int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
{
struct ieee80211_local *local = sta->local;
struct ieee80211_sub_if_data *sdata = sta->sdata;
int err = 0;

err = sta_info_insert_check(sta);
if (err) {
rcu_read_lock();
goto out_free;
}

/*
* In ad-hoc mode, we sometimes need to insert stations
* from tasklet context from the RX path. To avoid races,
* always do so in that case -- see the comment below.
*/
if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
err = sta_info_insert_ibss(sta);
if (err)
goto out_free;

return 0;
}

/*
* It might seem that the function called below is in race against
* the function call above that atomically inserts the station... That,
* however, is not true because the above code can only
* be invoked for IBSS interfaces, and the below code will
* not be -- and the two do not race against each other as
* the hash table also keys off the interface.
*/

might_sleep();

mutex_lock(&local->sta_mtx);

err = sta_info_insert_non_ibss(sta);
if (err)
goto out_free;

return 0;
out_free:
BUG_ON(!err);
Expand Down

0 comments on commit e8f963c

Please sign in to comment.