Blame view

net/mac80211/work.c 29.8 KB
af6b63741   Johannes Berg   mac80211: general...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  /*
   * mac80211 work implementation
   *
   * Copyright 2003-2008, Jouni Malinen <j@w1.fi>
   * Copyright 2004, Instant802 Networks, Inc.
   * Copyright 2005, Devicescape Software, Inc.
   * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
   * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
   * Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  
  #include <linux/delay.h>
  #include <linux/if_ether.h>
  #include <linux/skbuff.h>
  #include <linux/if_arp.h>
  #include <linux/etherdevice.h>
  #include <linux/crc32.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
22
  #include <linux/slab.h>
af6b63741   Johannes Berg   mac80211: general...
23
24
25
26
27
  #include <net/mac80211.h>
  #include <asm/unaligned.h>
  
  #include "ieee80211_i.h"
  #include "rate.h"
b2abb6e2b   Johannes Berg   mac80211: sync dr...
28
  #include "driver-ops.h"
af6b63741   Johannes Berg   mac80211: general...
29
30
31
32
33
  
  #define IEEE80211_AUTH_TIMEOUT (HZ / 5)
  #define IEEE80211_AUTH_MAX_TRIES 3
  #define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
  #define IEEE80211_ASSOC_MAX_TRIES 3
af6b63741   Johannes Berg   mac80211: general...
34
35
  
  enum work_action {
b8d92c9c1   Johannes Berg   mac80211: don't p...
36
  	WORK_ACT_MISMATCH,
af6b63741   Johannes Berg   mac80211: general...
37
38
39
40
41
42
43
44
45
  	WORK_ACT_NONE,
  	WORK_ACT_TIMEOUT,
  	WORK_ACT_DONE,
  };
  
  
  /* utils */
  static inline void ASSERT_WORK_MTX(struct ieee80211_local *local)
  {
a1699b75a   Johannes Berg   mac80211: unify s...
46
  	lockdep_assert_held(&local->mtx);
af6b63741   Johannes Berg   mac80211: general...
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
  }
  
  /*
   * We can have multiple work items (and connection probing)
   * scheduling this timer, but we need to take care to only
   * reschedule it when it should fire _earlier_ than it was
   * asked for before, or if it's not pending right now. This
   * function ensures that. Note that it then is required to
   * run this function for all timeouts after the first one
   * has happened -- the work that runs from this timer will
   * do that.
   */
  static void run_again(struct ieee80211_local *local,
  		      unsigned long timeout)
  {
  	ASSERT_WORK_MTX(local);
  
  	if (!timer_pending(&local->work_timer) ||
  	    time_before(timeout, local->work_timer.expires))
  		mod_timer(&local->work_timer, timeout);
  }
af6b63741   Johannes Berg   mac80211: general...
68
69
  void free_work(struct ieee80211_work *wk)
  {
a74ce1425   Lai Jiangshan   net/mac80211,rcu:...
70
  	kfree_rcu(wk, rcu_head);
af6b63741   Johannes Berg   mac80211: general...
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
  }
  
  static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
  				      struct ieee80211_supported_band *sband,
  				      u32 *rates)
  {
  	int i, j, count;
  	*rates = 0;
  	count = 0;
  	for (i = 0; i < supp_rates_len; i++) {
  		int rate = (supp_rates[i] & 0x7F) * 5;
  
  		for (j = 0; j < sband->n_bitrates; j++)
  			if (sband->bitrates[j].bitrate == rate) {
  				*rates |= BIT(j);
  				count++;
  				break;
  			}
  	}
  
  	return count;
  }
  
  /* frame sending functions */
ef96a8420   Ben Greear   mac80211: Support...
95
96
  static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
  				struct sk_buff *skb, const u8 *ht_info_ie,
77c8144ad   Johannes Berg   mac80211: refacto...
97
98
99
100
101
102
103
  				struct ieee80211_supported_band *sband,
  				struct ieee80211_channel *channel,
  				enum ieee80211_smps_mode smps)
  {
  	struct ieee80211_ht_info *ht_info;
  	u8 *pos;
  	u32 flags = channel->flags;
ef96a8420   Ben Greear   mac80211: Support...
104
105
106
107
  	u16 cap;
  	struct ieee80211_sta_ht_cap ht_cap;
  
  	BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap));
77c8144ad   Johannes Berg   mac80211: refacto...
108
109
110
111
112
113
114
115
116
  
  	if (!sband->ht_cap.ht_supported)
  		return;
  
  	if (!ht_info_ie)
  		return;
  
  	if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info))
  		return;
ef96a8420   Ben Greear   mac80211: Support...
117
118
  	memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
  	ieee80211_apply_htcap_overrides(sdata, &ht_cap);
77c8144ad   Johannes Berg   mac80211: refacto...
119
120
121
  	ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2);
  
  	/* determine capability flags */
ef96a8420   Ben Greear   mac80211: Support...
122
  	cap = ht_cap.cap;
77c8144ad   Johannes Berg   mac80211: refacto...
123

77c8144ad   Johannes Berg   mac80211: refacto...
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
  	switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
  	case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
  		if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
  			cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
  			cap &= ~IEEE80211_HT_CAP_SGI_40;
  		}
  		break;
  	case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
  		if (flags & IEEE80211_CHAN_NO_HT40MINUS) {
  			cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
  			cap &= ~IEEE80211_HT_CAP_SGI_40;
  		}
  		break;
  	}
  
  	/* set SM PS mode properly */
  	cap &= ~IEEE80211_HT_CAP_SM_PS;
  	switch (smps) {
  	case IEEE80211_SMPS_AUTOMATIC:
  	case IEEE80211_SMPS_NUM_MODES:
  		WARN_ON(1);
  	case IEEE80211_SMPS_OFF:
  		cap |= WLAN_HT_CAP_SM_PS_DISABLED <<
  			IEEE80211_HT_CAP_SM_PS_SHIFT;
  		break;
  	case IEEE80211_SMPS_STATIC:
  		cap |= WLAN_HT_CAP_SM_PS_STATIC <<
  			IEEE80211_HT_CAP_SM_PS_SHIFT;
  		break;
  	case IEEE80211_SMPS_DYNAMIC:
  		cap |= WLAN_HT_CAP_SM_PS_DYNAMIC <<
  			IEEE80211_HT_CAP_SM_PS_SHIFT;
  		break;
  	}
  
  	/* reserve and fill IE */
77c8144ad   Johannes Berg   mac80211: refacto...
160
  	pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
ef96a8420   Ben Greear   mac80211: Support...
161
  	ieee80211_ie_build_ht_cap(pos, &ht_cap, cap);
77c8144ad   Johannes Berg   mac80211: refacto...
162
  }
