Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include <linux/export.h>
00016 #include <net/mac80211.h>
00017 #include "ieee80211_i.h"
00018 #include "driver-trace.h"
00019
00020
00021
00022
00023
00024 static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
00025 {
00026 struct ieee80211_local *local = sdata->local;
00027 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
00028
00029 local->offchannel_ps_enabled = false;
00030
00031
00032
00033 del_timer_sync(&local->dynamic_ps_timer);
00034 del_timer_sync(&ifmgd->bcn_mon_timer);
00035 del_timer_sync(&ifmgd->conn_mon_timer);
00036
00037 cancel_work_sync(&local->dynamic_ps_enable_work);
00038
00039 if (local->hw.conf.flags & IEEE80211_CONF_PS) {
00040 local->offchannel_ps_enabled = true;
00041 local->hw.conf.flags &= ~IEEE80211_CONF_PS;
00042 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
00043 }
00044
00045 if (!(local->offchannel_ps_enabled) ||
00046 !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 ieee80211_send_nullfunc(local, sdata, 1);
00058 }
00059
00060
00061 static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
00062 {
00063 struct ieee80211_local *local = sdata->local;
00064
00065 if (!local->ps_sdata)
00066 ieee80211_send_nullfunc(local, sdata, 0);
00067 else if (local->offchannel_ps_enabled) {
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081 local->hw.conf.flags |= IEEE80211_CONF_PS;
00082 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
00083 } else if (local->hw.conf.dynamic_ps_timeout > 0) {
00084
00085
00086
00087
00088
00089
00090 ieee80211_send_nullfunc(local, sdata, 0);
00091 mod_timer(&local->dynamic_ps_timer, jiffies +
00092 msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
00093 }
00094
00095 ieee80211_sta_reset_beacon_monitor(sdata);
00096 ieee80211_sta_reset_conn_monitor(sdata);
00097 }
00098
00099 void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local)
00100 {
00101 struct ieee80211_sub_if_data *sdata;
00102
00103 mutex_lock(&local->iflist_mtx);
00104 list_for_each_entry(sdata, &local->interfaces, list) {
00105 if (!ieee80211_sdata_running(sdata))
00106 continue;
00107
00108
00109 if (sdata->vif.type == NL80211_IFTYPE_AP ||
00110 sdata->vif.type == NL80211_IFTYPE_ADHOC ||
00111 sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
00112 ieee80211_bss_info_change_notify(
00113 sdata, BSS_CHANGED_BEACON_ENABLED);
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 if (sdata->vif.type != NL80211_IFTYPE_STATION &&
00124 sdata->vif.type != NL80211_IFTYPE_MONITOR) {
00125 set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
00126 netif_tx_stop_all_queues(sdata->dev);
00127 }
00128 }
00129 mutex_unlock(&local->iflist_mtx);
00130 }
00131
00132 void ieee80211_offchannel_stop_station(struct ieee80211_local *local)
00133 {
00134 struct ieee80211_sub_if_data *sdata;
00135
00136
00137
00138
00139 mutex_lock(&local->iflist_mtx);
00140 list_for_each_entry(sdata, &local->interfaces, list) {
00141 if (!ieee80211_sdata_running(sdata))
00142 continue;
00143
00144 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
00145 set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
00146 netif_tx_stop_all_queues(sdata->dev);
00147 if (sdata->u.mgd.associated)
00148 ieee80211_offchannel_ps_enable(sdata);
00149 }
00150 }
00151 mutex_unlock(&local->iflist_mtx);
00152 }
00153
00154 void ieee80211_offchannel_return(struct ieee80211_local *local,
00155 bool enable_beaconing)
00156 {
00157 struct ieee80211_sub_if_data *sdata;
00158
00159 mutex_lock(&local->iflist_mtx);
00160 list_for_each_entry(sdata, &local->interfaces, list) {
00161 if (!ieee80211_sdata_running(sdata))
00162 continue;
00163
00164
00165 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
00166 if (sdata->u.mgd.associated)
00167 ieee80211_offchannel_ps_disable(sdata);
00168 }
00169
00170 if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
00171 clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182 netif_tx_wake_all_queues(sdata->dev);
00183 }
00184
00185
00186 if (enable_beaconing &&
00187 (sdata->vif.type == NL80211_IFTYPE_AP ||
00188 sdata->vif.type == NL80211_IFTYPE_ADHOC ||
00189 sdata->vif.type == NL80211_IFTYPE_MESH_POINT))
00190 ieee80211_bss_info_change_notify(
00191 sdata, BSS_CHANGED_BEACON_ENABLED);
00192 }
00193 mutex_unlock(&local->iflist_mtx);
00194 }
00195
00196 static void ieee80211_hw_roc_start(struct work_struct *work)
00197 {
00198 struct ieee80211_local *local =
00199 container_of(work, struct ieee80211_local, hw_roc_start);
00200 struct ieee80211_sub_if_data *sdata;
00201
00202 mutex_lock(&local->mtx);
00203
00204 if (!local->hw_roc_channel) {
00205 mutex_unlock(&local->mtx);
00206 return;
00207 }
00208
00209 ieee80211_recalc_idle(local);
00210
00211 if (local->hw_roc_skb) {
00212 sdata = IEEE80211_DEV_TO_SUB_IF(local->hw_roc_dev);
00213 ieee80211_tx_skb(sdata, local->hw_roc_skb);
00214 local->hw_roc_skb = NULL;
00215 } else {
00216 cfg80211_ready_on_channel(local->hw_roc_dev,
00217 local->hw_roc_cookie,
00218 local->hw_roc_channel,
00219 local->hw_roc_channel_type,
00220 local->hw_roc_duration,
00221 GFP_KERNEL);
00222 }
00223
00224 mutex_unlock(&local->mtx);
00225 }
00226
00227 void ieee80211_ready_on_channel(struct ieee80211_hw *hw)
00228 {
00229 struct ieee80211_local *local = hw_to_local(hw);
00230
00231 trace_api_ready_on_channel(local);
00232
00233 ieee80211_queue_work(hw, &local->hw_roc_start);
00234 }
00235 EXPORT_SYMBOL_GPL(ieee80211_ready_on_channel);
00236
00237 static void ieee80211_hw_roc_done(struct work_struct *work)
00238 {
00239 struct ieee80211_local *local =
00240 container_of(work, struct ieee80211_local, hw_roc_done);
00241
00242 mutex_lock(&local->mtx);
00243
00244 if (!local->hw_roc_channel) {
00245 mutex_unlock(&local->mtx);
00246 return;
00247 }
00248
00249
00250 if (local->hw_roc_skb) {
00251 u64 cookie;
00252
00253 cookie = local->hw_roc_cookie ^ 2;
00254
00255 cfg80211_mgmt_tx_status(local->hw_roc_dev, cookie,
00256 local->hw_roc_skb->data,
00257 local->hw_roc_skb->len, false,
00258 GFP_KERNEL);
00259
00260 kfree_skb(local->hw_roc_skb);
00261 local->hw_roc_skb = NULL;
00262 local->hw_roc_skb_for_status = NULL;
00263 }
00264
00265 if (!local->hw_roc_for_tx)
00266 cfg80211_remain_on_channel_expired(local->hw_roc_dev,
00267 local->hw_roc_cookie,
00268 local->hw_roc_channel,
00269 local->hw_roc_channel_type,
00270 GFP_KERNEL);
00271
00272 local->hw_roc_channel = NULL;
00273 local->hw_roc_cookie = 0;
00274
00275 ieee80211_recalc_idle(local);
00276
00277 mutex_unlock(&local->mtx);
00278 }
00279
00280 void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw)
00281 {
00282 struct ieee80211_local *local = hw_to_local(hw);
00283
00284 trace_api_remain_on_channel_expired(local);
00285
00286 ieee80211_queue_work(hw, &local->hw_roc_done);
00287 }
00288 EXPORT_SYMBOL_GPL(ieee80211_remain_on_channel_expired);
00289
00290 void ieee80211_hw_roc_setup(struct ieee80211_local *local)
00291 {
00292 INIT_WORK(&local->hw_roc_start, ieee80211_hw_roc_start);
00293 INIT_WORK(&local->hw_roc_done, ieee80211_hw_roc_done);
00294 }