diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-08-01 16:32:45 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2012-09-06 11:05:24 -0400 |
commit | 882a7c69d3c605bfacf32e19033447dc70204d45 (patch) | |
tree | 0f0059731dda5e796fbeee047e886218c534fa18 /net | |
parent | 30dd3edf97abda301150c8cf26fed21e53e3a9ce (diff) |
mac80211: disconnect if channel switch fails
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>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/ieee80211_i.h | 1 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 55 |
2 files changed, 38 insertions, 18 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 0a983fbd743d..e2ab03c773e3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -411,6 +411,7 @@ struct ieee80211_if_managed { | |||
411 | struct work_struct monitor_work; | 411 | struct work_struct monitor_work; |
412 | struct work_struct chswitch_work; | 412 | struct work_struct chswitch_work; |
413 | struct work_struct beacon_connection_loss_work; | 413 | struct work_struct beacon_connection_loss_work; |
414 | struct work_struct csa_connection_drop_work; | ||
414 | 415 | ||
415 | unsigned long beacon_timeout; | 416 | unsigned long beacon_timeout; |
416 | unsigned long probe_timeout; | 417 | unsigned long probe_timeout; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 5d77650d4363..6e374cb04af6 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -730,16 +730,13 @@ void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) | |||
730 | 730 | ||
731 | trace_api_chswitch_done(sdata, success); | 731 | trace_api_chswitch_done(sdata, success); |
732 | if (!success) { | 732 | if (!success) { |
733 | /* | 733 | sdata_info(sdata, |
734 | * If the channel switch was not successful, stay | 734 | "driver channel switch failed, disconnecting\n"); |
735 | * around on the old channel. We currently lack | 735 | ieee80211_queue_work(&sdata->local->hw, |
736 | * good handling of this situation, possibly we | 736 | &ifmgd->csa_connection_drop_work); |
737 | * should just drop the association. | 737 | } else { |
738 | */ | 738 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); |
739 | sdata->local->csa_channel = sdata->local->oper_channel; | ||
740 | } | 739 | } |
741 | |||
742 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); | ||
743 | } | 740 | } |
744 | EXPORT_SYMBOL(ieee80211_chswitch_done); | 741 | EXPORT_SYMBOL(ieee80211_chswitch_done); |
745 | 742 | ||
@@ -784,8 +781,14 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
784 | return; | 781 | return; |
785 | 782 | ||
786 | new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); | 783 | new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); |
787 | if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) | 784 | if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) { |
785 | sdata_info(sdata, | ||
786 | "AP %pM switches to unsupported channel (%d MHz), disconnecting\n", | ||
787 | ifmgd->associated->bssid, new_freq); | ||
788 | ieee80211_queue_work(&sdata->local->hw, | ||
789 | &ifmgd->csa_connection_drop_work); | ||
788 | return; | 790 | return; |
791 | } | ||
789 | 792 | ||
790 | sdata->local->csa_channel = new_ch; | 793 | sdata->local->csa_channel = new_ch; |
791 | 794 | ||
@@ -1692,7 +1695,8 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | |||
1692 | } | 1695 | } |
1693 | EXPORT_SYMBOL(ieee80211_ap_probereq_get); | 1696 | EXPORT_SYMBOL(ieee80211_ap_probereq_get); |
1694 | 1697 | ||
1695 | static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | 1698 | static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata, |
1699 | bool transmit_frame) | ||
1696 | { | 1700 | { |
1697 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1701 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1698 | struct ieee80211_local *local = sdata->local; | 1702 | struct ieee80211_local *local = sdata->local; |
@@ -1704,12 +1708,10 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | |||
1704 | return; | 1708 | return; |
1705 | } | 1709 | } |
1706 | 1710 | ||
1707 | sdata_info(sdata, "Connection to AP %pM lost\n", | ||
1708 | ifmgd->associated->bssid); | ||
1709 | |||
1710 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, | 1711 | ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, |
1711 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | 1712 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, |
1712 | false, frame_buf); | 1713 | transmit_frame, frame_buf); |
1714 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; | ||
1713 | mutex_unlock(&ifmgd->mtx); | 1715 | mutex_unlock(&ifmgd->mtx); |
1714 | 1716 | ||
1715 | /* | 1717 | /* |
@@ -1739,10 +1741,24 @@ static void ieee80211_beacon_connection_loss_work(struct work_struct *work) | |||
1739 | rcu_read_unlock(); | 1741 | rcu_read_unlock(); |
1740 | } | 1742 | } |
1741 | 1743 | ||
1742 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | 1744 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) { |
1743 | __ieee80211_connection_loss(sdata); | 1745 | sdata_info(sdata, "Connection to AP %pM lost\n", |
1744 | else | 1746 | ifmgd->bssid); |
1747 | __ieee80211_disconnect(sdata, false); | ||
1748 | } else { | ||
1745 | ieee80211_mgd_probe_ap(sdata, true); | 1749 | ieee80211_mgd_probe_ap(sdata, true); |
1750 | } | ||
1751 | } | ||
1752 | |||
1753 | static void ieee80211_csa_connection_drop_work(struct work_struct *work) | ||
1754 | { | ||
1755 | struct ieee80211_sub_if_data *sdata = | ||
1756 | container_of(work, struct ieee80211_sub_if_data, | ||
1757 | u.mgd.csa_connection_drop_work); | ||
1758 | |||
1759 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | ||
1760 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
1761 | __ieee80211_disconnect(sdata, true); | ||
1746 | } | 1762 | } |
1747 | 1763 | ||
1748 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) | 1764 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) |
@@ -2929,6 +2945,7 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata) | |||
2929 | 2945 | ||
2930 | cancel_work_sync(&ifmgd->monitor_work); | 2946 | cancel_work_sync(&ifmgd->monitor_work); |
2931 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); | 2947 | cancel_work_sync(&ifmgd->beacon_connection_loss_work); |
2948 | cancel_work_sync(&ifmgd->csa_connection_drop_work); | ||
2932 | if (del_timer_sync(&ifmgd->timer)) | 2949 | if (del_timer_sync(&ifmgd->timer)) |
2933 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); | 2950 | set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running); |
2934 | 2951 | ||
@@ -2985,6 +3002,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
2985 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); | 3002 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); |
2986 | INIT_WORK(&ifmgd->beacon_connection_loss_work, | 3003 | INIT_WORK(&ifmgd->beacon_connection_loss_work, |
2987 | ieee80211_beacon_connection_loss_work); | 3004 | ieee80211_beacon_connection_loss_work); |
3005 | INIT_WORK(&ifmgd->csa_connection_drop_work, | ||
3006 | ieee80211_csa_connection_drop_work); | ||
2988 | INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work); | 3007 | INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work); |
2989 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, | 3008 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, |
2990 | (unsigned long) sdata); | 3009 | (unsigned long) sdata); |