Go to the documentation of this file.00001 #include <net/mac80211.h>
00002 #include <net/rtnetlink.h>
00003
00004 #include "ieee80211_i.h"
00005 #include "mesh.h"
00006 #include "driver-ops.h"
00007 #include "led.h"
00008
00009
00010 static bool ieee80211_quiesce(struct ieee80211_sub_if_data *sdata)
00011 {
00012 switch (sdata->vif.type) {
00013 case NL80211_IFTYPE_STATION:
00014 ieee80211_sta_quiesce(sdata);
00015 return true;
00016 case NL80211_IFTYPE_ADHOC:
00017 ieee80211_ibss_quiesce(sdata);
00018 return true;
00019 case NL80211_IFTYPE_MESH_POINT:
00020 ieee80211_mesh_quiesce(sdata);
00021 return true;
00022 case NL80211_IFTYPE_AP_VLAN:
00023 case NL80211_IFTYPE_MONITOR:
00024
00025 return false;
00026 default:
00027 return true;
00028 }
00029 }
00030
00031 int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
00032 {
00033 struct ieee80211_local *local = hw_to_local(hw);
00034 struct ieee80211_sub_if_data *sdata;
00035 struct sta_info *sta;
00036
00037 if (!local->open_count)
00038 goto suspend;
00039
00040 ieee80211_scan_cancel(local);
00041
00042 if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
00043 mutex_lock(&local->sta_mtx);
00044 list_for_each_entry(sta, &local->sta_list, list) {
00045 set_sta_flag(sta, WLAN_STA_BLOCK_BA);
00046 ieee80211_sta_tear_down_BA_sessions(sta, true);
00047 }
00048 mutex_unlock(&local->sta_mtx);
00049 }
00050
00051 ieee80211_stop_queues_by_reason(hw,
00052 IEEE80211_QUEUE_STOP_REASON_SUSPEND);
00053
00054
00055 synchronize_net();
00056
00057 drv_flush(local, false);
00058
00059 local->quiescing = true;
00060
00061 mb();
00062
00063 flush_workqueue(local->workqueue);
00064
00065
00066 del_timer_sync(&local->sta_cleanup);
00067
00068
00069
00070
00071
00072 cancel_work_sync(&local->dynamic_ps_enable_work);
00073 del_timer_sync(&local->dynamic_ps_timer);
00074
00075 local->wowlan = wowlan && local->open_count;
00076 if (local->wowlan) {
00077 int err = drv_suspend(local, wowlan);
00078 if (err < 0) {
00079 local->quiescing = false;
00080 return err;
00081 } else if (err > 0) {
00082 WARN_ON(err != 1);
00083 local->wowlan = false;
00084 } else {
00085 list_for_each_entry(sdata, &local->interfaces, list) {
00086 cancel_work_sync(&sdata->work);
00087 ieee80211_quiesce(sdata);
00088 }
00089 goto suspend;
00090 }
00091 }
00092
00093
00094 list_for_each_entry(sdata, &local->interfaces, list)
00095 ieee80211_disable_keys(sdata);
00096
00097
00098 mutex_lock(&local->sta_mtx);
00099 list_for_each_entry(sta, &local->sta_list, list) {
00100 if (sta->uploaded) {
00101 enum ieee80211_sta_state state;
00102
00103 state = sta->sta_state;
00104 for (; state > IEEE80211_STA_NOTEXIST; state--)
00105 WARN_ON(drv_sta_state(local, sta->sdata, sta,
00106 state, state - 1));
00107 }
00108
00109 mesh_plink_quiesce(sta);
00110 }
00111 mutex_unlock(&local->sta_mtx);
00112
00113
00114 list_for_each_entry(sdata, &local->interfaces, list) {
00115 cancel_work_sync(&sdata->work);
00116
00117 if (!ieee80211_quiesce(sdata))
00118 continue;
00119
00120 if (!ieee80211_sdata_running(sdata))
00121 continue;
00122
00123
00124 ieee80211_bss_info_change_notify(sdata,
00125 BSS_CHANGED_BEACON_ENABLED);
00126
00127 drv_remove_interface(local, sdata);
00128 }
00129
00130 sdata = rtnl_dereference(local->monitor_sdata);
00131 if (sdata)
00132 drv_remove_interface(local, sdata);
00133
00134
00135 if (local->open_count)
00136 ieee80211_stop_device(local);
00137
00138 suspend:
00139 local->suspended = true;
00140
00141 barrier();
00142 local->quiescing = false;
00143
00144 return 0;
00145 }
00146
00147
00148
00149
00150
00151