00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include <linux/delay.h>
00017 #include <linux/if_ether.h>
00018 #include <linux/skbuff.h>
00019 #include <linux/if_arp.h>
00020 #include <linux/etherdevice.h>
00021 #include <linux/crc32.h>
00022 #include <linux/slab.h>
00023 #include <net/mac80211.h>
00024 #include <asm/unaligned.h>
00025
00026 #include "ieee80211_i.h"
00027 #include "rate.h"
00028 #include "driver-ops.h"
00029
00030 enum work_action {
00031 WORK_ACT_NONE,
00032 WORK_ACT_TIMEOUT,
00033 };
00034
00035
00036
00037 static inline void ASSERT_WORK_MTX(struct ieee80211_local *local)
00038 {
00039 lockdep_assert_held(&local->mtx);
00040 }
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052 static void run_again(struct ieee80211_local *local,
00053 unsigned long timeout)
00054 {
00055 ASSERT_WORK_MTX(local);
00056
00057 if (!timer_pending(&local->work_timer) ||
00058 time_before(timeout, local->work_timer.expires))
00059 mod_timer(&local->work_timer, timeout);
00060 }
00061
00062 void free_work(struct ieee80211_work *wk)
00063 {
00064 kfree_rcu(wk, rcu_head);
00065 }
00066
00067 static enum work_action __must_check
00068 ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk)
00069 {
00070
00071
00072
00073
00074 if (!wk->started) {
00075 wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration);
00076
00077 cfg80211_ready_on_channel(wk->sdata->dev, (unsigned long) wk,
00078 wk->chan, wk->chan_type,
00079 wk->remain.duration, GFP_KERNEL);
00080
00081 return WORK_ACT_NONE;
00082 }
00083
00084 return WORK_ACT_TIMEOUT;
00085 }
00086
00087 static enum work_action __must_check
00088 ieee80211_offchannel_tx(struct ieee80211_work *wk)
00089 {
00090 if (!wk->started) {
00091 wk->timeout = jiffies + msecs_to_jiffies(wk->offchan_tx.wait);
00092
00093
00094
00095
00096
00097
00098 ieee80211_tx_skb(wk->sdata, wk->offchan_tx.frame);
00099
00100 return WORK_ACT_NONE;
00101 }
00102
00103 return WORK_ACT_TIMEOUT;
00104 }
00105
00106 static void ieee80211_work_timer(unsigned long data)
00107 {
00108 struct ieee80211_local *local = (void *) data;
00109
00110 if (local->quiescing)
00111 return;
00112
00113 ieee80211_queue_work(&local->hw, &local->work_work);
00114 }
00115
00116 static void ieee80211_work_work(struct work_struct *work)
00117 {
00118 struct ieee80211_local *local =
00119 container_of(work, struct ieee80211_local, work_work);
00120 struct ieee80211_work *wk, *tmp;
00121 LIST_HEAD(free_work);
00122 enum work_action rma;
00123 bool remain_off_channel = false;
00124
00125
00126
00127
00128
00129 if (WARN(local->suspended, "work scheduled while going to suspend\n"))
00130 return;
00131
00132 mutex_lock(&local->mtx);
00133
00134 if (local->scanning) {
00135 mutex_unlock(&local->mtx);
00136 return;
00137 }
00138
00139 ieee80211_recalc_idle(local);
00140
00141 list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
00142 bool started = wk->started;
00143
00144
00145 if (!started && local->tmp_channel &&
00146 wk->chan == local->tmp_channel &&
00147 wk->chan_type == local->tmp_channel_type) {
00148 started = true;
00149 wk->timeout = jiffies;
00150 }
00151
00152 if (!started && !local->tmp_channel) {
00153 ieee80211_offchannel_stop_vifs(local, true);
00154
00155 local->tmp_channel = wk->chan;
00156 local->tmp_channel_type = wk->chan_type;
00157
00158 ieee80211_hw_config(local, 0);
00159
00160 started = true;
00161 wk->timeout = jiffies;
00162 }
00163
00164
00165 if (!started)
00166 continue;
00167
00168 if (time_is_after_jiffies(wk->timeout)) {
00169
00170
00171
00172
00173
00174 run_again(local, wk->timeout);
00175 continue;
00176 }
00177
00178 switch (wk->type) {
00179 default:
00180 WARN_ON(1);
00181
00182 rma = WORK_ACT_NONE;
00183 break;
00184 case IEEE80211_WORK_ABORT:
00185 rma = WORK_ACT_TIMEOUT;
00186 break;
00187 case IEEE80211_WORK_REMAIN_ON_CHANNEL:
00188 rma = ieee80211_remain_on_channel_timeout(wk);
00189 break;
00190 case IEEE80211_WORK_OFFCHANNEL_TX:
00191 rma = ieee80211_offchannel_tx(wk);
00192 break;
00193 }
00194
00195 wk->started = started;
00196
00197 switch (rma) {
00198 case WORK_ACT_NONE:
00199
00200 run_again(local, wk->timeout);
00201 break;
00202 case WORK_ACT_TIMEOUT:
00203 list_del_rcu(&wk->list);
00204 synchronize_rcu();
00205 list_add(&wk->list, &free_work);
00206 break;
00207 default:
00208 WARN(1, "unexpected: %d", rma);
00209 }
00210 }
00211
00212 list_for_each_entry(wk, &local->work_list, list) {
00213 if (!wk->started)
00214 continue;
00215 if (wk->chan != local->tmp_channel ||
00216 wk->chan_type != local->tmp_channel_type)
00217 continue;
00218 remain_off_channel = true;
00219 }
00220
00221 if (!remain_off_channel && local->tmp_channel) {
00222 local->tmp_channel = NULL;
00223 ieee80211_hw_config(local, 0);
00224
00225 ieee80211_offchannel_return(local, true);
00226
00227
00228 run_again(local, jiffies + HZ/2);
00229 }
00230
00231 ieee80211_recalc_idle(local);
00232 ieee80211_run_deferred_scan(local);
00233
00234 mutex_unlock(&local->mtx);
00235
00236 list_for_each_entry_safe(wk, tmp, &free_work, list) {
00237 wk->done(wk, NULL);
00238 list_del(&wk->list);
00239 kfree(wk);
00240 }
00241 }
00242
00243 void ieee80211_add_work(struct ieee80211_work *wk)
00244 {
00245 struct ieee80211_local *local;
00246
00247 if (WARN_ON(!wk->chan))
00248 return;
00249
00250 if (WARN_ON(!wk->sdata))
00251 return;
00252
00253 if (WARN_ON(!wk->done))
00254 return;
00255
00256 if (WARN_ON(!ieee80211_sdata_running(wk->sdata)))
00257 return;
00258
00259 wk->started = false;
00260
00261 local = wk->sdata->local;
00262 mutex_lock(&local->mtx);
00263 list_add_tail(&wk->list, &local->work_list);
00264 mutex_unlock(&local->mtx);
00265
00266 ieee80211_queue_work(&local->hw, &local->work_work);
00267 }
00268
00269 void ieee80211_work_init(struct ieee80211_local *local)
00270 {
00271 INIT_LIST_HEAD(&local->work_list);
00272 setup_timer(&local->work_timer, ieee80211_work_timer,
00273 (unsigned long)local);
00274 INIT_WORK(&local->work_work, ieee80211_work_work);
00275 }
00276
00277 void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata)
00278 {
00279 struct ieee80211_local *local = sdata->local;
00280 struct ieee80211_work *wk;
00281 bool cleanup = false;
00282
00283 mutex_lock(&local->mtx);
00284 list_for_each_entry(wk, &local->work_list, list) {
00285 if (wk->sdata != sdata)
00286 continue;
00287 cleanup = true;
00288 wk->type = IEEE80211_WORK_ABORT;
00289 wk->started = true;
00290 wk->timeout = jiffies;
00291 }
00292 mutex_unlock(&local->mtx);
00293
00294
00295 if (cleanup)
00296 ieee80211_work_work(&local->work_work);
00297
00298 mutex_lock(&local->mtx);
00299 list_for_each_entry(wk, &local->work_list, list) {
00300 if (wk->sdata != sdata)
00301 continue;
00302 WARN_ON(1);
00303 break;
00304 }
00305 mutex_unlock(&local->mtx);
00306 }
00307
00308 static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk,
00309 struct sk_buff *skb)
00310 {
00311
00312
00313
00314 cfg80211_remain_on_channel_expired(wk->sdata->dev, (unsigned long) wk,
00315 wk->chan, wk->chan_type,
00316 GFP_KERNEL);
00317
00318 return WORK_DONE_DESTROY;
00319 }
00320
00321 int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
00322 struct ieee80211_channel *chan,
00323 enum nl80211_channel_type channel_type,
00324 unsigned int duration, u64 *cookie)
00325 {
00326 struct ieee80211_work *wk;
00327
00328 wk = kzalloc(sizeof(*wk), GFP_KERNEL);
00329 if (!wk)
00330 return -ENOMEM;
00331
00332 wk->type = IEEE80211_WORK_REMAIN_ON_CHANNEL;
00333 wk->chan = chan;
00334 wk->chan_type = channel_type;
00335 wk->sdata = sdata;
00336 wk->done = ieee80211_remain_done;
00337
00338 wk->remain.duration = duration;
00339
00340 *cookie = (unsigned long) wk;
00341
00342 ieee80211_add_work(wk);
00343
00344 return 0;
00345 }
00346
00347 int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata,
00348 u64 cookie)
00349 {
00350 struct ieee80211_local *local = sdata->local;
00351 struct ieee80211_work *wk, *tmp;
00352 bool found = false;
00353
00354 mutex_lock(&local->mtx);
00355 list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
00356 if ((unsigned long) wk == cookie) {
00357 wk->timeout = jiffies;
00358 found = true;
00359 break;
00360 }
00361 }
00362 mutex_unlock(&local->mtx);
00363
00364 if (!found)
00365 return -ENOENT;
00366
00367 ieee80211_queue_work(&local->hw, &local->work_work);
00368
00369 return 0;
00370 }