mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-13 01:08:50 +00:00
mac80211: delay IBSS station insertion
In order to notify drivers and simplify the station management code, defer IBSS station insertion to a work item and don't do it directly while receiving a frame. This increases the complexity in IBSS a little bit, but it's pretty straight forward and it allows us to reduce the station management complexity (next patch) considerably. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
56544160d4
commit
8bf11d8d08
@ -275,6 +275,80 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
cbss->tsf);
|
||||
}
|
||||
|
||||
static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta)
|
||||
__acquires(RCU)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
u8 addr[ETH_ALEN];
|
||||
|
||||
memcpy(addr, sta->sta.addr, ETH_ALEN);
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
wiphy_debug(sdata->local->hw.wiphy,
|
||||
"Adding new IBSS station %pM (dev=%s)\n",
|
||||
addr, sdata->name);
|
||||
#endif
|
||||
|
||||
sta_info_move_state(sta, IEEE80211_STA_AUTH);
|
||||
sta_info_move_state(sta, IEEE80211_STA_ASSOC);
|
||||
sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
|
||||
|
||||
rate_control_rate_init(sta);
|
||||
|
||||
/* If it fails, maybe we raced another insertion? */
|
||||
if (sta_info_insert_rcu(sta))
|
||||
return sta_info_get(sdata, addr);
|
||||
return sta;
|
||||
}
|
||||
|
||||
static struct sta_info *
|
||||
ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *bssid, const u8 *addr,
|
||||
u32 supp_rates)
|
||||
__acquires(RCU)
|
||||
{
|
||||
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta;
|
||||
int band = local->hw.conf.channel->band;
|
||||
|
||||
/*
|
||||
* XXX: Consider removing the least recently used entry and
|
||||
* allow new one to be added.
|
||||
*/
|
||||
if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
|
||||
if (net_ratelimit())
|
||||
printk(KERN_DEBUG "%s: No room for a new IBSS STA entry %pM\n",
|
||||
sdata->name, addr);
|
||||
rcu_read_lock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ifibss->state == IEEE80211_IBSS_MLME_SEARCH) {
|
||||
rcu_read_lock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (compare_ether_addr(bssid, sdata->u.ibss.bssid)) {
|
||||
rcu_read_lock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sta = sta_info_alloc(sdata, addr, GFP_KERNEL);
|
||||
if (!sta) {
|
||||
rcu_read_lock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sta->last_rx = jiffies;
|
||||
|
||||
/* make sure mandatory rates are always added */
|
||||
sta->sta.supp_rates[band] = supp_rates |
|
||||
ieee80211_mandatory_rates(local, band);
|
||||
|
||||
return ieee80211_ibss_finish_sta(sta);
|
||||
}
|
||||
|
||||
static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
size_t len,
|
||||
@ -334,10 +408,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
#endif
|
||||
rates_updated = true;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
rcu_read_unlock();
|
||||
sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
|
||||
mgmt->sa, supp_rates,
|
||||
GFP_ATOMIC);
|
||||
mgmt->sa, supp_rates);
|
||||
}
|
||||
}
|
||||
|
||||
if (sta && elems->wmm_info)
|
||||
@ -464,21 +539,17 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||
ieee80211_sta_join_ibss(sdata, bss);
|
||||
supp_rates = ieee80211_sta_get_rates(local, elems, band);
|
||||
ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
|
||||
supp_rates, GFP_KERNEL);
|
||||
supp_rates);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
put_bss:
|
||||
ieee80211_rx_bss_put(local, bss);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a new IBSS station, will also be called by the RX code when,
|
||||
* in IBSS mode, receiving a frame from a yet-unknown station, hence
|
||||
* must be callable in atomic context.
|
||||
*/
|
||||
struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
|
||||
u8 *bssid, u8 *addr, u32 supp_rates,
|
||||
gfp_t gfp)
|
||||
void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *bssid, const u8 *addr,
|
||||
u32 supp_rates)
|
||||
{
|
||||
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
@ -493,40 +564,29 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
|
||||
if (net_ratelimit())
|
||||
printk(KERN_DEBUG "%s: No room for a new IBSS STA entry %pM\n",
|
||||
sdata->name, addr);
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ifibss->state == IEEE80211_IBSS_MLME_SEARCH)
|
||||
return NULL;
|
||||
return;
|
||||
|
||||
if (compare_ether_addr(bssid, sdata->u.ibss.bssid))
|
||||
return NULL;
|
||||
return;
|
||||
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
wiphy_debug(local->hw.wiphy, "Adding new IBSS station %pM (dev=%s)\n",
|
||||
addr, sdata->name);
|
||||
#endif
|
||||
|
||||
sta = sta_info_alloc(sdata, addr, gfp);
|
||||
sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
|
||||
if (!sta)
|
||||
return NULL;
|
||||
return;
|
||||
|
||||
sta->last_rx = jiffies;
|
||||
|
||||
sta_info_move_state(sta, IEEE80211_STA_AUTH);
|
||||
sta_info_move_state(sta, IEEE80211_STA_ASSOC);
|
||||
sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
|
||||
|
||||
/* make sure mandatory rates are always added */
|
||||
sta->sta.supp_rates[band] = supp_rates |
|
||||
ieee80211_mandatory_rates(local, band);
|
||||
|
||||
rate_control_rate_init(sta);
|
||||
|
||||
/* If it fails, maybe we raced another insertion? */
|
||||
if (sta_info_insert(sta))
|
||||
return sta_info_get(sdata, addr);
|
||||
return sta;
|
||||
spin_lock(&ifibss->incomplete_lock);
|
||||
list_add(&sta->list, &ifibss->incomplete_stations);
|
||||
spin_unlock(&ifibss->incomplete_lock);
|
||||
ieee80211_queue_work(&local->hw, &sdata->work);
|
||||
}
|
||||
|
||||
static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
|
||||
@ -865,6 +925,7 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
|
||||
void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
||||
struct sta_info *sta;
|
||||
|
||||
mutex_lock(&ifibss->mtx);
|
||||
|
||||
@ -876,6 +937,19 @@ void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata)
|
||||
if (!ifibss->ssid_len)
|
||||
goto out;
|
||||
|
||||
spin_lock_bh(&ifibss->incomplete_lock);
|
||||
while (!list_empty(&ifibss->incomplete_stations)) {
|
||||
sta = list_first_entry(&ifibss->incomplete_stations,
|
||||
struct sta_info, list);
|
||||
list_del(&sta->list);
|
||||
spin_unlock_bh(&ifibss->incomplete_lock);
|
||||
|
||||
ieee80211_ibss_finish_sta(sta);
|
||||
rcu_read_unlock();
|
||||
spin_lock_bh(&ifibss->incomplete_lock);
|
||||
}
|
||||
spin_unlock_bh(&ifibss->incomplete_lock);
|
||||
|
||||
switch (ifibss->state) {
|
||||
case IEEE80211_IBSS_MLME_SEARCH:
|
||||
ieee80211_sta_find_ibss(sdata);
|
||||
@ -934,6 +1008,8 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata)
|
||||
setup_timer(&ifibss->timer, ieee80211_ibss_timer,
|
||||
(unsigned long) sdata);
|
||||
mutex_init(&ifibss->mtx);
|
||||
INIT_LIST_HEAD(&ifibss->incomplete_stations);
|
||||
spin_lock_init(&ifibss->incomplete_lock);
|
||||
}
|
||||
|
||||
/* scan finished notification */
|
||||
@ -1053,6 +1129,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
|
||||
struct cfg80211_bss *cbss;
|
||||
u16 capability;
|
||||
int active_ibss;
|
||||
struct sta_info *sta;
|
||||
|
||||
mutex_lock(&sdata->u.ibss.mtx);
|
||||
|
||||
@ -1081,6 +1158,19 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
|
||||
}
|
||||
|
||||
sta_info_flush(sdata->local, sdata);
|
||||
|
||||
spin_lock_bh(&ifibss->incomplete_lock);
|
||||
while (!list_empty(&ifibss->incomplete_stations)) {
|
||||
sta = list_first_entry(&ifibss->incomplete_stations,
|
||||
struct sta_info, list);
|
||||
list_del(&sta->list);
|
||||
spin_unlock_bh(&ifibss->incomplete_lock);
|
||||
|
||||
sta_info_free(local, sta);
|
||||
spin_lock_bh(&ifibss->incomplete_lock);
|
||||
}
|
||||
spin_unlock_bh(&ifibss->incomplete_lock);
|
||||
|
||||
netif_carrier_off(sdata->dev);
|
||||
|
||||
/* remove beacon */
|
||||
|
@ -482,6 +482,9 @@ struct ieee80211_if_ibss {
|
||||
struct sk_buff __rcu *presp;
|
||||
struct sk_buff *skb;
|
||||
|
||||
spinlock_t incomplete_lock;
|
||||
struct list_head incomplete_stations;
|
||||
|
||||
enum {
|
||||
IEEE80211_IBSS_MLME_SEARCH,
|
||||
IEEE80211_IBSS_MLME_JOINED,
|
||||
@ -1172,9 +1175,8 @@ void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata);
|
||||
/* IBSS code */
|
||||
void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
|
||||
void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata);
|
||||
struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
|
||||
u8 *bssid, u8 *addr, u32 supp_rates,
|
||||
gfp_t gfp);
|
||||
void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
|
||||
const u8 *bssid, const u8 *addr, u32 supp_rates);
|
||||
int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_ibss_params *params);
|
||||
int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata);
|
||||
|
@ -2775,8 +2775,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
|
||||
rate_idx = 0; /* TODO: HT rates */
|
||||
else
|
||||
rate_idx = status->rate_idx;
|
||||
rx->sta = ieee80211_ibss_add_sta(sdata, bssid,
|
||||
hdr->addr2, BIT(rate_idx), GFP_ATOMIC);
|
||||
ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2,
|
||||
BIT(rate_idx));
|
||||
}
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
|
@ -354,35 +354,26 @@ static int sta_info_finish_insert(struct sta_info *sta,
|
||||
/* notify driver */
|
||||
err = drv_sta_add(local, sdata, &sta->sta);
|
||||
if (err) {
|
||||
if (!async)
|
||||
if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
|
||||
return err;
|
||||
printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to "
|
||||
"driver (%d) - keeping it anyway.\n",
|
||||
sdata->name, sta->sta.addr, err);
|
||||
} else {
|
||||
} else
|
||||
sta->uploaded = true;
|
||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
||||
if (async)
|
||||
wiphy_debug(local->hw.wiphy,
|
||||
"Finished adding IBSS STA %pM\n",
|
||||
sta->sta.addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
sdata = sta->sdata;
|
||||
}
|
||||
|
||||
if (!dummy_reinsert) {
|
||||
if (!async) {
|
||||
local->num_sta++;
|
||||
local->sta_generation++;
|
||||
smp_mb();
|
||||
local->num_sta++;
|
||||
local->sta_generation++;
|
||||
smp_mb();
|
||||
|
||||
/* make the station visible */
|
||||
spin_lock_irqsave(&local->sta_lock, flags);
|
||||
sta_info_hash_add(local, sta);
|
||||
spin_unlock_irqrestore(&local->sta_lock, flags);
|
||||
}
|
||||
/* make the station visible */
|
||||
spin_lock_irqsave(&local->sta_lock, flags);
|
||||
sta_info_hash_add(local, sta);
|
||||
spin_unlock_irqrestore(&local->sta_lock, flags);
|
||||
|
||||
list_add(&sta->list, &local->sta_list);
|
||||
} else {
|
||||
@ -1546,7 +1537,7 @@ EXPORT_SYMBOL(ieee80211_sta_set_buffered);
|
||||
int sta_info_move_state_checked(struct sta_info *sta,
|
||||
enum ieee80211_sta_state new_state)
|
||||
{
|
||||
/* might_sleep(); -- for driver notify later, fix IBSS first */
|
||||
might_sleep();
|
||||
|
||||
if (sta->sta_state == new_state)
|
||||
return 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user