Commit 0c21e632 authored by Luciano Coelho's avatar Luciano Coelho Committed by Johannes Berg

mac80211: wait for the first beacon on the new channel after CSA

Instead of immediately reopening the queues (in case of block_tx),
calling the post_channel_switch operation and sending the
notification, wait for the first beacon on the new channel.  This
makes sure that we don't lose packets if the AP/GO is not on the new
channel yet.
Signed-off-by: default avatarLuciano Coelho <luciano.coelho@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent f1d65583
...@@ -434,6 +434,8 @@ struct ieee80211_if_managed { ...@@ -434,6 +434,8 @@ struct ieee80211_if_managed {
unsigned int flags; unsigned int flags;
bool csa_waiting_bcn;
bool beacon_crc_valid; bool beacon_crc_valid;
u32 beacon_crc; u32 beacon_crc;
......
...@@ -842,6 +842,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, ...@@ -842,6 +842,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
sdata_lock(sdata); sdata_lock(sdata);
mutex_lock(&local->mtx); mutex_lock(&local->mtx);
sdata->vif.csa_active = false; sdata->vif.csa_active = false;
if (sdata->vif.type == NL80211_IFTYPE_STATION)
sdata->u.mgd.csa_waiting_bcn = false;
if (sdata->csa_block_tx) { if (sdata->csa_block_tx) {
ieee80211_wake_vif_queues(local, sdata, ieee80211_wake_vif_queues(local, sdata,
IEEE80211_QUEUE_STOP_REASON_CSA); IEEE80211_QUEUE_STOP_REASON_CSA);
......
...@@ -1001,31 +1001,44 @@ static void ieee80211_chswitch_work(struct work_struct *work) ...@@ -1001,31 +1001,44 @@ static void ieee80211_chswitch_work(struct work_struct *work)
/* XXX: shouldn't really modify cfg80211-owned data! */ /* XXX: shouldn't really modify cfg80211-owned data! */
ifmgd->associated->channel = sdata->csa_chandef.chan; ifmgd->associated->channel = sdata->csa_chandef.chan;
sdata->vif.csa_active = false; ifmgd->csa_waiting_bcn = true;
ieee80211_sta_reset_beacon_monitor(sdata);
ieee80211_sta_reset_conn_monitor(sdata);
out:
mutex_unlock(&local->chanctx_mtx);
mutex_unlock(&local->mtx);
sdata_unlock(sdata);
}
static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
int ret;
sdata_assert_lock(sdata);
WARN_ON(!sdata->vif.csa_active);
/* XXX: wait for a beacon first? */
if (sdata->csa_block_tx) { if (sdata->csa_block_tx) {
ieee80211_wake_vif_queues(local, sdata, ieee80211_wake_vif_queues(local, sdata,
IEEE80211_QUEUE_STOP_REASON_CSA); IEEE80211_QUEUE_STOP_REASON_CSA);
sdata->csa_block_tx = false; sdata->csa_block_tx = false;
} }
sdata->vif.csa_active = false;
ifmgd->csa_waiting_bcn = false;
ret = drv_post_channel_switch(sdata); ret = drv_post_channel_switch(sdata);
if (ret) { if (ret) {
sdata_info(sdata, sdata_info(sdata,
"driver post channel switch failed, disconnecting\n"); "driver post channel switch failed, disconnecting\n");
ieee80211_queue_work(&local->hw, ieee80211_queue_work(&local->hw,
&ifmgd->csa_connection_drop_work); &ifmgd->csa_connection_drop_work);
goto out; return;
} }
ieee80211_sta_reset_beacon_monitor(sdata);
ieee80211_sta_reset_conn_monitor(sdata);
out:
mutex_unlock(&local->chanctx_mtx);
mutex_unlock(&local->mtx);
sdata_unlock(sdata);
} }
void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
...@@ -1943,6 +1956,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ...@@ -1943,6 +1956,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
ieee80211_vif_release_channel(sdata); ieee80211_vif_release_channel(sdata);
sdata->vif.csa_active = false; sdata->vif.csa_active = false;
ifmgd->csa_waiting_bcn = false;
if (sdata->csa_block_tx) { if (sdata->csa_block_tx) {
ieee80211_wake_vif_queues(local, sdata, ieee80211_wake_vif_queues(local, sdata,
IEEE80211_QUEUE_STOP_REASON_CSA); IEEE80211_QUEUE_STOP_REASON_CSA);
...@@ -2191,6 +2205,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) ...@@ -2191,6 +2205,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
true, frame_buf); true, frame_buf);
mutex_lock(&local->mtx); mutex_lock(&local->mtx);
sdata->vif.csa_active = false; sdata->vif.csa_active = false;
ifmgd->csa_waiting_bcn = false;
if (sdata->csa_block_tx) { if (sdata->csa_block_tx) {
ieee80211_wake_vif_queues(local, sdata, ieee80211_wake_vif_queues(local, sdata,
IEEE80211_QUEUE_STOP_REASON_CSA); IEEE80211_QUEUE_STOP_REASON_CSA);
...@@ -3215,6 +3230,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, ...@@ -3215,6 +3230,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
} }
} }
if (ifmgd->csa_waiting_bcn)
ieee80211_chswitch_post_beacon(sdata);
if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
return; return;
ifmgd->beacon_crc = ncrc; ifmgd->beacon_crc = ncrc;
...@@ -3687,11 +3705,12 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data) ...@@ -3687,11 +3705,12 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data)
struct ieee80211_sub_if_data *sdata = struct ieee80211_sub_if_data *sdata =
(struct ieee80211_sub_if_data *) data; (struct ieee80211_sub_if_data *) data;
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
if (local->quiescing) if (local->quiescing)
return; return;
if (sdata->vif.csa_active) if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
return; return;
sdata->u.mgd.connection_loss = false; sdata->u.mgd.connection_loss = false;
...@@ -3709,7 +3728,7 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data) ...@@ -3709,7 +3728,7 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data)
if (local->quiescing) if (local->quiescing)
return; return;
if (sdata->vif.csa_active) if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
return; return;
ieee80211_queue_work(&local->hw, &ifmgd->monitor_work); ieee80211_queue_work(&local->hw, &ifmgd->monitor_work);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment