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 sdata = sta->sdata;
00102 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
00103 sdata = container_of(sdata->bss,
00104 struct ieee80211_sub_if_data,
00105 u.ap);
00106
00107 drv_sta_remove(local, sdata, &sta->sta);
00108 }
00109
00110 mesh_plink_quiesce(sta);
00111 }
00112 mutex_unlock(&local->sta_mtx);
00113
00114
00115 list_for_each_entry(sdata, &local->interfaces, list) {
00116 cancel_work_sync(&sdata->work);
00117
00118 if (!ieee80211_quiesce(sdata))
00119 continue;
00120
00121 if (!ieee80211_sdata_running(sdata))
00122 continue;
00123
00124
00125 ieee80211_bss_info_change_notify(sdata,
00126 BSS_CHANGED_BEACON_ENABLED);
00127
00128 drv_remove_interface(local, &sdata->vif);
00129 }
00130
00131
00132 if (local->open_count)
00133 ieee80211_stop_device(local);
00134
00135 suspend:
00136 local->suspended = true;
00137
00138 barrier();
00139 local->quiescing = false;
00140
00141 return 0;
00142 }
00143
00144
00145
00146
00147
00148