aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuciano Coelho <luciano.coelho@intel.com>2014-10-08 02:48:39 -0400
committerJohannes Berg <johannes.berg@intel.com>2014-10-09 05:30:09 -0400
commit0c21e6320f6ea7c4bd2fc0a8c1d8577b372f92d2 (patch)
tree928688796878b45d17d3138157f947384cec82ad
parentf1d65583bc5bd43ace8abb9d4f4d9e8da407f708 (diff)
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: Luciano Coelho <luciano.coelho@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/iface.c2
-rw-r--r--net/mac80211/mlme.c45
3 files changed, 36 insertions, 13 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a9cc49128980..78d6121eb372 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -434,6 +434,8 @@ struct ieee80211_if_managed {
434 434
435 unsigned int flags; 435 unsigned int flags;
436 436
437 bool csa_waiting_bcn;
438
437 bool beacon_crc_valid; 439 bool beacon_crc_valid;
438 u32 beacon_crc; 440 u32 beacon_crc;
439 441
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index af237223a8cd..e469b3390f2a 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -842,6 +842,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
842 sdata_lock(sdata); 842 sdata_lock(sdata);
843 mutex_lock(&local->mtx); 843 mutex_lock(&local->mtx);
844 sdata->vif.csa_active = false; 844 sdata->vif.csa_active = false;
845 if (sdata->vif.type == NL80211_IFTYPE_STATION)
846 sdata->u.mgd.csa_waiting_bcn = false;
845 if (sdata->csa_block_tx) { 847 if (sdata->csa_block_tx) {
846 ieee80211_wake_vif_queues(local, sdata, 848 ieee80211_wake_vif_queues(local, sdata,
847 IEEE80211_QUEUE_STOP_REASON_CSA); 849 IEEE80211_QUEUE_STOP_REASON_CSA);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index cb1a8c3bc73f..148253c1bd78 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1001,31 +1001,44 @@ static void ieee80211_chswitch_work(struct work_struct *work)
1001 /* XXX: shouldn't really modify cfg80211-owned data! */ 1001 /* XXX: shouldn't really modify cfg80211-owned data! */
1002 ifmgd->associated->channel = sdata->csa_chandef.chan; 1002 ifmgd->associated->channel = sdata->csa_chandef.chan;
1003 1003
1004 sdata->vif.csa_active = false; 1004 ifmgd->csa_waiting_bcn = true;
1005
1006 ieee80211_sta_reset_beacon_monitor(sdata);
1007 ieee80211_sta_reset_conn_monitor(sdata);
1008
1009out:
1010 mutex_unlock(&local->chanctx_mtx);
1011 mutex_unlock(&local->mtx);
1012 sdata_unlock(sdata);
1013}
1014
1015static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata)
1016{
1017 struct ieee80211_local *local = sdata->local;
1018 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
1019 int ret;
1020
1021 sdata_assert_lock(sdata);
1022
1023 WARN_ON(!sdata->vif.csa_active);
1005 1024
1006 /* XXX: wait for a beacon first? */
1007 if (sdata->csa_block_tx) { 1025 if (sdata->csa_block_tx) {
1008 ieee80211_wake_vif_queues(local, sdata, 1026 ieee80211_wake_vif_queues(local, sdata,
1009 IEEE80211_QUEUE_STOP_REASON_CSA); 1027 IEEE80211_QUEUE_STOP_REASON_CSA);
1010 sdata->csa_block_tx = false; 1028 sdata->csa_block_tx = false;
1011 } 1029 }
1012 1030
1031 sdata->vif.csa_active = false;
1032 ifmgd->csa_waiting_bcn = false;
1033
1013 ret = drv_post_channel_switch(sdata); 1034 ret = drv_post_channel_switch(sdata);
1014 if (ret) { 1035 if (ret) {
1015 sdata_info(sdata, 1036 sdata_info(sdata,
1016 "driver post channel switch failed, disconnecting\n"); 1037 "driver post channel switch failed, disconnecting\n");
1017 ieee80211_queue_work(&local->hw, 1038 ieee80211_queue_work(&local->hw,
1018 &ifmgd->csa_connection_drop_work); 1039 &ifmgd->csa_connection_drop_work);
1019 goto out; 1040 return;
1020 } 1041 }
1021
1022 ieee80211_sta_reset_beacon_monitor(sdata);
1023 ieee80211_sta_reset_conn_monitor(sdata);
1024
1025out:
1026 mutex_unlock(&local->chanctx_mtx);
1027 mutex_unlock(&local->mtx);
1028 sdata_unlock(sdata);
1029} 1042}
1030 1043
1031void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) 1044void 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 ieee80211_vif_release_channel(sdata); 1956 ieee80211_vif_release_channel(sdata);
1944 1957
1945 sdata->vif.csa_active = false; 1958 sdata->vif.csa_active = false;
1959 ifmgd->csa_waiting_bcn = false;
1946 if (sdata->csa_block_tx) { 1960 if (sdata->csa_block_tx) {
1947 ieee80211_wake_vif_queues(local, sdata, 1961 ieee80211_wake_vif_queues(local, sdata,
1948 IEEE80211_QUEUE_STOP_REASON_CSA); 1962 IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -2191,6 +2205,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
2191 true, frame_buf); 2205 true, frame_buf);
2192 mutex_lock(&local->mtx); 2206 mutex_lock(&local->mtx);
2193 sdata->vif.csa_active = false; 2207 sdata->vif.csa_active = false;
2208 ifmgd->csa_waiting_bcn = false;
2194 if (sdata->csa_block_tx) { 2209 if (sdata->csa_block_tx) {
2195 ieee80211_wake_vif_queues(local, sdata, 2210 ieee80211_wake_vif_queues(local, sdata,
2196 IEEE80211_QUEUE_STOP_REASON_CSA); 2211 IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -3215,6 +3230,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
3215 } 3230 }
3216 } 3231 }
3217 3232
3233 if (ifmgd->csa_waiting_bcn)
3234 ieee80211_chswitch_post_beacon(sdata);
3235
3218 if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid) 3236 if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
3219 return; 3237 return;
3220 ifmgd->beacon_crc = ncrc; 3238 ifmgd->beacon_crc = ncrc;
@@ -3687,11 +3705,12 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data)
3687 struct ieee80211_sub_if_data *sdata = 3705 struct ieee80211_sub_if_data *sdata =
3688 (struct ieee80211_sub_if_data *) data; 3706 (struct ieee80211_sub_if_data *) data;
3689 struct ieee80211_local *local = sdata->local; 3707 struct ieee80211_local *local = sdata->local;
3708 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
3690 3709
3691 if (local->quiescing) 3710 if (local->quiescing)
3692 return; 3711 return;
3693 3712
3694 if (sdata->vif.csa_active) 3713 if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
3695 return; 3714 return;
3696 3715
3697 sdata->u.mgd.connection_loss = false; 3716 sdata->u.mgd.connection_loss = false;
@@ -3709,7 +3728,7 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data)
3709 if (local->quiescing) 3728 if (local->quiescing)
3710 return; 3729 return;
3711 3730
3712 if (sdata->vif.csa_active) 3731 if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
3713 return; 3732 return;
3714 3733
3715 ieee80211_queue_work(&local->hw, &ifmgd->monitor_work); 3734 ieee80211_queue_work(&local->hw, &ifmgd->monitor_work);