Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso...
[pandora-kernel.git] / net / mac80211 / work.c
1 /*
2  * mac80211 work implementation
3  *
4  * Copyright 2003-2008, Jouni Malinen <j@w1.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
16 #include <linux/delay.h>
17 #include <linux/if_ether.h>
18 #include <linux/skbuff.h>
19 #include <linux/if_arp.h>
20 #include <linux/etherdevice.h>
21 #include <linux/crc32.h>
22 #include <linux/slab.h>
23 #include <net/mac80211.h>
24 #include <asm/unaligned.h>
25
26 #include "ieee80211_i.h"
27 #include "rate.h"
28 #include "driver-ops.h"
29
30 enum work_action {
31         WORK_ACT_NONE,
32         WORK_ACT_TIMEOUT,
33 };
34
35
36 /* utils */
37 static inline void ASSERT_WORK_MTX(struct ieee80211_local *local)
38 {
39         lockdep_assert_held(&local->mtx);
40 }
41
42 /*
43  * We can have multiple work items (and connection probing)
44  * scheduling this timer, but we need to take care to only
45  * reschedule it when it should fire _earlier_ than it was
46  * asked for before, or if it's not pending right now. This
47  * function ensures that. Note that it then is required to
48  * run this function for all timeouts after the first one
49  * has happened -- the work that runs from this timer will
50  * do that.
51  */
52 static void run_again(struct ieee80211_local *local,
53                       unsigned long timeout)
54 {
55         ASSERT_WORK_MTX(local);
56
57         if (!timer_pending(&local->work_timer) ||
58             time_before(timeout, local->work_timer.expires))
59                 mod_timer(&local->work_timer, timeout);
60 }
61
62 void free_work(struct ieee80211_work *wk)
63 {
64         kfree_rcu(wk, rcu_head);
65 }
66
67 static enum work_action __must_check
68 ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk)
69 {
70         /*
71          * First time we run, do nothing -- the generic code will
72          * have switched to the right channel etc.
73          */
74         if (!wk->started) {
75                 wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration);
76
77                 cfg80211_ready_on_channel(wk->sdata->dev, (unsigned long) wk,
78                                           wk->chan, wk->chan_type,
79                                           wk->remain.duration, GFP_KERNEL);
80
81                 return WORK_ACT_NONE;
82         }
83
84         return WORK_ACT_TIMEOUT;
85 }
86
87 static enum work_action __must_check
88 ieee80211_offchannel_tx(struct ieee80211_work *wk)
89 {
90         if (!wk->started) {
91                 wk->timeout = jiffies + msecs_to_jiffies(wk->offchan_tx.wait);
92
93                 /*
94                  * After this, offchan_tx.frame remains but now is no
95                  * longer a valid pointer -- we still need it as the
96                  * cookie for canceling this work/status matching.
97                  */
98                 ieee80211_tx_skb(wk->sdata, wk->offchan_tx.frame);
99
100                 return WORK_ACT_NONE;
101         }
102
103         return WORK_ACT_TIMEOUT;
104 }
105
106 static void ieee80211_work_timer(unsigned long data)
107 {
108         struct ieee80211_local *local = (void *) data;
109
110         if (local->quiescing)
111                 return;
112
113         ieee80211_queue_work(&local->hw, &local->work_work);
114 }
115
116 static void ieee80211_work_work(struct work_struct *work)
117 {
118         struct ieee80211_local *local =
119                 container_of(work, struct ieee80211_local, work_work);
120         struct ieee80211_work *wk, *tmp;
121         LIST_HEAD(free_work);
122         enum work_action rma;
123         bool remain_off_channel = false;
124
125         if (local->scanning)
126                 return;
127
128         /*
129          * ieee80211_queue_work() should have picked up most cases,
130          * here we'll pick the rest.
131          */
132         if (WARN(local->suspended, "work scheduled while going to suspend\n"))
133                 return;
134
135         mutex_lock(&local->mtx);
136
137         ieee80211_recalc_idle(local);
138
139         list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
140                 bool started = wk->started;
141
142                 /* mark work as started if it's on the current off-channel */
143                 if (!started && local->tmp_channel &&
144                     wk->chan == local->tmp_channel &&
145                     wk->chan_type == local->tmp_channel_type) {
146                         started = true;
147                         wk->timeout = jiffies;
148                 }
149
150                 if (!started && !local->tmp_channel) {
151                         ieee80211_offchannel_stop_vifs(local, true);
152
153                         local->tmp_channel = wk->chan;
154                         local->tmp_channel_type = wk->chan_type;
155
156                         ieee80211_hw_config(local, 0);
157
158                         started = true;
159                         wk->timeout = jiffies;
160                 }
161
162                 /* don't try to work with items that aren't started */
163                 if (!started)
164                         continue;
165
166                 if (time_is_after_jiffies(wk->timeout)) {
167                         /*
168                          * This work item isn't supposed to be worked on
169                          * right now, but take care to adjust the timer
170                          * properly.
171                          */
172                         run_again(local, wk->timeout);
173                         continue;
174                 }
175
176                 switch (wk->type) {
177                 default:
178                         WARN_ON(1);
179                         /* nothing */
180                         rma = WORK_ACT_NONE;
181                         break;
182                 case IEEE80211_WORK_ABORT:
183                         rma = WORK_ACT_TIMEOUT;
184                         break;
185                 case IEEE80211_WORK_REMAIN_ON_CHANNEL:
186                         rma = ieee80211_remain_on_channel_timeout(wk);
187                         break;
188                 case IEEE80211_WORK_OFFCHANNEL_TX:
189                         rma = ieee80211_offchannel_tx(wk);
190                         break;
191                 }
192
193                 wk->started = started;
194
195                 switch (rma) {
196                 case WORK_ACT_NONE:
197                         /* might have changed the timeout */
198                         run_again(local, wk->timeout);
199                         break;
200                 case WORK_ACT_TIMEOUT:
201                         list_del_rcu(&wk->list);
202                         synchronize_rcu();
203                         list_add(&wk->list, &free_work);
204                         break;
205                 default:
206                         WARN(1, "unexpected: %d", rma);
207                 }
208         }
209
210         list_for_each_entry(wk, &local->work_list, list) {
211                 if (!wk->started)
212                         continue;
213                 if (wk->chan != local->tmp_channel ||
214                     wk->chan_type != local->tmp_channel_type)
215                         continue;
216                 remain_off_channel = true;
217         }
218
219         if (!remain_off_channel && local->tmp_channel) {
220                 local->tmp_channel = NULL;
221                 ieee80211_hw_config(local, 0);
222
223                 ieee80211_offchannel_return(local, true);
224
225                 /* give connection some time to breathe */
226                 run_again(local, jiffies + HZ/2);
227         }
228
229         if (list_empty(&local->work_list) && local->scan_req &&
230             !local->scanning)
231                 ieee80211_queue_delayed_work(&local->hw,
232                                              &local->scan_work,
233                                              round_jiffies_relative(0));
234
235         ieee80211_recalc_idle(local);
236
237         mutex_unlock(&local->mtx);
238
239         list_for_each_entry_safe(wk, tmp, &free_work, list) {
240                 wk->done(wk, NULL);
241                 list_del(&wk->list);
242                 kfree(wk);
243         }
244 }
245
246 void ieee80211_add_work(struct ieee80211_work *wk)
247 {
248         struct ieee80211_local *local;
249
250         if (WARN_ON(!wk->chan))
251                 return;
252
253         if (WARN_ON(!wk->sdata))
254                 return;
255
256         if (WARN_ON(!wk->done))
257                 return;
258
259         if (WARN_ON(!ieee80211_sdata_running(wk->sdata)))
260                 return;
261
262         wk->started = false;
263
264         local = wk->sdata->local;
265         mutex_lock(&local->mtx);
266         list_add_tail(&wk->list, &local->work_list);
267         mutex_unlock(&local->mtx);
268
269         ieee80211_queue_work(&local->hw, &local->work_work);
270 }
271
272 void ieee80211_work_init(struct ieee80211_local *local)
273 {
274         INIT_LIST_HEAD(&local->work_list);
275         setup_timer(&local->work_timer, ieee80211_work_timer,
276                     (unsigned long)local);
277         INIT_WORK(&local->work_work, ieee80211_work_work);
278 }
279
280 void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata)
281 {
282         struct ieee80211_local *local = sdata->local;
283         struct ieee80211_work *wk;
284         bool cleanup = false;
285
286         mutex_lock(&local->mtx);
287         list_for_each_entry(wk, &local->work_list, list) {
288                 if (wk->sdata != sdata)
289                         continue;
290                 cleanup = true;
291                 wk->type = IEEE80211_WORK_ABORT;
292                 wk->started = true;
293                 wk->timeout = jiffies;
294         }
295         mutex_unlock(&local->mtx);
296
297         /* run cleanups etc. */
298         if (cleanup)
299                 ieee80211_work_work(&local->work_work);
300
301         mutex_lock(&local->mtx);
302         list_for_each_entry(wk, &local->work_list, list) {
303                 if (wk->sdata != sdata)
304                         continue;
305                 WARN_ON(1);
306                 break;
307         }
308         mutex_unlock(&local->mtx);
309 }
310
311 static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk,
312                                                    struct sk_buff *skb)
313 {
314         /*
315          * We are done serving the remain-on-channel command.
316          */
317         cfg80211_remain_on_channel_expired(wk->sdata->dev, (unsigned long) wk,
318                                            wk->chan, wk->chan_type,
319                                            GFP_KERNEL);
320
321         return WORK_DONE_DESTROY;
322 }
323
324 int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
325                                    struct ieee80211_channel *chan,
326                                    enum nl80211_channel_type channel_type,
327                                    unsigned int duration, u64 *cookie)
328 {
329         struct ieee80211_work *wk;
330
331         wk = kzalloc(sizeof(*wk), GFP_KERNEL);
332         if (!wk)
333                 return -ENOMEM;
334
335         wk->type = IEEE80211_WORK_REMAIN_ON_CHANNEL;
336         wk->chan = chan;
337         wk->chan_type = channel_type;
338         wk->sdata = sdata;
339         wk->done = ieee80211_remain_done;
340
341         wk->remain.duration = duration;
342
343         *cookie = (unsigned long) wk;
344
345         ieee80211_add_work(wk);
346
347         return 0;
348 }
349
350 int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata,
351                                           u64 cookie)
352 {
353         struct ieee80211_local *local = sdata->local;
354         struct ieee80211_work *wk, *tmp;
355         bool found = false;
356
357         mutex_lock(&local->mtx);
358         list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
359                 if ((unsigned long) wk == cookie) {
360                         wk->timeout = jiffies;
361                         found = true;
362                         break;
363                 }
364         }
365         mutex_unlock(&local->mtx);
366
367         if (!found)
368                 return -ENOENT;
369
370         ieee80211_queue_work(&local->hw, &local->work_work);
371
372         return 0;
373 }