diff options
author | Luciano Coelho <luciano.coelho@intel.com> | 2014-10-08 02:48:39 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2014-10-09 05:30:09 -0400 |
commit | 0c21e6320f6ea7c4bd2fc0a8c1d8577b372f92d2 (patch) | |
tree | 928688796878b45d17d3138157f947384cec82ad | |
parent | f1d65583bc5bd43ace8abb9d4f4d9e8da407f708 (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.h | 2 | ||||
-rw-r--r-- | net/mac80211/iface.c | 2 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 45 |
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 | |||
1009 | out: | ||
1010 | mutex_unlock(&local->chanctx_mtx); | ||
1011 | mutex_unlock(&local->mtx); | ||
1012 | sdata_unlock(sdata); | ||
1013 | } | ||
1014 | |||
1015 | static 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 | |||
1025 | out: | ||
1026 | mutex_unlock(&local->chanctx_mtx); | ||
1027 | mutex_unlock(&local->mtx); | ||
1028 | sdata_unlock(sdata); | ||
1029 | } | 1042 | } |
1030 | 1043 | ||
1031 | void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) | 1044 | 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 | 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); |