diff options
Diffstat (limited to 'net/mac80211/offchannel.c')
-rw-r--r-- | net/mac80211/offchannel.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index 4b564091e51d..b4e52676f3fb 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
@@ -14,6 +14,7 @@ | |||
14 | */ | 14 | */ |
15 | #include <net/mac80211.h> | 15 | #include <net/mac80211.h> |
16 | #include "ieee80211_i.h" | 16 | #include "ieee80211_i.h" |
17 | #include "driver-trace.h" | ||
17 | 18 | ||
18 | /* | 19 | /* |
19 | * inform AP that we will go to sleep so that it will buffer the frames | 20 | * inform AP that we will go to sleep so that it will buffer the frames |
@@ -190,3 +191,87 @@ void ieee80211_offchannel_return(struct ieee80211_local *local, | |||
190 | } | 191 | } |
191 | mutex_unlock(&local->iflist_mtx); | 192 | mutex_unlock(&local->iflist_mtx); |
192 | } | 193 | } |
194 | |||
195 | static void ieee80211_hw_roc_start(struct work_struct *work) | ||
196 | { | ||
197 | struct ieee80211_local *local = | ||
198 | container_of(work, struct ieee80211_local, hw_roc_start); | ||
199 | struct ieee80211_sub_if_data *sdata; | ||
200 | |||
201 | mutex_lock(&local->mtx); | ||
202 | |||
203 | if (!local->hw_roc_channel) { | ||
204 | mutex_unlock(&local->mtx); | ||
205 | return; | ||
206 | } | ||
207 | |||
208 | ieee80211_recalc_idle(local); | ||
209 | |||
210 | if (local->hw_roc_skb) { | ||
211 | sdata = IEEE80211_DEV_TO_SUB_IF(local->hw_roc_dev); | ||
212 | ieee80211_tx_skb(sdata, local->hw_roc_skb); | ||
213 | local->hw_roc_skb = NULL; | ||
214 | } else { | ||
215 | cfg80211_ready_on_channel(local->hw_roc_dev, | ||
216 | local->hw_roc_cookie, | ||
217 | local->hw_roc_channel, | ||
218 | local->hw_roc_channel_type, | ||
219 | local->hw_roc_duration, | ||
220 | GFP_KERNEL); | ||
221 | } | ||
222 | |||
223 | mutex_unlock(&local->mtx); | ||
224 | } | ||
225 | |||
226 | void ieee80211_ready_on_channel(struct ieee80211_hw *hw) | ||
227 | { | ||
228 | struct ieee80211_local *local = hw_to_local(hw); | ||
229 | |||
230 | trace_api_ready_on_channel(local); | ||
231 | |||
232 | ieee80211_queue_work(hw, &local->hw_roc_start); | ||
233 | } | ||
234 | EXPORT_SYMBOL_GPL(ieee80211_ready_on_channel); | ||
235 | |||
236 | static void ieee80211_hw_roc_done(struct work_struct *work) | ||
237 | { | ||
238 | struct ieee80211_local *local = | ||
239 | container_of(work, struct ieee80211_local, hw_roc_done); | ||
240 | |||
241 | mutex_lock(&local->mtx); | ||
242 | |||
243 | if (!local->hw_roc_channel) { | ||
244 | mutex_unlock(&local->mtx); | ||
245 | return; | ||
246 | } | ||
247 | |||
248 | if (!local->hw_roc_for_tx) | ||
249 | cfg80211_remain_on_channel_expired(local->hw_roc_dev, | ||
250 | local->hw_roc_cookie, | ||
251 | local->hw_roc_channel, | ||
252 | local->hw_roc_channel_type, | ||
253 | GFP_KERNEL); | ||
254 | |||
255 | local->hw_roc_channel = NULL; | ||
256 | local->hw_roc_cookie = 0; | ||
257 | |||
258 | ieee80211_recalc_idle(local); | ||
259 | |||
260 | mutex_unlock(&local->mtx); | ||
261 | } | ||
262 | |||
263 | void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw) | ||
264 | { | ||
265 | struct ieee80211_local *local = hw_to_local(hw); | ||
266 | |||
267 | trace_api_remain_on_channel_expired(local); | ||
268 | |||
269 | ieee80211_queue_work(hw, &local->hw_roc_done); | ||
270 | } | ||
271 | EXPORT_SYMBOL_GPL(ieee80211_remain_on_channel_expired); | ||
272 | |||
273 | void ieee80211_hw_roc_setup(struct ieee80211_local *local) | ||
274 | { | ||
275 | INIT_WORK(&local->hw_roc_start, ieee80211_hw_roc_start); | ||
276 | INIT_WORK(&local->hw_roc_done, ieee80211_hw_roc_done); | ||
277 | } | ||