aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-08-01 16:32:45 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-09-06 11:05:24 -0400
commit882a7c69d3c605bfacf32e19033447dc70204d45 (patch)
tree0f0059731dda5e796fbeee047e886218c534fa18 /net
parent30dd3edf97abda301150c8cf26fed21e53e3a9ce (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.h1
-rw-r--r--net/mac80211/mlme.c55
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}
744EXPORT_SYMBOL(ieee80211_chswitch_done); 741EXPORT_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}
1693EXPORT_SYMBOL(ieee80211_ap_probereq_get); 1696EXPORT_SYMBOL(ieee80211_ap_probereq_get);
1694 1697
1695static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) 1698static 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
1753static 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
1748void ieee80211_beacon_loss(struct ieee80211_vif *vif) 1764void 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);