af6b63741   Johannes Berg   mac80211: general...
163
164
165
166
167
168
  static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
  				 struct ieee80211_work *wk)
  {
  	struct ieee80211_local *local = sdata->local;
  	struct sk_buff *skb;
  	struct ieee80211_mgmt *mgmt;
ab13315af   Kalle Valo   mac80211: add U-A...
169
  	u8 *pos, qos_info;
8e664fb3f   Johannes Berg   mac80211: split u...
170
  	size_t offset = 0, noffset;
0915cba39   Rajkumar Manoharan   mac80211: Fix war...
171
  	int i, count, rates_len, supp_rates_len;
af6b63741   Johannes Berg   mac80211: general...
172
173
174
  	u16 capab;
  	struct ieee80211_supported_band *sband;
  	u32 rates = 0;
77c8144ad   Johannes Berg   mac80211: refacto...
175
  	sband = local->hw.wiphy->bands[wk->chan->band];
76f273640   Stanislaw Gruszka   mac80211: fix sup...
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
  	if (wk->assoc.supp_rates_len) {
  		/*
  		 * Get all rates supported by the device and the AP as
  		 * some APs don't like getting a superset of their rates
  		 * in the association request (e.g. D-Link DAP 1353 in
  		 * b-only mode)...
  		 */
  		rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates,
  						       wk->assoc.supp_rates_len,
  						       sband, &rates);
  	} else {
  		/*
  		 * In case AP not provide any supported rates information
  		 * before association, we send information element(s) with
  		 * all rates that we support.
  		 */
  		rates = ~0;
  		rates_len = sband->n_bitrates;
  	}
77c8144ad   Johannes Berg   mac80211: refacto...
195
196
197
198
199
200
201
202
203
204
205
  
  	skb = alloc_skb(local->hw.extra_tx_headroom +
  			sizeof(*mgmt) + /* bit too much but doesn't matter */
  			2 + wk->assoc.ssid_len + /* SSID */
  			4 + rates_len + /* (extended) rates */
  			4 + /* power capability */
  			2 + 2 * sband->n_channels + /* supported channels */
  			2 + sizeof(struct ieee80211_ht_cap) + /* HT */
  			wk->ie_len + /* extra IEs */
  			9, /* WMM */
  			GFP_KERNEL);
d15b84590   Joe Perches   mac80211: Remove ...
206
  	if (!skb)
af6b63741   Johannes Berg   mac80211: general...
207
  		return;
d15b84590   Joe Perches   mac80211: Remove ...
208

af6b63741   Johannes Berg   mac80211: general...
209
  	skb_reserve(skb, local->hw.extra_tx_headroom);
af6b63741   Johannes Berg   mac80211: general...
210
211
212
213
214
215
216
217
218
219
220
  	capab = WLAN_CAPABILITY_ESS;
  
  	if (sband->band == IEEE80211_BAND_2GHZ) {
  		if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
  			capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
  		if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
  			capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
  	}
  
  	if (wk->assoc.capability & WLAN_CAPABILITY_PRIVACY)
  		capab |= WLAN_CAPABILITY_PRIVACY;
af6b63741   Johannes Berg   mac80211: general...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
  	if ((wk->assoc.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
  	    (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
  		capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
  
  	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
  	memset(mgmt, 0, 24);
  	memcpy(mgmt->da, wk->filter_ta, ETH_ALEN);
  	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
  	memcpy(mgmt->bssid, wk->filter_ta, ETH_ALEN);
  
  	if (!is_zero_ether_addr(wk->assoc.prev_bssid)) {
  		skb_put(skb, 10);
  		mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
  						  IEEE80211_STYPE_REASSOC_REQ);
  		mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);
  		mgmt->u.reassoc_req.listen_interval =
  				cpu_to_le16(local->hw.conf.listen_interval);
  		memcpy(mgmt->u.reassoc_req.current_ap, wk->assoc.prev_bssid,
  		       ETH_ALEN);
  	} else {
  		skb_put(skb, 4);
  		mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
  						  IEEE80211_STYPE_ASSOC_REQ);
  		mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
  		mgmt->u.assoc_req.listen_interval =
  				cpu_to_le16(local->hw.conf.listen_interval);
  	}
  
  	/* SSID */
0915cba39   Rajkumar Manoharan   mac80211: Fix war...
250
  	pos = skb_put(skb, 2 + wk->assoc.ssid_len);
af6b63741   Johannes Berg   mac80211: general...
251
252
253
254
255
256
257
258
  	*pos++ = WLAN_EID_SSID;
  	*pos++ = wk->assoc.ssid_len;
  	memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len);
  
  	/* add all rates which were marked to be used above */
  	supp_rates_len = rates_len;
  	if (supp_rates_len > 8)
  		supp_rates_len = 8;
af6b63741   Johannes Berg   mac80211: general...
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
  	pos = skb_put(skb, supp_rates_len + 2);
  	*pos++ = WLAN_EID_SUPP_RATES;
  	*pos++ = supp_rates_len;
  
  	count = 0;
  	for (i = 0; i < sband->n_bitrates; i++) {
  		if (BIT(i) & rates) {
  			int rate = sband->bitrates[i].bitrate;
  			*pos++ = (u8) (rate / 5);
  			if (++count == 8)
  				break;
  		}
  	}
  
  	if (rates_len > count) {
  		pos = skb_put(skb, rates_len - count + 2);
  		*pos++ = WLAN_EID_EXT_SUPP_RATES;
  		*pos++ = rates_len - count;
  
  		for (i++; i < sband->n_bitrates; i++) {
  			if (BIT(i) & rates) {
  				int rate = sband->bitrates[i].bitrate;
  				*pos++ = (u8) (rate / 5);
  			}
  		}
  	}
  
  	if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) {
  		/* 1. power capabilities */
  		pos = skb_put(skb, 4);
  		*pos++ = WLAN_EID_PWR_CAPABILITY;
  		*pos++ = 2;
  		*pos++ = 0; /* min tx power */
77c8144ad   Johannes Berg   mac80211: refacto...
292
  		*pos++ = wk->chan->max_power; /* max tx power */
af6b63741   Johannes Berg   mac80211: general...
293
294
295
296
297
298
299
300
301
302
303
304
  
  		/* 2. supported channels */
  		/* TODO: get this in reg domain format */
  		pos = skb_put(skb, 2 * sband->n_channels + 2);
  		*pos++ = WLAN_EID_SUPPORTED_CHANNELS;
  		*pos++ = 2 * sband->n_channels;
  		for (i = 0; i < sband->n_channels; i++) {
  			*pos++ = ieee80211_frequency_to_channel(
  					sband->channels[i].center_freq);
  			*pos++ = 1; /* one channel in the subband*/
  		}
  	}
8e664fb3f   Johannes Berg   mac80211: split u...
305
  	/* if present, add any custom IEs that go before HT */
af6b63741   Johannes Berg   mac80211: general...
306
  	if (wk->ie_len && wk->ie) {
8e664fb3f   Johannes Berg   mac80211: split u...
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
  		static const u8 before_ht[] = {
  			WLAN_EID_SSID,
  			WLAN_EID_SUPP_RATES,
  			WLAN_EID_EXT_SUPP_RATES,
  			WLAN_EID_PWR_CAPABILITY,
  			WLAN_EID_SUPPORTED_CHANNELS,
  			WLAN_EID_RSN,
  			WLAN_EID_QOS_CAPA,
  			WLAN_EID_RRM_ENABLED_CAPABILITIES,
  			WLAN_EID_MOBILITY_DOMAIN,
  			WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
  		};
  		noffset = ieee80211_ie_split(wk->ie, wk->ie_len,
  					     before_ht, ARRAY_SIZE(before_ht),
  					     offset);
  		pos = skb_put(skb, noffset - offset);
  		memcpy(pos, wk->ie + offset, noffset - offset);
  		offset = noffset;
af6b63741   Johannes Berg   mac80211: general...
325
  	}
77c8144ad   Johannes Berg   mac80211: refacto...
326
327
  	if (wk->assoc.use_11n && wk->assoc.wmm_used &&
  	    local->hw.queues >= 4)
ef96a8420   Ben Greear   mac80211: Support...
328
  		ieee80211_add_ht_ie(sdata, skb, wk->assoc.ht_information_ie,
77c8144ad   Johannes Berg   mac80211: refacto...
329
  				    sband, wk->chan, wk->assoc.smps);
8e664fb3f   Johannes Berg   mac80211: split u...
330
331
332
333
334
335
336
337
  	/* if present, add any custom non-vendor IEs that go after HT */
  	if (wk->ie_len && wk->ie) {
  		noffset = ieee80211_ie_split_vendor(wk->ie, wk->ie_len,
  						    offset);
  		pos = skb_put(skb, noffset - offset);
  		memcpy(pos, wk->ie + offset, noffset - offset);
  		offset = noffset;
  	}
af6b63741   Johannes Berg   mac80211: general...
338
  	if (wk->assoc.wmm_used && local->hw.queues >= 4) {
ab13315af   Kalle Valo   mac80211: add U-A...
339
  		if (wk->assoc.uapsd_used) {
50ae0cf15   Kalle Valo   mac80211: add deb...
340
341
  			qos_info = local->uapsd_queues;
  			qos_info |= (local->uapsd_max_sp_len <<
ab13315af   Kalle Valo   mac80211: add U-A...
342
343
344
345
  				     IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT);
  		} else {
  			qos_info = 0;
  		}
af6b63741   Johannes Berg   mac80211: general...
346
347
348
349
350
351
352
353
354
  		pos = skb_put(skb, 9);
  		*pos++ = WLAN_EID_VENDOR_SPECIFIC;
  		*pos++ = 7; /* len */
  		*pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
  		*pos++ = 0x50;
  		*pos++ = 0xf2;
  		*pos++ = 2; /* WME */
  		*pos++ = 0; /* WME info */
  		*pos++ = 1; /* WME ver */
ab13315af   Kalle Valo   mac80211: add U-A...
355
  		*pos++ = qos_info;
af6b63741   Johannes Berg   mac80211: general...
356
  	}
8e664fb3f   Johannes Berg   mac80211: split u...
357
358
359
360
361
362
  	/* add any remaining custom (i.e. vendor specific here) IEs */
  	if (wk->ie_len && wk->ie) {
  		noffset = wk->ie_len;
  		pos = skb_put(skb, noffset - offset);
  		memcpy(pos, wk->ie + offset, noffset - offset);
  	}
af6b63741   Johannes Berg   mac80211: general...
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
  	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
  	ieee80211_tx_skb(sdata, skb);
  }
  
  static void ieee80211_remove_auth_bss(struct ieee80211_local *local,
  				      struct ieee80211_work *wk)
  {
  	struct cfg80211_bss *cbss;
  	u16 capa_val = WLAN_CAPABILITY_ESS;
  
  	if (wk->probe_auth.privacy)
  		capa_val |= WLAN_CAPABILITY_PRIVACY;
  
  	cbss = cfg80211_get_bss(local->hw.wiphy, wk->chan, wk->filter_ta,
  				wk->probe_auth.ssid, wk->probe_auth.ssid_len,
  				WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY,
  				capa_val);
  	if (!cbss)
  		return;
  
  	cfg80211_unlink_bss(local->hw.wiphy, cbss);
  	cfg80211_put_bss(cbss);
  }
  
  static enum work_action __must_check
  ieee80211_direct_probe(struct ieee80211_work *wk)
  {
  	struct ieee80211_sub_if_data *sdata = wk->sdata;
  	struct ieee80211_local *local = sdata->local;
b2abb6e2b   Johannes Berg   mac80211: sync dr...
392
393
394
395
396
397
398
  	if (!wk->probe_auth.synced) {
  		int ret = drv_tx_sync(local, sdata, wk->filter_ta,
  				      IEEE80211_TX_SYNC_AUTH);
  		if (ret)
  			return WORK_ACT_TIMEOUT;
  	}
  	wk->probe_auth.synced = true;
af6b63741   Johannes Berg   mac80211: general...
399
400
  	wk->probe_auth.tries++;
  	if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) {
7d3a1c3b0   Johannes Berg   mac80211: rewrite...
401
402
  		printk(KERN_DEBUG "%s: direct probe to %pM timed out
  ",
af6b63741   Johannes Berg   mac80211: general...
403
404
405
406
407
408
409
  		       sdata->name, wk->filter_ta);
  
  		/*
  		 * Most likely AP is not in the range so remove the
  		 * bss struct for that AP.
  		 */
  		ieee80211_remove_auth_bss(local, wk);
af6b63741   Johannes Berg   mac80211: general...
410
411
  		return WORK_ACT_TIMEOUT;
  	}
2f8867501   Ben Greear   mac80211: Show ma...
412
413
414
415
  	printk(KERN_DEBUG "%s: direct probe to %pM (try %d/%i)
  ",
  	       sdata->name, wk->filter_ta, wk->probe_auth.tries,
  	       IEEE80211_AUTH_MAX_TRIES);
af6b63741   Johannes Berg   mac80211: general...
416
417
418
419
420
421
  
  	/*
  	 * Direct probe is sent to broadcast address as some APs
  	 * will not answer to direct packet in unassociated state.
  	 */
  	ieee80211_send_probe_req(sdata, NULL, wk->probe_auth.ssid,
85a237fe3   Johannes Berg   mac80211: impleme...
422
  				 wk->probe_auth.ssid_len, NULL, 0,
aad14ceb4   Rajkumar Manoharan   mac80211: Send th...
423
  				 (u32) -1, true, false);
