mac80211: split off ibss disconnect
IBSS CSA will require to disconnect if a channel switch fails, but mac80211 should search and re-connect after this disconnect. To allow such usage, split off the ibss disconnect process in a separate function which only performs the disconnect without overwriting nl80211-supplied parameters. Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
e6b7cde4d3
commit
871a4180b8
|
@ -499,6 +499,96 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid,
|
|||
return ieee80211_ibss_finish_sta(sta);
|
||||
}
|
||||
|
||||
static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
int active = 0;
|
||||
struct sta_info *sta;
|
||||
|
||||
sdata_assert_lock(sdata);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
list_for_each_entry_rcu(sta, &local->sta_list, list) {
|
||||
if (sta->sdata == sdata &&
|
||||
time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
|
||||
jiffies)) {
|
||||
active++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return active;
|
||||
}
|
||||
|
||||
static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct cfg80211_bss *cbss;
|
||||
struct beacon_data *presp;
|
||||
struct sta_info *sta;
|
||||
int active_ibss;
|
||||
u16 capability;
|
||||
|
||||
active_ibss = ieee80211_sta_active_ibss(sdata);
|
||||
|
||||
if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) {
|
||||
capability = WLAN_CAPABILITY_IBSS;
|
||||
|
||||
if (ifibss->privacy)
|
||||
capability |= WLAN_CAPABILITY_PRIVACY;
|
||||
|
||||
cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan,
|
||||
ifibss->bssid, ifibss->ssid,
|
||||
ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
|
||||
WLAN_CAPABILITY_PRIVACY,
|
||||
capability);
|
||||
|
||||
if (cbss) {
|
||||
cfg80211_unlink_bss(local->hw.wiphy, cbss);
|
||||
cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
|
||||
}
|
||||
}
|
||||
|
||||
ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
|
||||
|
||||
sta_info_flush(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);
|
||||
|
||||
sdata->vif.bss_conf.ibss_joined = false;
|
||||
sdata->vif.bss_conf.ibss_creator = false;
|
||||
sdata->vif.bss_conf.enable_beacon = false;
|
||||
sdata->vif.bss_conf.ssid_len = 0;
|
||||
|
||||
/* remove beacon */
|
||||
presp = rcu_dereference_protected(ifibss->presp,
|
||||
lockdep_is_held(&sdata->wdev.mtx));
|
||||
RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);
|
||||
if (presp)
|
||||
kfree_rcu(presp, rcu_head);
|
||||
|
||||
clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
|
||||
BSS_CHANGED_IBSS);
|
||||
ieee80211_vif_release_channel(sdata);
|
||||
}
|
||||
|
||||
static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_mgmt *mgmt,
|
||||
size_t len)
|
||||
|
@ -775,30 +865,6 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
|
|||
ieee80211_queue_work(&local->hw, &sdata->work);
|
||||
}
|
||||
|
||||
static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
int active = 0;
|
||||
struct sta_info *sta;
|
||||
|
||||
sdata_assert_lock(sdata);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
list_for_each_entry_rcu(sta, &local->sta_list, list) {
|
||||
if (sta->sdata == sdata &&
|
||||
time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
|
||||
jiffies)) {
|
||||
active++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return active;
|
||||
}
|
||||
|
||||
static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
|
@ -1265,73 +1331,19 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
|
|||
int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
|
||||
{
|
||||
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct cfg80211_bss *cbss;
|
||||
u16 capability;
|
||||
int active_ibss;
|
||||
struct sta_info *sta;
|
||||
struct beacon_data *presp;
|
||||
|
||||
active_ibss = ieee80211_sta_active_ibss(sdata);
|
||||
|
||||
if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) {
|
||||
capability = WLAN_CAPABILITY_IBSS;
|
||||
|
||||
if (ifibss->privacy)
|
||||
capability |= WLAN_CAPABILITY_PRIVACY;
|
||||
|
||||
cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan,
|
||||
ifibss->bssid, ifibss->ssid,
|
||||
ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
|
||||
WLAN_CAPABILITY_PRIVACY,
|
||||
capability);
|
||||
|
||||
if (cbss) {
|
||||
cfg80211_unlink_bss(local->hw.wiphy, cbss);
|
||||
cfg80211_put_bss(local->hw.wiphy, cbss);
|
||||
}
|
||||
}
|
||||
|
||||
ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
|
||||
memset(ifibss->bssid, 0, ETH_ALEN);
|
||||
ieee80211_ibss_disconnect(sdata);
|
||||
ifibss->ssid_len = 0;
|
||||
|
||||
sta_info_flush(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);
|
||||
memset(ifibss->bssid, 0, ETH_ALEN);
|
||||
|
||||
/* remove beacon */
|
||||
kfree(sdata->u.ibss.ie);
|
||||
presp = rcu_dereference_protected(ifibss->presp,
|
||||
lockdep_is_held(&sdata->wdev.mtx));
|
||||
RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);
|
||||
|
||||
/* on the next join, re-program HT parameters */
|
||||
memset(&ifibss->ht_capa, 0, sizeof(ifibss->ht_capa));
|
||||
memset(&ifibss->ht_capa_mask, 0, sizeof(ifibss->ht_capa_mask));
|
||||
|
||||
sdata->vif.bss_conf.ibss_joined = false;
|
||||
sdata->vif.bss_conf.ibss_creator = false;
|
||||
sdata->vif.bss_conf.enable_beacon = false;
|
||||
sdata->vif.bss_conf.ssid_len = 0;
|
||||
clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
|
||||
BSS_CHANGED_IBSS);
|
||||
ieee80211_vif_release_channel(sdata);
|
||||
synchronize_rcu();
|
||||
kfree(presp);
|
||||
|
||||
skb_queue_purge(&sdata->skb_queue);
|
||||
|
||||
|
|
Loading…
Reference in New Issue