Skip to content

Commit

Permalink
mac80211: disconnect if channel switch fails
Browse files Browse the repository at this point in the history
Disconnect from the AP if channel switching in the
driver failed or if the new channel is unavailable.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
  • Loading branch information
Johannes Berg committed Sep 6, 2012
1 parent 30dd3ed commit 882a7c6
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 18 deletions.
1 change: 1 addition & 0 deletions net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ struct ieee80211_if_managed {
struct work_struct monitor_work;
struct work_struct chswitch_work;
struct work_struct beacon_connection_loss_work;
struct work_struct csa_connection_drop_work;

unsigned long beacon_timeout;
unsigned long probe_timeout;
Expand Down
55 changes: 37 additions & 18 deletions net/mac80211/mlme.c
Original file line number Diff line number Diff line change
Expand Up @@ -730,16 +730,13 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)

trace_api_chswitch_done(sdata, success);
if (!success) {
/*
* If the channel switch was not successful, stay
* around on the old channel. We currently lack
* good handling of this situation, possibly we
* should just drop the association.
*/
sdata->local->csa_channel = sdata->local->oper_channel;
sdata_info(sdata,
"driver channel switch failed, disconnecting\n");
ieee80211_queue_work(&sdata->local->hw,
&ifmgd->csa_connection_drop_work);
} else {
ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
}

ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
}
EXPORT_SYMBOL(ieee80211_chswitch_done);

Expand Down Expand Up @@ -784,8 +781,14 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
return;

new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED)
if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) {
sdata_info(sdata,
"AP %pM switches to unsupported channel (%d MHz), disconnecting\n",
ifmgd->associated->bssid, new_freq);
ieee80211_queue_work(&sdata->local->hw,
&ifmgd->csa_connection_drop_work);
return;
}

sdata->local->csa_channel = new_ch;

Expand Down Expand Up @@ -1692,7 +1695,8 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ieee80211_ap_probereq_get);

static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata,
bool transmit_frame)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
Expand All @@ -1704,12 +1708,10 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
return;
}

sdata_info(sdata, "Connection to AP %pM lost\n",
ifmgd->associated->bssid);

ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
false, frame_buf);
transmit_frame, frame_buf);
ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
mutex_unlock(&ifmgd->mtx);

/*
Expand Down Expand Up @@ -1739,10 +1741,24 @@ static void ieee80211_beacon_connection_loss_work(struct work_struct *work)
rcu_read_unlock();
}

if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
__ieee80211_connection_loss(sdata);
else
if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) {
sdata_info(sdata, "Connection to AP %pM lost\n",
ifmgd->bssid);
__ieee80211_disconnect(sdata, false);
} else {
ieee80211_mgd_probe_ap(sdata, true);
}
}

static void ieee80211_csa_connection_drop_work(struct work_struct *work)
{
struct ieee80211_sub_if_data *sdata =
container_of(work, struct ieee80211_sub_if_data,
u.mgd.csa_connection_drop_work);

ieee80211_wake_queues_by_reason(&sdata->local->hw,
IEEE80211_QUEUE_STOP_REASON_CSA);
__ieee80211_disconnect(sdata, true);
}

void ieee80211_beacon_loss(struct ieee80211_vif *vif)
Expand Down Expand Up @@ -2929,6 +2945,7 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)

cancel_work_sync(&ifmgd->monitor_work);
cancel_work_sync(&ifmgd->beacon_connection_loss_work);
cancel_work_sync(&ifmgd->csa_connection_drop_work);
if (del_timer_sync(&ifmgd->timer))
set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);

Expand Down Expand Up @@ -2985,6 +3002,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
INIT_WORK(&ifmgd->beacon_connection_loss_work,
ieee80211_beacon_connection_loss_work);
INIT_WORK(&ifmgd->csa_connection_drop_work,
ieee80211_csa_connection_drop_work);
INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work);
setup_timer(&ifmgd->timer, ieee80211_sta_timer,
(unsigned long) sdata);
Expand Down

0 comments on commit 882a7c6

Please sign in to comment.