af6b63741   Johannes Berg   mac80211: general...
424
425
426
427
428
429
430
431
432
433
434
435
436
  
  	wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
  	run_again(local, wk->timeout);
  
  	return WORK_ACT_NONE;
  }
  
  
  static enum work_action __must_check
  ieee80211_authenticate(struct ieee80211_work *wk)
  {
  	struct ieee80211_sub_if_data *sdata = wk->sdata;
  	struct ieee80211_local *local = sdata->local;
b2abb6e2b   Johannes Berg   mac80211: sync dr...
437
438
439
440
441
442
443
  	if (!wk->probe_auth.synced) {
  		int ret = drv_tx_sync(local, sdata, wk->filter_ta,
  				      IEEE80211_TX_SYNC_AUTH);
  		if (ret)
  			return WORK_ACT_TIMEOUT;
  	}
  	wk->probe_auth.synced = true;
af6b63741   Johannes Berg   mac80211: general...
444
445
  	wk->probe_auth.tries++;
  	if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) {
7d3a1c3b0   Johannes Berg   mac80211: rewrite...
446
  		printk(KERN_DEBUG "%s: authentication with %pM"
af6b63741   Johannes Berg   mac80211: general...
447
448
449
450
451
452
453
454
  		       " timed out
  ", sdata->name, wk->filter_ta);
  
  		/*
  		 * Most likely AP is not in the range so remove the
  		 * bss struct for that AP.
  		 */
  		ieee80211_remove_auth_bss(local, wk);
af6b63741   Johannes Berg   mac80211: general...
455
456
  		return WORK_ACT_TIMEOUT;
  	}
7d3a1c3b0   Johannes Berg   mac80211: rewrite...
457
458
  	printk(KERN_DEBUG "%s: authenticate with %pM (try %d)
  ",
af6b63741   Johannes Berg   mac80211: general...
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
  	       sdata->name, wk->filter_ta, wk->probe_auth.tries);
  
  	ieee80211_send_auth(sdata, 1, wk->probe_auth.algorithm, wk->ie,
  			    wk->ie_len, wk->filter_ta, NULL, 0, 0);
  	wk->probe_auth.transaction = 2;
  
  	wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
  	run_again(local, wk->timeout);
  
  	return WORK_ACT_NONE;
  }
  
  static enum work_action __must_check
  ieee80211_associate(struct ieee80211_work *wk)
  {
  	struct ieee80211_sub_if_data *sdata = wk->sdata;
  	struct ieee80211_local *local = sdata->local;
b2abb6e2b   Johannes Berg   mac80211: sync dr...
476
477
478
479
480
481
482
  	if (!wk->assoc.synced) {
  		int ret = drv_tx_sync(local, sdata, wk->filter_ta,
  				      IEEE80211_TX_SYNC_ASSOC);
  		if (ret)
  			return WORK_ACT_TIMEOUT;
  	}
  	wk->assoc.synced = true;
af6b63741   Johannes Berg   mac80211: general...
483
484
  	wk->assoc.tries++;
  	if (wk->assoc.tries > IEEE80211_ASSOC_MAX_TRIES) {
7d3a1c3b0   Johannes Berg   mac80211: rewrite...
485
  		printk(KERN_DEBUG "%s: association with %pM"
af6b63741   Johannes Berg   mac80211: general...
486
487
488
489
490
491
492
493
494
  		       " timed out
  ",
  		       sdata->name, wk->filter_ta);
  
  		/*
  		 * Most likely AP is not in the range so remove the
  		 * bss struct for that AP.
  		 */
  		if (wk->assoc.bss)
0c1ad2cac   Johannes Berg   mac80211: proper ...
495
  			cfg80211_unlink_bss(local->hw.wiphy, wk->assoc.bss);
af6b63741   Johannes Berg   mac80211: general...
496

af6b63741   Johannes Berg   mac80211: general...
497
498
  		return WORK_ACT_TIMEOUT;
  	}
7d3a1c3b0   Johannes Berg   mac80211: rewrite...
499
500
  	printk(KERN_DEBUG "%s: associate with %pM (try %d)
  ",
af6b63741   Johannes Berg   mac80211: general...
501
502
503
504
505
506
507
508
  	       sdata->name, wk->filter_ta, wk->assoc.tries);
  	ieee80211_send_assoc(sdata, wk);
  
  	wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
  	run_again(local, wk->timeout);
  
  	return WORK_ACT_NONE;
  }
b8bc4b0aa   Johannes Berg   mac80211: support...
509
510
511
  static enum work_action __must_check
  ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk)
  {
b8bc4b0aa   Johannes Berg   mac80211: support...
512
513
514
515
  	/*
  	 * First time we run, do nothing -- the generic code will
  	 * have switched to the right channel etc.
  	 */
723bae7ee   Johannes Berg   mac80211: track w...
516
  	if (!wk->started) {
e4da8c37a   Johannes Berg   mac80211: make of...
517
  		wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration);
b8bc4b0aa   Johannes Berg   mac80211: support...
518

1990ca611   Kalle Valo   mac80211: fix a w...
519
520
521
  		cfg80211_ready_on_channel(wk->sdata->dev, (unsigned long) wk,
  					  wk->chan, wk->chan_type,
  					  wk->remain.duration, GFP_KERNEL);
b8bc4b0aa   Johannes Berg   mac80211: support...
522

e4da8c37a   Johannes Berg   mac80211: make of...
523
  		return WORK_ACT_NONE;
b8bc4b0aa   Johannes Berg   mac80211: support...
524
  	}
e4da8c37a   Johannes Berg   mac80211: make of...
525
  	return WORK_ACT_TIMEOUT;
b8bc4b0aa   Johannes Berg   mac80211: support...
526
  }
e5b900d22   Johannes Berg   mac80211: allow d...
527
  static enum work_action __must_check
f30221e4e   Johannes Berg   mac80211: impleme...
528
529
530
531
532
533
534
535
  ieee80211_offchannel_tx(struct ieee80211_work *wk)
  {
  	if (!wk->started) {
  		wk->timeout = jiffies + msecs_to_jiffies(wk->offchan_tx.wait);
  
  		/*
  		 * After this, offchan_tx.frame remains but now is no
  		 * longer a valid pointer -- we still need it as the
28a1bcdb5   Johannes Berg   mac80211: fix off...
536
  		 * cookie for canceling this work/status matching.
f30221e4e   Johannes Berg   mac80211: impleme...
537
538
539
540
541
542
543
544
545
546
  		 */
  		ieee80211_tx_skb(wk->sdata, wk->offchan_tx.frame);
  
  		return WORK_ACT_NONE;
  	}
  
  	return WORK_ACT_TIMEOUT;
  }
  
  static enum work_action __must_check
e5b900d22   Johannes Berg   mac80211: allow d...
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
  ieee80211_assoc_beacon_wait(struct ieee80211_work *wk)
  {
  	if (wk->started)
  		return WORK_ACT_TIMEOUT;
  
  	/*
  	 * Wait up to one beacon interval ...
  	 * should this be more if we miss one?
  	 */
  	printk(KERN_DEBUG "%s: waiting for beacon from %pM
  ",
  	       wk->sdata->name, wk->filter_ta);
  	wk->timeout = TU_TO_EXP_TIME(wk->assoc.bss->beacon_interval);
  	return WORK_ACT_NONE;
  }
af6b63741   Johannes Berg   mac80211: general...
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
  static void ieee80211_auth_challenge(struct ieee80211_work *wk,
  				     struct ieee80211_mgmt *mgmt,
  				     size_t len)
  {
  	struct ieee80211_sub_if_data *sdata = wk->sdata;
  	u8 *pos;
  	struct ieee802_11_elems elems;
  
  	pos = mgmt->u.auth.variable;
  	ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
  	if (!elems.challenge)
  		return;
  	ieee80211_send_auth(sdata, 3, wk->probe_auth.algorithm,
  			    elems.challenge - 2, elems.challenge_len + 2,
  			    wk->filter_ta, wk->probe_auth.key,
  			    wk->probe_auth.key_len, wk->probe_auth.key_idx);
  	wk->probe_auth.transaction = 4;
  }
  
  static enum work_action __must_check
  ieee80211_rx_mgmt_auth(struct ieee80211_work *wk,
  		       struct ieee80211_mgmt *mgmt, size_t len)
  {
  	u16 auth_alg, auth_transaction, status_code;
  
  	if (wk->type != IEEE80211_WORK_AUTH)
b8d92c9c1   Johannes Berg   mac80211: don't p...
588
  		return WORK_ACT_MISMATCH;
af6b63741   Johannes Berg   mac80211: general...
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
  
  	if (len < 24 + 6)
  		return WORK_ACT_NONE;
  
  	auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
  	auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
  	status_code = le16_to_cpu(mgmt->u.auth.status_code);
  
  	if (auth_alg != wk->probe_auth.algorithm ||
  	    auth_transaction != wk->probe_auth.transaction)
  		return WORK_ACT_NONE;
  
  	if (status_code != WLAN_STATUS_SUCCESS) {
  		printk(KERN_DEBUG "%s: %pM denied authentication (status %d)
  ",
  		       wk->sdata->name, mgmt->sa, status_code);
  		return WORK_ACT_DONE;
  	}
  
  	switch (wk->probe_auth.algorithm) {
  	case WLAN_AUTH_OPEN:
  	case WLAN_AUTH_LEAP:
  	case WLAN_AUTH_FT:
  		break;
  	case WLAN_AUTH_SHARED_KEY:
  		if (wk->probe_auth.transaction != 4) {
  			ieee80211_auth_challenge(wk, mgmt, len);
  			/* need another frame */
  			return WORK_ACT_NONE;
  		}
  		break;
  	default:
  		WARN_ON(1);
  		return WORK_ACT_NONE;
  	}
  
  	printk(KERN_DEBUG "%s: authenticated
  ", wk->sdata->name);
  	return WORK_ACT_DONE;
  }
  
  static enum work_action __must_check
  ieee80211_rx_mgmt_assoc_resp(struct ieee80211_work *wk,
  			     struct ieee80211_mgmt *mgmt, size_t len,
  			     bool reassoc)
  {
  	struct ieee80211_sub_if_data *sdata = wk->sdata;
  	struct ieee80211_local *local = sdata->local;
  	u16 capab_info, status_code, aid;
  	struct ieee802_11_elems elems;
  	u8 *pos;
b8d92c9c1   Johannes Berg   mac80211: don't p...
640
641
  	if (wk->type != IEEE80211_WORK_ASSOC)
  		return WORK_ACT_MISMATCH;
af6b63741   Johannes Berg   mac80211: general...
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
  	/*
  	 * AssocResp and ReassocResp have identical structure, so process both
  	 * of them in this function.
  	 */
  
  	if (len < 24 + 6)
  		return WORK_ACT_NONE;
  
  	capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
  	status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
  	aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
  
  	printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x "
  	       "status=%d aid=%d)
  ",
  	       sdata->name, reassoc ? "Rea" : "A", mgmt->sa,
  	       capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
  
  	pos = mgmt->u.assoc_resp.variable;
  	ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
  
  	if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
  	    elems.timeout_int && elems.timeout_int_len == 5 &&
  	    elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) {
  		u32 tu, ms;
  		tu = get_unaligned_le32(elems.timeout_int + 1);
  		ms = tu * 1024 / 1000;
7d3a1c3b0   Johannes Berg   mac80211: rewrite...
669
  		printk(KERN_DEBUG "%s: %pM rejected association temporarily; "
af6b63741   Johannes Berg   mac80211: general...
670
671
  		       "comeback duration %u TU (%u ms)
  ",
7d3a1c3b0   Johannes Berg   mac80211: rewrite...
672
  		       sdata->name, mgmt->sa, tu, ms);
af6b63741   Johannes Berg   mac80211: general...
673
674
675
676
677
678
679
  		wk->timeout = jiffies + msecs_to_jiffies(ms);
  		if (ms > IEEE80211_ASSOC_TIMEOUT)
  			run_again(local, wk->timeout);
  		return WORK_ACT_NONE;
  	}
  
  	if (status_code != WLAN_STATUS_SUCCESS)
7d3a1c3b0   Johannes Berg   mac80211: rewrite...
680
681
682
  		printk(KERN_DEBUG "%s: %pM denied association (code=%d)
  ",
  		       sdata->name, mgmt->sa, status_code);
af6b63741   Johannes Berg   mac80211: general...
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
  	else
  		printk(KERN_DEBUG "%s: associated
  ", sdata->name);
  
  	return WORK_ACT_DONE;
  }
  
  static enum work_action __must_check
  ieee80211_rx_mgmt_probe_resp(struct ieee80211_work *wk,
  			     struct ieee80211_mgmt *mgmt, size_t len,
  			     struct ieee80211_rx_status *rx_status)
  {
  	struct ieee80211_sub_if_data *sdata = wk->sdata;
  	struct ieee80211_local *local = sdata->local;
  	size_t baselen;
  
  	ASSERT_WORK_MTX(local);
b8d92c9c1   Johannes Berg   mac80211: don't p...
700
701
702
703
704
  	if (wk->type != IEEE80211_WORK_DIRECT_PROBE)
  		return WORK_ACT_MISMATCH;
  
  	if (len < 24 + 12)
  		return WORK_ACT_NONE;
af6b63741   Johannes Berg   mac80211: general...
705
706
707
708
709
710
711
712
  	baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
  	if (baselen > len)
  		return WORK_ACT_NONE;
  
  	printk(KERN_DEBUG "%s: direct probe responded
  ", sdata->name);
  	return WORK_ACT_DONE;
  }
e5b900d22   Johannes Berg   mac80211: allow d...
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
  static enum work_action __must_check
  ieee80211_rx_mgmt_beacon(struct ieee80211_work *wk,
  			 struct ieee80211_mgmt *mgmt, size_t len)
  {
  	struct ieee80211_sub_if_data *sdata = wk->sdata;
  	struct ieee80211_local *local = sdata->local;
  
  	ASSERT_WORK_MTX(local);
  
  	if (wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT)
  		return WORK_ACT_MISMATCH;
  
  	if (len < 24 + 12)
  		return WORK_ACT_NONE;
  
  	printk(KERN_DEBUG "%s: beacon received
  ", sdata->name);
  	return WORK_ACT_DONE;
  }
af6b63741   Johannes Berg   mac80211: general...
732
733
734
735
736
737
  static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
  					  struct sk_buff *skb)
  {
  	struct ieee80211_rx_status *rx_status;
  	struct ieee80211_mgmt *mgmt;
  	struct ieee80211_work *wk;
021570e55   Christoph Fritz   mac80211: fix war...
738
  	enum work_action rma = WORK_ACT_NONE;
af6b63741   Johannes Berg   mac80211: general...
739
740
741
742
743
  	u16 fc;
  
  	rx_status = (struct ieee80211_rx_status *) skb->cb;
  	mgmt = (struct ieee80211_mgmt *) skb->data;
  	fc = le16_to_cpu(mgmt->frame_control);
a1699b75a   Johannes Berg   mac80211: unify s...
744
  	mutex_lock(&local->mtx);
af6b63741   Johannes Berg   mac80211: general...
745
746
747
748
749
750
751
752
  
  	list_for_each_entry(wk, &local->work_list, list) {
  		const u8 *bssid = NULL;
  
  		switch (wk->type) {
  		case IEEE80211_WORK_DIRECT_PROBE:
  		case IEEE80211_WORK_AUTH:
  		case IEEE80211_WORK_ASSOC:
e5b900d22   Johannes Berg   mac80211: allow d...
753
  		case IEEE80211_WORK_ASSOC_BEACON_WAIT:
af6b63741   Johannes Berg   mac80211: general...
754
755
756
757
758
759
760
761
762
763
764
765
766
767
  			bssid = wk->filter_ta;
  			break;
  		default:
  			continue;
  		}
  
  		/*
  		 * Before queuing, we already verified mgmt->sa,
  		 * so this is needed just for matching.
  		 */
  		if (compare_ether_addr(bssid, mgmt->bssid))
  			continue;
  
  		switch (fc & IEEE80211_FCTL_STYPE) {
e5b900d22   Johannes Berg   mac80211: allow d...
768
769
770
  		case IEEE80211_STYPE_BEACON:
  			rma = ieee80211_rx_mgmt_beacon(wk, mgmt, skb->len);
  			break;
af6b63741   Johannes Berg   mac80211: general...
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
  		case IEEE80211_STYPE_PROBE_RESP:
  			rma = ieee80211_rx_mgmt_probe_resp(wk, mgmt, skb->len,
  							   rx_status);
  			break;
  		case IEEE80211_STYPE_AUTH:
  			rma = ieee80211_rx_mgmt_auth(wk, mgmt, skb->len);
  			break;
  		case IEEE80211_STYPE_ASSOC_RESP:
  			rma = ieee80211_rx_mgmt_assoc_resp(wk, mgmt,
  							   skb->len, false);
  			break;
  		case IEEE80211_STYPE_REASSOC_RESP:
  			rma = ieee80211_rx_mgmt_assoc_resp(wk, mgmt,
  							   skb->len, true);
  			break;
  		default:
  			WARN_ON(1);
b8d92c9c1   Johannes Berg   mac80211: don't p...
788
  			rma = WORK_ACT_NONE;
af6b63741   Johannes Berg   mac80211: general...
789
  		}
b8d92c9c1   Johannes Berg   mac80211: don't p...
790
791
792
793
794
795
796
797
  
  		/*
  		 * We've either received an unexpected frame, or we have
  		 * multiple work items and need to match the frame to the
  		 * right one.
  		 */
  		if (rma == WORK_ACT_MISMATCH)
  			continue;
af6b63741   Johannes Berg   mac80211: general...
798
799
800
801
802
803
804
805
806
  		/*
  		 * We've processed this frame for that work, so it can't
  		 * belong to another work struct.
  		 * NB: this is also required for correctness for 'rma'!
  		 */
  		break;
  	}
  
  	switch (rma) {
b8d92c9c1   Johannes Berg   mac80211: don't p...
807
808
809
  	case WORK_ACT_MISMATCH:
  		/* ignore this unmatched frame */
  		break;
af6b63741   Johannes Berg   mac80211: general...
810
811
812
813
814
815
816
817
  	case WORK_ACT_NONE:
  		break;
  	case WORK_ACT_DONE:
  		list_del_rcu(&wk->list);
  		break;
  	default:
  		WARN(1, "unexpected: %d", rma);
  	}
a1699b75a   Johannes Berg   mac80211: unify s...
818
  	mutex_unlock(&local->mtx);
af6b63741   Johannes Berg   mac80211: general...
819
820
821
822
823
824
825
826
827
828
  
  	if (rma != WORK_ACT_DONE)
  		goto out;
  
  	switch (wk->done(wk, skb)) {
  	case WORK_DONE_DESTROY:
  		free_work(wk);
  		break;
  	case WORK_DONE_REQUEUE:
  		synchronize_rcu();
e4da8c37a   Johannes Berg   mac80211: make of...
829
  		wk->started = false; /* restart */
a1699b75a   Johannes Berg   mac80211: unify s...
830
  		mutex_lock(&local->mtx);
af6b63741   Johannes Berg   mac80211: general...
831
  		list_add_tail(&wk->list, &local->work_list);
a1699b75a   Johannes Berg   mac80211: unify s...
832
  		mutex_unlock(&local->mtx);
af6b63741   Johannes Berg   mac80211: general...
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
  	}
  
   out:
  	kfree_skb(skb);
  }
  
  static void ieee80211_work_timer(unsigned long data)
  {
  	struct ieee80211_local *local = (void *) data;
  
  	if (local->quiescing)
  		return;
  
  	ieee80211_queue_work(&local->hw, &local->work_work);
  }
  
  static void ieee80211_work_work(struct work_struct *work)
  {
  	struct ieee80211_local *local =
  		container_of(work, struct ieee80211_local, work_work);
  	struct sk_buff *skb;
  	struct ieee80211_work *wk, *tmp;
  	LIST_HEAD(free_work);
  	enum work_action rma;
e4da8c37a   Johannes Berg   mac80211: make of...
857
  	bool remain_off_channel = false;
af6b63741   Johannes Berg   mac80211: general...
858
859
860
861
862
863
  
  	if (local->scanning)
  		return;
  
  	/*
  	 * ieee80211_queue_work() should have picked up most cases,
77c2061d1   Walter Goldens   wireless: fix sev...
864
  	 * here we'll pick the rest.
af6b63741   Johannes Berg   mac80211: general...
865
866
867
868
869
870
871
872
  	 */
  	if (WARN(local->suspended, "work scheduled while going to suspend
  "))
  		return;
  
  	/* first process frames to avoid timing out while a frame is pending */
  	while ((skb = skb_dequeue(&local->work_skb_queue)))
  		ieee80211_work_rx_queued_mgmt(local, skb);
a1699b75a   Johannes Berg   mac80211: unify s...
873
  	mutex_lock(&local->mtx);
af6b63741   Johannes Berg   mac80211: general...
874

7da7cc1d4   Johannes Berg   mac80211: per int...
875
  	ieee80211_recalc_idle(local);
af6b63741   Johannes Berg   mac80211: general...
876
  	list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
723bae7ee   Johannes Berg   mac80211: track w...
877
  		bool started = wk->started;
e4da8c37a   Johannes Berg   mac80211: make of...
878
  		/* mark work as started if it's on the current off-channel */
723bae7ee   Johannes Berg   mac80211: track w...
879
  		if (!started && local->tmp_channel &&
e4da8c37a   Johannes Berg   mac80211: make of...
880
881
  		    wk->chan == local->tmp_channel &&
  		    wk->chan_type == local->tmp_channel_type) {
723bae7ee   Johannes Berg   mac80211: track w...
882
  			started = true;
81ac3462d   Johannes Berg   mac80211: fix a f...
883
  			wk->timeout = jiffies;
e4da8c37a   Johannes Berg   mac80211: make of...
884
  		}
723bae7ee   Johannes Berg   mac80211: track w...
885
  		if (!started && !local->tmp_channel) {
e76aadc57   Johannes Berg   mac80211: revert ...
886
  			ieee80211_offchannel_stop_vifs(local, true);
da2fd1f0f   Ben Greear   mac80211: Allow w...
887

e4da8c37a   Johannes Berg   mac80211: make of...
888
  			local->tmp_channel = wk->chan;
e76aadc57   Johannes Berg   mac80211: revert ...
889
890
891
  			local->tmp_channel_type = wk->chan_type;
  
  			ieee80211_hw_config(local, 0);
b23b025fe   Ben Greear   mac80211: Optimiz...
892

723bae7ee   Johannes Berg   mac80211: track w...
893
  			started = true;
e4da8c37a   Johannes Berg   mac80211: make of...
894
895
896
897
  			wk->timeout = jiffies;
  		}
  
  		/* don't try to work with items that aren't started */
723bae7ee   Johannes Berg   mac80211: track w...
898
  		if (!started)
e4da8c37a   Johannes Berg   mac80211: make of...
899
  			continue;
af6b63741   Johannes Berg   mac80211: general...
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
  		if (time_is_after_jiffies(wk->timeout)) {
  			/*
  			 * This work item isn't supposed to be worked on
  			 * right now, but take care to adjust the timer
  			 * properly.
  			 */
  			run_again(local, wk->timeout);
  			continue;
  		}
  
  		switch (wk->type) {
  		default:
  			WARN_ON(1);
  			/* nothing */
  			rma = WORK_ACT_NONE;
  			break;
b8bc4b0aa   Johannes Berg   mac80211: support...
916
917
  		case IEEE80211_WORK_ABORT:
  			rma = WORK_ACT_TIMEOUT;
0e0a22839   Juuso Oikarinen   mac80211: fix dir...
918
  			break;
af6b63741   Johannes Berg   mac80211: general...
919
920
921
922
923
924
925
926
927
  		case IEEE80211_WORK_DIRECT_PROBE:
  			rma = ieee80211_direct_probe(wk);
  			break;
  		case IEEE80211_WORK_AUTH:
  			rma = ieee80211_authenticate(wk);
  			break;
  		case IEEE80211_WORK_ASSOC:
  			rma = ieee80211_associate(wk);
  			break;
b8bc4b0aa   Johannes Berg   mac80211: support...
928
929
930
  		case IEEE80211_WORK_REMAIN_ON_CHANNEL:
  			rma = ieee80211_remain_on_channel_timeout(wk);
  			break;
f30221e4e   Johannes Berg   mac80211: impleme...
931
932
933
  		case IEEE80211_WORK_OFFCHANNEL_TX:
  			rma = ieee80211_offchannel_tx(wk);
  			break;
e5b900d22   Johannes Berg   mac80211: allow d...
934
935
936
  		case IEEE80211_WORK_ASSOC_BEACON_WAIT:
  			rma = ieee80211_assoc_beacon_wait(wk);
  			break;
af6b63741   Johannes Berg   mac80211: general...
937
  		}
723bae7ee   Johannes Berg   mac80211: track w...
938
  		wk->started = started;
af6b63741   Johannes Berg   mac80211: general...
939
940
  		switch (rma) {
  		case WORK_ACT_NONE:
e4da8c37a   Johannes Berg   mac80211: make of...
941
942
  			/* might have changed the timeout */
  			run_again(local, wk->timeout);
af6b63741   Johannes Berg   mac80211: general...
943
944
945
946
947
948
949
950
951
952
  			break;
  		case WORK_ACT_TIMEOUT:
  			list_del_rcu(&wk->list);
  			synchronize_rcu();
  			list_add(&wk->list, &free_work);
  			break;
  		default:
  			WARN(1, "unexpected: %d", rma);
  		}
  	}
e4da8c37a   Johannes Berg   mac80211: make of...
953
954
955
  	list_for_each_entry(wk, &local->work_list, list) {
  		if (!wk->started)
  			continue;
e76aadc57   Johannes Berg   mac80211: revert ...
956
957
  		if (wk->chan != local->tmp_channel ||
  		    wk->chan_type != local->tmp_channel_type)
e4da8c37a   Johannes Berg   mac80211: make of...
958
959
960
961
962
963
  			continue;
  		remain_off_channel = true;
  	}
  
  	if (!remain_off_channel && local->tmp_channel) {
  		local->tmp_channel = NULL;
e76aadc57   Johannes Berg   mac80211: revert ...
964
  		ieee80211_hw_config(local, 0);
b23b025fe   Ben Greear   mac80211: Optimiz...
965

e76aadc57   Johannes Berg   mac80211: revert ...
966
  		ieee80211_offchannel_return(local, true);
b23b025fe   Ben Greear   mac80211: Optimiz...
967

e4da8c37a   Johannes Berg   mac80211: make of...
968
969
970
  		/* give connection some time to breathe */
  		run_again(local, jiffies + HZ/2);
  	}
68dd5b7a4   Teemu Paasikivi   mac80211: check w...
971
972
  	if (list_empty(&local->work_list) && local->scan_req &&
  	    !local->scanning)
af6b63741   Johannes Berg   mac80211: general...
973
974
975
  		ieee80211_queue_delayed_work(&local->hw,
  					     &local->scan_work,
  					     round_jiffies_relative(0));
e4da8c37a   Johannes Berg   mac80211: make of...
976
  	ieee80211_recalc_idle(local);
7da7cc1d4   Johannes Berg   mac80211: per int...
977
  	mutex_unlock(&local->mtx);
af6b63741   Johannes Berg   mac80211: general...
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
  	list_for_each_entry_safe(wk, tmp, &free_work, list) {
  		wk->done(wk, NULL);
  		list_del(&wk->list);
  		kfree(wk);
  	}
  }
  
  void ieee80211_add_work(struct ieee80211_work *wk)
  {
  	struct ieee80211_local *local;
  
  	if (WARN_ON(!wk->chan))
  		return;
  
  	if (WARN_ON(!wk->sdata))
  		return;
  
  	if (WARN_ON(!wk->done))
  		return;
81ac3462d   Johannes Berg   mac80211: fix a f...
997
998
  	if (WARN_ON(!ieee80211_sdata_running(wk->sdata)))
  		return;
e4da8c37a   Johannes Berg   mac80211: make of...
999
  	wk->started = false;
af6b63741   Johannes Berg   mac80211: general...
1000
1001
  
  	local = wk->sdata->local;
a1699b75a   Johannes Berg   mac80211: unify s...
1002
  	mutex_lock(&local->mtx);
af6b63741   Johannes Berg   mac80211: general...
1003
  	list_add_tail(&wk->list, &local->work_list);
a1699b75a   Johannes Berg   mac80211: unify s...
1004
  	mutex_unlock(&local->mtx);
af6b63741   Johannes Berg   mac80211: general...
1005
1006
1007
1008
1009
1010
  
  	ieee80211_queue_work(&local->hw, &local->work_work);
  }
  
  void ieee80211_work_init(struct ieee80211_local *local)
  {
af6b63741   Johannes Berg   mac80211: general...
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
  	INIT_LIST_HEAD(&local->work_list);
  	setup_timer(&local->work_timer, ieee80211_work_timer,
  		    (unsigned long)local);
  	INIT_WORK(&local->work_work, ieee80211_work_work);
  	skb_queue_head_init(&local->work_skb_queue);
  }
  
  void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata)
  {
  	struct ieee80211_local *local = sdata->local;
b8bc4b0aa   Johannes Berg   mac80211: support...
1021
  	struct ieee80211_work *wk;
8808f6417   Herton Ronaldo Krzesinski   mac80211: avoid c...
1022
  	bool cleanup = false;
af6b63741   Johannes Berg   mac80211: general...
1023

a1699b75a   Johannes Berg   mac80211: unify s...
1024
  	mutex_lock(&local->mtx);
b8bc4b0aa   Johannes Berg   mac80211: support...
1025
  	list_for_each_entry(wk, &local->work_list, list) {
af6b63741   Johannes Berg   mac80211: general...
1026
1027
  		if (wk->sdata != sdata)
  			continue;
8808f6417   Herton Ronaldo Krzesinski   mac80211: avoid c...
1028
  		cleanup = true;
b8bc4b0aa   Johannes Berg   mac80211: support...
1029
  		wk->type = IEEE80211_WORK_ABORT;
e4da8c37a   Johannes Berg   mac80211: make of...
1030
1031
  		wk->started = true;
  		wk->timeout = jiffies;
b8bc4b0aa   Johannes Berg   mac80211: support...
1032
  	}
a1699b75a   Johannes Berg   mac80211: unify s...
1033
  	mutex_unlock(&local->mtx);
b8bc4b0aa   Johannes Berg   mac80211: support...
1034
1035
  
  	/* run cleanups etc. */
8808f6417   Herton Ronaldo Krzesinski   mac80211: avoid c...
1036
1037
  	if (cleanup)
  		ieee80211_work_work(&local->work_work);
b8bc4b0aa   Johannes Berg   mac80211: support...
1038

a1699b75a   Johannes Berg   mac80211: unify s...
1039
  	mutex_lock(&local->mtx);
b8bc4b0aa   Johannes Berg   mac80211: support...
1040
1041
1042
1043
1044
  	list_for_each_entry(wk, &local->work_list, list) {
  		if (wk->sdata != sdata)
  			continue;
  		WARN_ON(1);
  		break;
af6b63741   Johannes Berg   mac80211: general...
1045
  	}
a1699b75a   Johannes Berg   mac80211: unify s...
1046
  	mutex_unlock(&local->mtx);
af6b63741   Johannes Berg   mac80211: general...
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
  }
  
  ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata,
  					   struct sk_buff *skb)
  {
  	struct ieee80211_local *local = sdata->local;
  	struct ieee80211_mgmt *mgmt;
  	struct ieee80211_work *wk;
  	u16 fc;
  
  	if (skb->len < 24)
  		return RX_DROP_MONITOR;
  
  	mgmt = (struct ieee80211_mgmt *) skb->data;
  	fc = le16_to_cpu(mgmt->frame_control);
  
  	list_for_each_entry_rcu(wk, &local->work_list, list) {
  		if (sdata != wk->sdata)
  			continue;
  		if (compare_ether_addr(wk->filter_ta, mgmt->sa))
  			continue;
  		if (compare_ether_addr(wk->filter_ta, mgmt->bssid))
  			continue;
  
  		switch (fc & IEEE80211_FCTL_STYPE) {
  		case IEEE80211_STYPE_AUTH:
  		case IEEE80211_STYPE_PROBE_RESP:
  		case IEEE80211_STYPE_ASSOC_RESP:
  		case IEEE80211_STYPE_REASSOC_RESP:
e5b900d22   Johannes Berg   mac80211: allow d...
1076
  		case IEEE80211_STYPE_BEACON:
af6b63741   Johannes Berg   mac80211: general...
1077
1078
1079
1080
1081
1082
1083
1084
  			skb_queue_tail(&local->work_skb_queue, skb);
  			ieee80211_queue_work(&local->hw, &local->work_work);
  			return RX_QUEUED;
  		}
  	}
  
  	return RX_CONTINUE;
  }
b8bc4b0aa   Johannes Berg   mac80211: support...
1085

e4da8c37a   Johannes Berg   mac80211: make of...
1086
1087
1088
1089
1090
1091
  static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk,
  						   struct sk_buff *skb)
  {
  	/*
  	 * We are done serving the remain-on-channel command.
  	 */
1990ca611   Kalle Valo   mac80211: fix a w...
1092
  	cfg80211_remain_on_channel_expired(wk->sdata->dev, (unsigned long) wk,
e4da8c37a   Johannes Berg   mac80211: make of...
1093
1094
1095
1096
1097
  					   wk->chan, wk->chan_type,
  					   GFP_KERNEL);
  
  	return WORK_DONE_DESTROY;
  }
