]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - net/mac80211/offchannel.c
mac80211: cleanup offchannel_ps_enable argument
[karo-tx-linux.git] / net / mac80211 / offchannel.c
1 /*
2  * Off-channel operation helpers
3  *
4  * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
5  * Copyright 2004, Instant802 Networks, Inc.
6  * Copyright 2005, Devicescape Software, Inc.
7  * Copyright 2006-2007  Jiri Benc <jbenc@suse.cz>
8  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
9  * Copyright 2009       Johannes Berg <johannes@sipsolutions.net>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License version 2 as
13  * published by the Free Software Foundation.
14  */
15 #include <linux/export.h>
16 #include <net/mac80211.h>
17 #include "ieee80211_i.h"
18 #include "driver-trace.h"
19 #include "driver-ops.h"
20
21 /*
22  * Tell our hardware to disable PS.
23  * Optionally inform AP that we will go to sleep so that it will buffer
24  * the frames while we are doing off-channel work.  This is optional
25  * because we *may* be doing work on-operating channel, and want our
26  * hardware unconditionally awake, but still let the AP send us normal frames.
27  */
28 static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)
29 {
30         struct ieee80211_local *local = sdata->local;
31         struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
32
33         local->offchannel_ps_enabled = false;
34
35         /* FIXME: what to do when local->pspolling is true? */
36
37         del_timer_sync(&local->dynamic_ps_timer);
38         del_timer_sync(&ifmgd->bcn_mon_timer);
39         del_timer_sync(&ifmgd->conn_mon_timer);
40
41         cancel_work_sync(&local->dynamic_ps_enable_work);
42
43         if (local->hw.conf.flags & IEEE80211_CONF_PS) {
44                 local->offchannel_ps_enabled = true;
45                 local->hw.conf.flags &= ~IEEE80211_CONF_PS;
46                 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
47         }
48
49         if (!local->offchannel_ps_enabled ||
50             !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
51                 /*
52                  * If power save was enabled, no need to send a nullfunc
53                  * frame because AP knows that we are sleeping. But if the
54                  * hardware is creating the nullfunc frame for power save
55                  * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not
56                  * enabled) and power save was enabled, the firmware just
57                  * sent a null frame with power save disabled. So we need
58                  * to send a new nullfunc frame to inform the AP that we
59                  * are again sleeping.
60                  */
61                 ieee80211_send_nullfunc(local, sdata, 1);
62 }
63
64 /* inform AP that we are awake again, unless power save is enabled */
65 static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
66 {
67         struct ieee80211_local *local = sdata->local;
68
69         if (!local->ps_sdata)
70                 ieee80211_send_nullfunc(local, sdata, 0);
71         else if (local->offchannel_ps_enabled) {
72                 /*
73                  * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware
74                  * will send a nullfunc frame with the powersave bit set
75                  * even though the AP already knows that we are sleeping.
76                  * This could be avoided by sending a null frame with power
77                  * save bit disabled before enabling the power save, but
78                  * this doesn't gain anything.
79                  *
80                  * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need
81                  * to send a nullfunc frame because AP already knows that
82                  * we are sleeping, let's just enable power save mode in
83                  * hardware.
84                  */
85                 /* TODO:  Only set hardware if CONF_PS changed?
86                  * TODO:  Should we set offchannel_ps_enabled to false?
87                  */
88                 local->hw.conf.flags |= IEEE80211_CONF_PS;
89                 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
90         } else if (local->hw.conf.dynamic_ps_timeout > 0) {
91                 /*
92                  * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer
93                  * had been running before leaving the operating channel,
94                  * restart the timer now and send a nullfunc frame to inform
95                  * the AP that we are awake.
96                  */
97                 ieee80211_send_nullfunc(local, sdata, 0);
98                 mod_timer(&local->dynamic_ps_timer, jiffies +
99                           msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
100         }
101
102         ieee80211_sta_reset_beacon_monitor(sdata);
103         ieee80211_sta_reset_conn_monitor(sdata);
104 }
105
106 void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
107                                     bool offchannel_ps_enable)
108 {
109         struct ieee80211_sub_if_data *sdata;
110
111         /*
112          * notify the AP about us leaving the channel and stop all
113          * STA interfaces.
114          */
115         mutex_lock(&local->iflist_mtx);
116         list_for_each_entry(sdata, &local->interfaces, list) {
117                 if (!ieee80211_sdata_running(sdata))
118                         continue;
119
120                 if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
121                         set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
122
123                 /* Check to see if we should disable beaconing. */
124                 if (sdata->vif.type == NL80211_IFTYPE_AP ||
125                     sdata->vif.type == NL80211_IFTYPE_ADHOC ||
126                     sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
127                         ieee80211_bss_info_change_notify(
128                                 sdata, BSS_CHANGED_BEACON_ENABLED);
129
130                 if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
131                         netif_tx_stop_all_queues(sdata->dev);
132                         if (offchannel_ps_enable &&
133                             (sdata->vif.type == NL80211_IFTYPE_STATION) &&
134                             sdata->u.mgd.associated)
135                                 ieee80211_offchannel_ps_enable(sdata);
136                 }
137         }
138         mutex_unlock(&local->iflist_mtx);
139 }
140
141 void ieee80211_offchannel_return(struct ieee80211_local *local,
142                                  bool offchannel_ps_disable)
143 {
144         struct ieee80211_sub_if_data *sdata;
145
146         mutex_lock(&local->iflist_mtx);
147         list_for_each_entry(sdata, &local->interfaces, list) {
148                 if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
149                         clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
150
151                 if (!ieee80211_sdata_running(sdata))
152                         continue;
153
154                 /* Tell AP we're back */
155                 if (offchannel_ps_disable &&
156                     sdata->vif.type == NL80211_IFTYPE_STATION) {
157                         if (sdata->u.mgd.associated)
158                                 ieee80211_offchannel_ps_disable(sdata);
159                 }
160
161                 if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
162                         /*
163                          * This may wake up queues even though the driver
164                          * currently has them stopped. This is not very
165                          * likely, since the driver won't have gotten any
166                          * (or hardly any) new packets while we weren't
167                          * on the right channel, and even if it happens
168                          * it will at most lead to queueing up one more
169                          * packet per queue in mac80211 rather than on
170                          * the interface qdisc.
171                          */
172                         netif_tx_wake_all_queues(sdata->dev);
173                 }
174
175                 if (sdata->vif.type == NL80211_IFTYPE_AP ||
176                     sdata->vif.type == NL80211_IFTYPE_ADHOC ||
177                     sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
178                         ieee80211_bss_info_change_notify(
179                                 sdata, BSS_CHANGED_BEACON_ENABLED);
180         }
181         mutex_unlock(&local->iflist_mtx);
182 }
183
184 void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc)
185 {
186         if (roc->notified)
187                 return;
188
189         if (roc->mgmt_tx_cookie) {
190                 if (!WARN_ON(!roc->frame)) {
191                         ieee80211_tx_skb(roc->sdata, roc->frame);
192                         roc->frame = NULL;
193                 }
194         } else {
195                 cfg80211_ready_on_channel(roc->sdata->dev, (unsigned long)roc,
196                                           roc->chan, roc->chan_type,
197                                           roc->req_duration, GFP_KERNEL);
198         }
199
200         roc->notified = true;
201 }
202
203 static void ieee80211_hw_roc_start(struct work_struct *work)
204 {
205         struct ieee80211_local *local =
206                 container_of(work, struct ieee80211_local, hw_roc_start);
207         struct ieee80211_roc_work *roc, *dep, *tmp;
208
209         mutex_lock(&local->mtx);
210
211         if (list_empty(&local->roc_list))
212                 goto out_unlock;
213
214         roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work,
215                                list);
216
217         if (!roc->started)
218                 goto out_unlock;
219
220         roc->hw_begun = true;
221         roc->hw_start_time = local->hw_roc_start_time;
222
223         ieee80211_handle_roc_started(roc);
224         list_for_each_entry_safe(dep, tmp, &roc->dependents, list) {
225                 ieee80211_handle_roc_started(dep);
226
227                 if (dep->duration > roc->duration) {
228                         u32 dur = dep->duration;
229                         dep->duration = dur - roc->duration;
230                         roc->duration = dur;
231                         list_del(&dep->list);
232                         list_add(&dep->list, &roc->list);
233                 }
234         }
235  out_unlock:
236         mutex_unlock(&local->mtx);
237 }
238
239 void ieee80211_ready_on_channel(struct ieee80211_hw *hw)
240 {
241         struct ieee80211_local *local = hw_to_local(hw);
242
243         local->hw_roc_start_time = jiffies;
244
245         trace_api_ready_on_channel(local);
246
247         ieee80211_queue_work(hw, &local->hw_roc_start);
248 }
249 EXPORT_SYMBOL_GPL(ieee80211_ready_on_channel);
250
251 void ieee80211_start_next_roc(struct ieee80211_local *local)
252 {
253         struct ieee80211_roc_work *roc;
254
255         lockdep_assert_held(&local->mtx);
256
257         if (list_empty(&local->roc_list)) {
258                 ieee80211_run_deferred_scan(local);
259                 return;
260         }
261
262         roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work,
263                                list);
264
265         if (local->ops->remain_on_channel) {
266                 int ret, duration = roc->duration;
267
268                 /* XXX: duplicated, see ieee80211_start_roc_work() */
269                 if (!duration)
270                         duration = 10;
271
272                 ret = drv_remain_on_channel(local, roc->chan,
273                                             roc->chan_type,
274                                             duration);
275
276                 roc->started = true;
277
278                 if (ret) {
279                         wiphy_warn(local->hw.wiphy,
280                                    "failed to start next HW ROC (%d)\n", ret);
281                         /*
282                          * queue the work struct again to avoid recursion
283                          * when multiple failures occur
284                          */
285                         ieee80211_remain_on_channel_expired(&local->hw);
286                 }
287         } else {
288                 /* delay it a bit */
289                 ieee80211_queue_delayed_work(&local->hw, &roc->work,
290                                              round_jiffies_relative(HZ/2));
291         }
292 }
293
294 void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
295 {
296         struct ieee80211_roc_work *dep, *tmp;
297
298         /* was never transmitted */
299         if (roc->frame) {
300                 cfg80211_mgmt_tx_status(roc->sdata->dev,
301                                         (unsigned long)roc->frame,
302                                         roc->frame->data, roc->frame->len,
303                                         false, GFP_KERNEL);
304                 kfree_skb(roc->frame);
305         }
306
307         if (!roc->mgmt_tx_cookie)
308                 cfg80211_remain_on_channel_expired(roc->sdata->dev,
309                                                    (unsigned long)roc,
310                                                    roc->chan, roc->chan_type,
311                                                    GFP_KERNEL);
312
313         list_for_each_entry_safe(dep, tmp, &roc->dependents, list)
314                 ieee80211_roc_notify_destroy(dep);
315
316         kfree(roc);
317 }
318
319 void ieee80211_sw_roc_work(struct work_struct *work)
320 {
321         struct ieee80211_roc_work *roc =
322                 container_of(work, struct ieee80211_roc_work, work.work);
323         struct ieee80211_sub_if_data *sdata = roc->sdata;
324         struct ieee80211_local *local = sdata->local;
325
326         mutex_lock(&local->mtx);
327
328         if (roc->abort)
329                 goto finish;
330
331         if (WARN_ON(list_empty(&local->roc_list)))
332                 goto out_unlock;
333
334         if (WARN_ON(roc != list_first_entry(&local->roc_list,
335                                             struct ieee80211_roc_work,
336                                             list)))
337                 goto out_unlock;
338
339         if (!roc->started) {
340                 struct ieee80211_roc_work *dep;
341
342                 /* start this ROC */
343
344                 /* switch channel etc */
345                 ieee80211_recalc_idle(local);
346
347                 local->tmp_channel = roc->chan;
348                 local->tmp_channel_type = roc->chan_type;
349                 ieee80211_hw_config(local, 0);
350
351                 /* tell userspace or send frame */
352                 ieee80211_handle_roc_started(roc);
353                 list_for_each_entry(dep, &roc->dependents, list)
354                         ieee80211_handle_roc_started(dep);
355
356                 /* if it was pure TX, just finish right away */
357                 if (!roc->duration)
358                         goto finish;
359
360                 roc->started = true;
361                 ieee80211_queue_delayed_work(&local->hw, &roc->work,
362                                              msecs_to_jiffies(roc->duration));
363         } else {
364                 /* finish this ROC */
365  finish:
366                 list_del(&roc->list);
367                 ieee80211_roc_notify_destroy(roc);
368
369                 if (roc->started) {
370                         drv_flush(local, false);
371
372                         local->tmp_channel = NULL;
373                         ieee80211_hw_config(local, 0);
374
375                         ieee80211_offchannel_return(local, true);
376                 }
377
378                 ieee80211_recalc_idle(local);
379
380                 ieee80211_start_next_roc(local);
381         }
382
383  out_unlock:
384         mutex_unlock(&local->mtx);
385 }
386
387 static void ieee80211_hw_roc_done(struct work_struct *work)
388 {
389         struct ieee80211_local *local =
390                 container_of(work, struct ieee80211_local, hw_roc_done);
391         struct ieee80211_roc_work *roc;
392
393         mutex_lock(&local->mtx);
394
395         if (list_empty(&local->roc_list))
396                 goto out_unlock;
397
398         roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work,
399                                list);
400
401         if (!roc->started)
402                 goto out_unlock;
403
404         list_del(&roc->list);
405
406         ieee80211_roc_notify_destroy(roc);
407
408         /* if there's another roc, start it now */
409         ieee80211_start_next_roc(local);
410
411  out_unlock:
412         mutex_unlock(&local->mtx);
413 }
414
415 void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw)
416 {
417         struct ieee80211_local *local = hw_to_local(hw);
418
419         trace_api_remain_on_channel_expired(local);
420
421         ieee80211_queue_work(hw, &local->hw_roc_done);
422 }
423 EXPORT_SYMBOL_GPL(ieee80211_remain_on_channel_expired);
424
425 void ieee80211_roc_setup(struct ieee80211_local *local)
426 {
427         INIT_WORK(&local->hw_roc_start, ieee80211_hw_roc_start);
428         INIT_WORK(&local->hw_roc_done, ieee80211_hw_roc_done);
429         INIT_LIST_HEAD(&local->roc_list);
430 }
431
432 void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata)
433 {
434         struct ieee80211_local *local = sdata->local;
435         struct ieee80211_roc_work *roc, *tmp;
436         LIST_HEAD(tmp_list);
437
438         mutex_lock(&local->mtx);
439         list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
440                 if (roc->sdata != sdata)
441                         continue;
442
443                 if (roc->started && local->ops->remain_on_channel) {
444                         /* can race, so ignore return value */
445                         drv_cancel_remain_on_channel(local);
446                 }
447
448                 list_move_tail(&roc->list, &tmp_list);
449                 roc->abort = true;
450         }
451
452         ieee80211_start_next_roc(local);
453         mutex_unlock(&local->mtx);
454
455         list_for_each_entry_safe(roc, tmp, &tmp_list, list) {
456                 if (local->ops->remain_on_channel) {
457                         list_del(&roc->list);
458                         ieee80211_roc_notify_destroy(roc);
459                 } else {
460                         ieee80211_queue_delayed_work(&local->hw, &roc->work, 0);
461
462                         /* work will clean up etc */
463                         flush_delayed_work(&roc->work);
464                 }
465         }
466
467         WARN_ON_ONCE(!list_empty(&tmp_list));
468 }