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);
|
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,
|
static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
||||||
struct ieee80211_mgmt *mgmt,
|
struct ieee80211_mgmt *mgmt,
|
||||||
size_t len,
|
size_t len,
|
||||||
@ -334,10 +408,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||||||
#endif
|
#endif
|
||||||
rates_updated = true;
|
rates_updated = true;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
|
rcu_read_unlock();
|
||||||
sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
|
sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
|
||||||
mgmt->sa, supp_rates,
|
mgmt->sa, supp_rates);
|
||||||
GFP_ATOMIC);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sta && elems->wmm_info)
|
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);
|
ieee80211_sta_join_ibss(sdata, bss);
|
||||||
supp_rates = ieee80211_sta_get_rates(local, elems, band);
|
supp_rates = ieee80211_sta_get_rates(local, elems, band);
|
||||||
ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
|
ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
|
||||||
supp_rates, GFP_KERNEL);
|
supp_rates);
|
||||||
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
put_bss:
|
put_bss:
|
||||||
ieee80211_rx_bss_put(local, bss);
|
ieee80211_rx_bss_put(local, bss);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
|
||||||
* Add a new IBSS station, will also be called by the RX code when,
|
const u8 *bssid, const u8 *addr,
|
||||||
* in IBSS mode, receiving a frame from a yet-unknown station, hence
|
u32 supp_rates)
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
||||||
struct ieee80211_local *local = sdata->local;
|
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())
|
if (net_ratelimit())
|
||||||
printk(KERN_DEBUG "%s: No room for a new IBSS STA entry %pM\n",
|
printk(KERN_DEBUG "%s: No room for a new IBSS STA entry %pM\n",
|
||||||
sdata->name, addr);
|
sdata->name, addr);
|
||||||
return NULL;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ifibss->state == IEEE80211_IBSS_MLME_SEARCH)
|
if (ifibss->state == IEEE80211_IBSS_MLME_SEARCH)
|
||||||
return NULL;
|
return;
|
||||||
|
|
||||||
if (compare_ether_addr(bssid, sdata->u.ibss.bssid))
|
if (compare_ether_addr(bssid, sdata->u.ibss.bssid))
|
||||||
return NULL;
|
return;
|
||||||
|
|
||||||
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
|
sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
|
||||||
wiphy_debug(local->hw.wiphy, "Adding new IBSS station %pM (dev=%s)\n",
|
|
||||||
addr, sdata->name);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
sta = sta_info_alloc(sdata, addr, gfp);
|
|
||||||
if (!sta)
|
if (!sta)
|
||||||
return NULL;
|
return;
|
||||||
|
|
||||||
sta->last_rx = jiffies;
|
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 */
|
/* make sure mandatory rates are always added */
|
||||||
sta->sta.supp_rates[band] = supp_rates |
|
sta->sta.supp_rates[band] = supp_rates |
|
||||||
ieee80211_mandatory_rates(local, band);
|
ieee80211_mandatory_rates(local, band);
|
||||||
|
|
||||||
rate_control_rate_init(sta);
|
spin_lock(&ifibss->incomplete_lock);
|
||||||
|
list_add(&sta->list, &ifibss->incomplete_stations);
|
||||||
/* If it fails, maybe we raced another insertion? */
|
spin_unlock(&ifibss->incomplete_lock);
|
||||||
if (sta_info_insert(sta))
|
ieee80211_queue_work(&local->hw, &sdata->work);
|
||||||
return sta_info_get(sdata, addr);
|
|
||||||
return sta;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
|
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)
|
void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata)
|
||||||
{
|
{
|
||||||
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
||||||
|
struct sta_info *sta;
|
||||||
|
|
||||||
mutex_lock(&ifibss->mtx);
|
mutex_lock(&ifibss->mtx);
|
||||||
|
|
||||||
@ -876,6 +937,19 @@ void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata)
|
|||||||
if (!ifibss->ssid_len)
|
if (!ifibss->ssid_len)
|
||||||
goto out;
|
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) {
|
switch (ifibss->state) {
|
||||||
case IEEE80211_IBSS_MLME_SEARCH:
|
case IEEE80211_IBSS_MLME_SEARCH:
|
||||||
ieee80211_sta_find_ibss(sdata);
|
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,
|
setup_timer(&ifibss->timer, ieee80211_ibss_timer,
|
||||||
(unsigned long) sdata);
|
(unsigned long) sdata);
|
||||||
mutex_init(&ifibss->mtx);
|
mutex_init(&ifibss->mtx);
|
||||||
|
INIT_LIST_HEAD(&ifibss->incomplete_stations);
|
||||||
|
spin_lock_init(&ifibss->incomplete_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* scan finished notification */
|
/* scan finished notification */
|
||||||
@ -1053,6 +1129,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
|
|||||||
struct cfg80211_bss *cbss;
|
struct cfg80211_bss *cbss;
|
||||||
u16 capability;
|
u16 capability;
|
||||||
int active_ibss;
|
int active_ibss;
|
||||||
|
struct sta_info *sta;
|
||||||
|
|
||||||
mutex_lock(&sdata->u.ibss.mtx);
|
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);
|
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);
|
netif_carrier_off(sdata->dev);
|
||||||
|
|
||||||
/* remove beacon */
|
/* remove beacon */
|
||||||
|
@ -482,6 +482,9 @@ struct ieee80211_if_ibss {
|
|||||||
struct sk_buff __rcu *presp;
|
struct sk_buff __rcu *presp;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
spinlock_t incomplete_lock;
|
||||||
|
struct list_head incomplete_stations;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
IEEE80211_IBSS_MLME_SEARCH,
|
IEEE80211_IBSS_MLME_SEARCH,
|
||||||
IEEE80211_IBSS_MLME_JOINED,
|
IEEE80211_IBSS_MLME_JOINED,
|
||||||
@ -1172,9 +1175,8 @@ void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata);
|
|||||||
/* IBSS code */
|
/* IBSS code */
|
||||||
void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
|
void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
|
||||||
void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata);
|
void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata);
|
||||||
struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
|
void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
|
||||||
u8 *bssid, u8 *addr, u32 supp_rates,
|
const u8 *bssid, const u8 *addr, u32 supp_rates);
|
||||||
gfp_t gfp);
|
|
||||||
int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
||||||
struct cfg80211_ibss_params *params);
|
struct cfg80211_ibss_params *params);
|
||||||
int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata);
|
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 */
|
rate_idx = 0; /* TODO: HT rates */
|
||||||
else
|
else
|
||||||
rate_idx = status->rate_idx;
|
rate_idx = status->rate_idx;
|
||||||
rx->sta = ieee80211_ibss_add_sta(sdata, bssid,
|
ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2,
|
||||||
hdr->addr2, BIT(rate_idx), GFP_ATOMIC);
|
BIT(rate_idx));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NL80211_IFTYPE_MESH_POINT:
|
case NL80211_IFTYPE_MESH_POINT:
|
||||||
|
@ -354,35 +354,26 @@ static int sta_info_finish_insert(struct sta_info *sta,
|
|||||||
/* notify driver */
|
/* notify driver */
|
||||||
err = drv_sta_add(local, sdata, &sta->sta);
|
err = drv_sta_add(local, sdata, &sta->sta);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (!async)
|
if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
|
||||||
return err;
|
return err;
|
||||||
printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to "
|
printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to "
|
||||||
"driver (%d) - keeping it anyway.\n",
|
"driver (%d) - keeping it anyway.\n",
|
||||||
sdata->name, sta->sta.addr, err);
|
sdata->name, sta->sta.addr, err);
|
||||||
} else {
|
} else
|
||||||
sta->uploaded = true;
|
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;
|
sdata = sta->sdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dummy_reinsert) {
|
if (!dummy_reinsert) {
|
||||||
if (!async) {
|
local->num_sta++;
|
||||||
local->num_sta++;
|
local->sta_generation++;
|
||||||
local->sta_generation++;
|
smp_mb();
|
||||||
smp_mb();
|
|
||||||
|
|
||||||
/* make the station visible */
|
/* make the station visible */
|
||||||
spin_lock_irqsave(&local->sta_lock, flags);
|
spin_lock_irqsave(&local->sta_lock, flags);
|
||||||
sta_info_hash_add(local, sta);
|
sta_info_hash_add(local, sta);
|
||||||
spin_unlock_irqrestore(&local->sta_lock, flags);
|
spin_unlock_irqrestore(&local->sta_lock, flags);
|
||||||
}
|
|
||||||
|
|
||||||
list_add(&sta->list, &local->sta_list);
|
list_add(&sta->list, &local->sta_list);
|
||||||
} else {
|
} else {
|
||||||
@ -1546,7 +1537,7 @@ EXPORT_SYMBOL(ieee80211_sta_set_buffered);
|
|||||||
int sta_info_move_state_checked(struct sta_info *sta,
|
int sta_info_move_state_checked(struct sta_info *sta,
|
||||||
enum ieee80211_sta_state new_state)
|
enum ieee80211_sta_state new_state)
|
||||||
{
|
{
|
||||||
/* might_sleep(); -- for driver notify later, fix IBSS first */
|
might_sleep();
|
||||||
|
|
||||||
if (sta->sta_state == new_state)
|
if (sta->sta_state == new_state)
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user