b8bc4b0aa   Johannes Berg   mac80211: support...
1098
1099
1100
1101
1102
  int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
  				   struct ieee80211_channel *chan,
  				   enum nl80211_channel_type channel_type,
  				   unsigned int duration, u64 *cookie)
  {
b8bc4b0aa   Johannes Berg   mac80211: support...
1103
1104
1105
1106
1107
1108
1109
1110
  	struct ieee80211_work *wk;
  
  	wk = kzalloc(sizeof(*wk), GFP_KERNEL);
  	if (!wk)
  		return -ENOMEM;
  
  	wk->type = IEEE80211_WORK_REMAIN_ON_CHANNEL;
  	wk->chan = chan;
e4da8c37a   Johannes Berg   mac80211: make of...
1111
  	wk->chan_type = channel_type;
b8bc4b0aa   Johannes Berg   mac80211: support...
1112
  	wk->sdata = sdata;
e4da8c37a   Johannes Berg   mac80211: make of...
1113
  	wk->done = ieee80211_remain_done;
b8bc4b0aa   Johannes Berg   mac80211: support...
1114

e4da8c37a   Johannes Berg   mac80211: make of...
1115
  	wk->remain.duration = duration;
b8bc4b0aa   Johannes Berg   mac80211: support...
1116

1990ca611   Kalle Valo   mac80211: fix a w...
1117
  	*cookie = (unsigned long) wk;
b8bc4b0aa   Johannes Berg   mac80211: support...
1118
1119
  
  	ieee80211_add_work(wk);
b8bc4b0aa   Johannes Berg   mac80211: support...
1120
1121
1122
1123
1124
1125
1126
1127
1128
  	return 0;
  }
  
  int ieee80211_wk_cancel_remain_on_channel(struct ieee80211_sub_if_data *sdata,
  					  u64 cookie)
  {
  	struct ieee80211_local *local = sdata->local;
  	struct ieee80211_work *wk, *tmp;
  	bool found = false;
a1699b75a   Johannes Berg   mac80211: unify s...
1129
  	mutex_lock(&local->mtx);
b8bc4b0aa   Johannes Berg   mac80211: support...
1130
  	list_for_each_entry_safe(wk, tmp, &local->work_list, list) {
1990ca611   Kalle Valo   mac80211: fix a w...
1131
  		if ((unsigned long) wk == cookie) {
e4da8c37a   Johannes Berg   mac80211: make of...
1132
  			wk->timeout = jiffies;
b8bc4b0aa   Johannes Berg   mac80211: support...
1133
  			found = true;
b8bc4b0aa   Johannes Berg   mac80211: support...
1134
1135
1136
  			break;
  		}
  	}
a1699b75a   Johannes Berg   mac80211: unify s...
1137
  	mutex_unlock(&local->mtx);
b8bc4b0aa   Johannes Berg   mac80211: support...
1138
1139
1140
  
  	if (!found)
  		return -ENOENT;
e4da8c37a   Johannes Berg   mac80211: make of...
1141
  	ieee80211_queue_work(&local->hw, &local->work_work);
b8bc4b0aa   Johannes Berg   mac80211: support...
1142
1143
1144
  
  	return 0;
  }