0001
0002
0003
0004
0005
0006 #include <net/mac80211.h>
0007 #include <net/rtnetlink.h>
0008
0009 #include "ieee80211_i.h"
0010 #include "mesh.h"
0011 #include "driver-ops.h"
0012 #include "led.h"
0013
0014 static void ieee80211_sched_scan_cancel(struct ieee80211_local *local)
0015 {
0016 if (ieee80211_request_sched_scan_stop(local))
0017 return;
0018 cfg80211_sched_scan_stopped_locked(local->hw.wiphy, 0);
0019 }
0020
0021 int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
0022 {
0023 struct ieee80211_local *local = hw_to_local(hw);
0024 struct ieee80211_sub_if_data *sdata;
0025 struct sta_info *sta;
0026
0027 if (!local->open_count)
0028 goto suspend;
0029
0030 local->suspending = true;
0031 mb();
0032
0033 ieee80211_scan_cancel(local);
0034
0035 ieee80211_dfs_cac_cancel(local);
0036
0037 ieee80211_roc_purge(local, NULL);
0038
0039 ieee80211_del_virtual_monitor(local);
0040
0041 if (ieee80211_hw_check(hw, AMPDU_AGGREGATION) &&
0042 !(wowlan && wowlan->any)) {
0043 mutex_lock(&local->sta_mtx);
0044 list_for_each_entry(sta, &local->sta_list, list) {
0045 set_sta_flag(sta, WLAN_STA_BLOCK_BA);
0046 ieee80211_sta_tear_down_BA_sessions(
0047 sta, AGG_STOP_LOCAL_REQUEST);
0048 }
0049 mutex_unlock(&local->sta_mtx);
0050 }
0051
0052
0053 if (!(wowlan && wowlan->any))
0054 ieee80211_sched_scan_cancel(local);
0055
0056 ieee80211_stop_queues_by_reason(hw,
0057 IEEE80211_MAX_QUEUE_MAP,
0058 IEEE80211_QUEUE_STOP_REASON_SUSPEND,
0059 false);
0060
0061
0062 synchronize_net();
0063
0064 ieee80211_flush_queues(local, NULL, true);
0065
0066 local->quiescing = true;
0067
0068 mb();
0069
0070 flush_workqueue(local->workqueue);
0071
0072
0073 del_timer_sync(&local->sta_cleanup);
0074
0075
0076
0077
0078
0079 cancel_work_sync(&local->dynamic_ps_enable_work);
0080 del_timer_sync(&local->dynamic_ps_timer);
0081
0082 local->wowlan = wowlan;
0083 if (local->wowlan) {
0084 int err;
0085
0086
0087
0088
0089
0090
0091
0092
0093 list_for_each_entry(sdata, &local->interfaces, list) {
0094 if (!ieee80211_sdata_running(sdata))
0095 continue;
0096 if (sdata->vif.type != NL80211_IFTYPE_STATION)
0097 continue;
0098 ieee80211_mgd_quiesce(sdata);
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108 if (sdata->u.mgd.associated &&
0109 sdata->u.mgd.powersave &&
0110 !(local->hw.conf.flags & IEEE80211_CONF_PS)) {
0111 local->hw.conf.flags |= IEEE80211_CONF_PS;
0112 ieee80211_hw_config(local,
0113 IEEE80211_CONF_CHANGE_PS);
0114 }
0115 }
0116
0117 err = drv_suspend(local, wowlan);
0118 if (err < 0) {
0119 local->quiescing = false;
0120 local->wowlan = false;
0121 if (ieee80211_hw_check(hw, AMPDU_AGGREGATION)) {
0122 mutex_lock(&local->sta_mtx);
0123 list_for_each_entry(sta,
0124 &local->sta_list, list) {
0125 clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
0126 }
0127 mutex_unlock(&local->sta_mtx);
0128 }
0129 ieee80211_wake_queues_by_reason(hw,
0130 IEEE80211_MAX_QUEUE_MAP,
0131 IEEE80211_QUEUE_STOP_REASON_SUSPEND,
0132 false);
0133 return err;
0134 } else if (err > 0) {
0135 WARN_ON(err != 1);
0136
0137
0138
0139 ieee80211_wake_queues_by_reason(hw,
0140 IEEE80211_MAX_QUEUE_MAP,
0141 IEEE80211_QUEUE_STOP_REASON_SUSPEND,
0142 false);
0143 return err;
0144 } else {
0145 goto suspend;
0146 }
0147 }
0148
0149
0150 list_for_each_entry(sdata, &local->interfaces, list) {
0151 if (!ieee80211_sdata_running(sdata))
0152 continue;
0153 switch (sdata->vif.type) {
0154 case NL80211_IFTYPE_AP_VLAN:
0155 case NL80211_IFTYPE_MONITOR:
0156 continue;
0157 case NL80211_IFTYPE_STATION:
0158 ieee80211_mgd_quiesce(sdata);
0159 break;
0160 default:
0161 break;
0162 }
0163
0164 flush_delayed_work(&sdata->dec_tailroom_needed_wk);
0165 drv_remove_interface(local, sdata);
0166 }
0167
0168
0169
0170
0171
0172 WARN_ON(!list_empty(&local->chanctx_list));
0173
0174
0175 ieee80211_stop_device(local);
0176
0177 suspend:
0178 local->suspended = true;
0179
0180 barrier();
0181 local->quiescing = false;
0182 local->suspending = false;
0183
0184 return 0;
0185 }
0186
0187
0188
0189
0190
0191
0192
0193 void ieee80211_report_wowlan_wakeup(struct ieee80211_vif *vif,
0194 struct cfg80211_wowlan_wakeup *wakeup,
0195 gfp_t gfp)
0196 {
0197 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
0198
0199 cfg80211_report_wowlan_wakeup(&sdata->wdev, wakeup, gfp);
0200 }
0201 EXPORT_SYMBOL(ieee80211_report_wowlan_wakeup);