aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/work.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-01-20 07:55:27 -0500
committerJohn W. Linville <linville@tuxdriver.com>2012-02-06 14:50:37 -0500
commit66e67e418908442389d3a9e6509985f01cbaf9b0 (patch)
tree01fad87d0d47f5887497c569d98cee20fa1f0f29 /net/mac80211/work.c
parent4c0c0b75e0c35ddb8f61c06bcbffede63ab4f4a2 (diff)
mac80211: redesign auth/assoc
This is the second part of the auth/assoc redesign, the mac80211 part. This moves the auth/assoc code out of the work abstraction and into the MLME, so that we don't flip channels all the time etc. The only downside is that when we are associated, we need to drop the association in order to create a connection to another AP, but for most drivers this is actually desirable and the ability to do was never used by any applications. If we want to implement resource reservation with FT-OTA, we'd probably best do it with explicit R-O-C in wpa_s. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/work.c')
-rw-r--r--net/mac80211/work.c815
1 files changed, 0 insertions, 815 deletions
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index 0a1a176fbe9..c6e230efa04 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -27,16 +27,9 @@
27#include "rate.h" 27#include "rate.h"
28#include "driver-ops.h" 28#include "driver-ops.h"
29 29
30#define IEEE80211_AUTH_TIMEOUT (HZ / 5)
31#define IEEE80211_AUTH_MAX_TRIES 3
32#define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
33#define IEEE80211_ASSOC_MAX_TRIES 3
34
35enum work_action { 30enum work_action {
36 WORK_ACT_MISMATCH,
37 WORK_ACT_NONE, 31 WORK_ACT_NONE,
38 WORK_ACT_TIMEOUT, 32 WORK_ACT_TIMEOUT,
39 WORK_ACT_DONE,
40}; 33};
41 34
42 35
@@ -71,465 +64,6 @@ void free_work(struct ieee80211_work *wk)
71 kfree_rcu(wk, rcu_head); 64 kfree_rcu(wk, rcu_head);
72} 65}
73 66
74static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
75 struct ieee80211_supported_band *sband,
76 u32 *rates)
77{
78 int i, j, count;
79 *rates = 0;
80 count = 0;
81 for (i = 0; i < supp_rates_len; i++) {
82 int rate = (supp_rates[i] & 0x7F) * 5;
83
84 for (j = 0; j < sband->n_bitrates; j++)
85 if (sband->bitrates[j].bitrate == rate) {
86 *rates |= BIT(j);
87 count++;
88 break;
89 }
90 }
91
92 return count;
93}
94
95/* frame sending functions */
96
97static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
98 struct sk_buff *skb, const u8 *ht_info_ie,
99 struct ieee80211_supported_band *sband,
100 struct ieee80211_channel *channel,
101 enum ieee80211_smps_mode smps)
102{
103 struct ieee80211_ht_info *ht_info;
104 u8 *pos;
105 u32 flags = channel->flags;
106 u16 cap;
107 struct ieee80211_sta_ht_cap ht_cap;
108
109 BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap));
110
111 if (!sband->ht_cap.ht_supported)
112 return;
113
114 if (!ht_info_ie)
115 return;
116
117 if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info))
118 return;
119
120 memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
121 ieee80211_apply_htcap_overrides(sdata, &ht_cap);
122
123 ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2);
124
125 /* determine capability flags */
126 cap = ht_cap.cap;
127
128 switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
129 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
130 if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
131 cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
132 cap &= ~IEEE80211_HT_CAP_SGI_40;
133 }
134 break;
135 case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
136 if (flags & IEEE80211_CHAN_NO_HT40MINUS) {
137 cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
138 cap &= ~IEEE80211_HT_CAP_SGI_40;
139 }
140 break;
141 }
142
143 /* set SM PS mode properly */
144 cap &= ~IEEE80211_HT_CAP_SM_PS;
145 switch (smps) {
146 case IEEE80211_SMPS_AUTOMATIC:
147 case IEEE80211_SMPS_NUM_MODES:
148 WARN_ON(1);
149 case IEEE80211_SMPS_OFF:
150 cap |= WLAN_HT_CAP_SM_PS_DISABLED <<
151 IEEE80211_HT_CAP_SM_PS_SHIFT;
152 break;
153 case IEEE80211_SMPS_STATIC:
154 cap |= WLAN_HT_CAP_SM_PS_STATIC <<
155 IEEE80211_HT_CAP_SM_PS_SHIFT;
156 break;
157 case IEEE80211_SMPS_DYNAMIC:
158 cap |= WLAN_HT_CAP_SM_PS_DYNAMIC <<
159 IEEE80211_HT_CAP_SM_PS_SHIFT;
160 break;
161 }
162
163 /* reserve and fill IE */
164 pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
165 ieee80211_ie_build_ht_cap(pos, &ht_cap, cap);
166}
167
168static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
169 struct ieee80211_work *wk)
170{
171 struct ieee80211_local *local = sdata->local;
172 struct sk_buff *skb;
173 struct ieee80211_mgmt *mgmt;
174 u8 *pos, qos_info;
175 size_t offset = 0, noffset;
176 int i, count, rates_len, supp_rates_len;
177 u16 capab;
178 struct ieee80211_supported_band *sband;
179 u32 rates = 0;
180
181 sband = local->hw.wiphy->bands[wk->chan->band];
182
183 if (wk->assoc.supp_rates_len) {
184 /*
185 * Get all rates supported by the device and the AP as
186 * some APs don't like getting a superset of their rates
187 * in the association request (e.g. D-Link DAP 1353 in
188 * b-only mode)...
189 */
190 rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates,
191 wk->assoc.supp_rates_len,
192 sband, &rates);
193 } else {
194 /*
195 * In case AP not provide any supported rates information
196 * before association, we send information element(s) with
197 * all rates that we support.
198 */
199 rates = ~0;
200 rates_len = sband->n_bitrates;
201 }
202
203 skb = alloc_skb(local->hw.extra_tx_headroom +
204 sizeof(*mgmt) + /* bit too much but doesn't matter */
205 2 + wk->assoc.ssid_len + /* SSID */
206 4 + rates_len + /* (extended) rates */
207 4 + /* power capability */
208 2 + 2 * sband->n_channels + /* supported channels */
209 2 + sizeof(struct ieee80211_ht_cap) + /* HT */
210 wk->ie_len + /* extra IEs */
211 9, /* WMM */
212 GFP_KERNEL);
213 if (!skb)
214 return;
215
216 skb_reserve(skb, local->hw.extra_tx_headroom);
217
218 capab = WLAN_CAPABILITY_ESS;
219
220 if (sband->band == IEEE80211_BAND_2GHZ) {
221 if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
222 capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
223 if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
224 capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
225 }
226
227 if (wk->assoc.capability & WLAN_CAPABILITY_PRIVACY)
228 capab |= WLAN_CAPABILITY_PRIVACY;
229
230 if ((wk->assoc.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
231 (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
232 capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
233
234 mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
235 memset(mgmt, 0, 24);
236 memcpy(mgmt->da, wk->filter_ta, ETH_ALEN);
237 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
238 memcpy(mgmt->bssid, wk->filter_ta, ETH_ALEN);
239
240 if (!is_zero_ether_addr(wk->assoc.prev_bssid)) {
241 skb_put(skb, 10);
242 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
243 IEEE80211_STYPE_REASSOC_REQ);
244 mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);
245 mgmt->u.reassoc_req.listen_interval =
246 cpu_to_le16(local->hw.conf.listen_interval);
247 memcpy(mgmt->u.reassoc_req.current_ap, wk->assoc.prev_bssid,
248 ETH_ALEN);
249 } else {
250 skb_put(skb, 4);
251 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
252 IEEE80211_STYPE_ASSOC_REQ);
253 mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
254 mgmt->u.assoc_req.listen_interval =
255 cpu_to_le16(local->hw.conf.listen_interval);
256 }
257
258 /* SSID */
259 pos = skb_put(skb, 2 + wk->assoc.ssid_len);
260 *pos++ = WLAN_EID_SSID;
261 *pos++ = wk->assoc.ssid_len;
262 memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len);
263
264 /* add all rates which were marked to be used above */
265 supp_rates_len = rates_len;
266 if (supp_rates_len > 8)
267 supp_rates_len = 8;
268
269 pos = skb_put(skb, supp_rates_len + 2);
270 *pos++ = WLAN_EID_SUPP_RATES;
271 *pos++ = supp_rates_len;
272
273 count = 0;
274 for (i = 0; i < sband->n_bitrates; i++) {
275 if (BIT(i) & rates) {
276 int rate = sband->bitrates[i].bitrate;
277 *pos++ = (u8) (rate / 5);
278 if (++count == 8)
279 break;
280 }
281 }
282
283 if (rates_len > count) {
284 pos = skb_put(skb, rates_len - count + 2);
285 *pos++ = WLAN_EID_EXT_SUPP_RATES;
286 *pos++ = rates_len - count;
287
288 for (i++; i < sband->n_bitrates; i++) {
289 if (BIT(i) & rates) {
290 int rate = sband->bitrates[i].bitrate;
291 *pos++ = (u8) (rate / 5);
292 }
293 }
294 }
295
296 if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) {
297 /* 1. power capabilities */
298 pos = skb_put(skb, 4);
299 *pos++ = WLAN_EID_PWR_CAPABILITY;
300 *pos++ = 2;
301 *pos++ = 0; /* min tx power */
302 *pos++ = wk->chan->max_power; /* max tx power */
303
304 /* 2. supported channels */
305 /* TODO: get this in reg domain format */
306 pos = skb_put(skb, 2 * sband->n_channels + 2);
307 *pos++ = WLAN_EID_SUPPORTED_CHANNELS;
308 *pos++ = 2 * sband->n_channels;
309 for (i = 0; i < sband->n_channels; i++) {
310 *pos++ = ieee80211_frequency_to_channel(
311 sband->channels[i].center_freq);
312 *pos++ = 1; /* one channel in the subband*/
313 }
314 }
315
316 /* if present, add any custom IEs that go before HT */
317 if (wk->ie_len && wk->ie) {
318 static const u8 before_ht[] = {
319 WLAN_EID_SSID,
320 WLAN_EID_SUPP_RATES,
321 WLAN_EID_EXT_SUPP_RATES,
322 WLAN_EID_PWR_CAPABILITY,
323 WLAN_EID_SUPPORTED_CHANNELS,
324 WLAN_EID_RSN,
325 WLAN_EID_QOS_CAPA,
326 WLAN_EID_RRM_ENABLED_CAPABILITIES,
327 WLAN_EID_MOBILITY_DOMAIN,
328 WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
329 };
330 noffset = ieee80211_ie_split(wk->ie, wk->ie_len,
331 before_ht, ARRAY_SIZE(before_ht),
332 offset);
333 pos = skb_put(skb, noffset - offset);
334 memcpy(pos, wk->ie + offset, noffset - offset);
335 offset = noffset;
336 }
337
338 if (wk->assoc.use_11n && wk->assoc.wmm_used &&
339 local->hw.queues >= 4)
340 ieee80211_add_ht_ie(sdata, skb, wk->assoc.ht_information_ie,
341 sband, wk->chan, wk->assoc.smps);
342
343 /* if present, add any custom non-vendor IEs that go after HT */
344 if (wk->ie_len && wk->ie) {
345 noffset = ieee80211_ie_split_vendor(wk->ie, wk->ie_len,
346 offset);
347 pos = skb_put(skb, noffset - offset);
348 memcpy(pos, wk->ie + offset, noffset - offset);
349 offset = noffset;
350 }
351
352 if (wk->assoc.wmm_used && local->hw.queues >= 4) {
353 if (wk->assoc.uapsd_used) {
354 qos_info = local->uapsd_queues;
355 qos_info |= (local->uapsd_max_sp_len <<
356 IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT);
357 } else {
358 qos_info = 0;
359 }
360
361 pos = skb_put(skb, 9);
362 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
363 *pos++ = 7; /* len */
364 *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
365 *pos++ = 0x50;
366 *pos++ = 0xf2;
367 *pos++ = 2; /* WME */
368 *pos++ = 0; /* WME info */
369 *pos++ = 1; /* WME ver */
370 *pos++ = qos_info;
371 }
372
373 /* add any remaining custom (i.e. vendor specific here) IEs */
374 if (wk->ie_len && wk->ie) {
375 noffset = wk->ie_len;
376 pos = skb_put(skb, noffset - offset);
377 memcpy(pos, wk->ie + offset, noffset - offset);
378 }
379
380 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
381 ieee80211_tx_skb(sdata, skb);
382}
383
384static void ieee80211_remove_auth_bss(struct ieee80211_local *local,
385 struct ieee80211_work *wk)
386{
387 struct cfg80211_bss *cbss;
388 u16 capa_val = WLAN_CAPABILITY_ESS;
389
390 if (wk->probe_auth.privacy)
391 capa_val |= WLAN_CAPABILITY_PRIVACY;
392
393 cbss = cfg80211_get_bss(local->hw.wiphy, wk->chan, wk->filter_ta,
394 wk->probe_auth.ssid, wk->probe_auth.ssid_len,
395 WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY,
396 capa_val);
397 if (!cbss)
398 return;
399
400 cfg80211_unlink_bss(local->hw.wiphy, cbss);
401 cfg80211_put_bss(cbss);
402}
403
404static enum work_action __must_check
405ieee80211_direct_probe(struct ieee80211_work *wk)
406{
407 struct ieee80211_sub_if_data *sdata = wk->sdata;
408 struct ieee80211_local *local = sdata->local;
409
410 if (!wk->probe_auth.synced) {
411 int ret = drv_tx_sync(local, sdata, wk->filter_ta,
412 IEEE80211_TX_SYNC_AUTH);
413 if (ret)
414 return WORK_ACT_TIMEOUT;
415 }
416 wk->probe_auth.synced = true;
417
418 wk->probe_auth.tries++;
419 if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) {
420 printk(KERN_DEBUG "%s: direct probe to %pM timed out\n",
421 sdata->name, wk->filter_ta);
422
423 /*
424 * Most likely AP is not in the range so remove the
425 * bss struct for that AP.
426 */
427 ieee80211_remove_auth_bss(local, wk);
428
429 return WORK_ACT_TIMEOUT;
430 }
431
432 printk(KERN_DEBUG "%s: direct probe to %pM (try %d/%i)\n",
433 sdata->name, wk->filter_ta, wk->probe_auth.tries,
434 IEEE80211_AUTH_MAX_TRIES);
435
436 /*
437 * Direct probe is sent to broadcast address as some APs
438 * will not answer to direct packet in unassociated state.
439 */
440 ieee80211_send_probe_req(sdata, NULL, wk->probe_auth.ssid,
441 wk->probe_auth.ssid_len, NULL, 0,
442 (u32) -1, true, false);
443
444 wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
445 run_again(local, wk->timeout);
446
447 return WORK_ACT_NONE;
448}
449
450
451static enum work_action __must_check
452ieee80211_authenticate(struct ieee80211_work *wk)
453{
454 struct ieee80211_sub_if_data *sdata = wk->sdata;
455 struct ieee80211_local *local = sdata->local;
456
457 if (!wk->probe_auth.synced) {
458 int ret = drv_tx_sync(local, sdata, wk->filter_ta,
459 IEEE80211_TX_SYNC_AUTH);
460 if (ret)
461 return WORK_ACT_TIMEOUT;
462 }
463 wk->probe_auth.synced = true;
464
465 wk->probe_auth.tries++;
466 if (wk->probe_auth.tries > IEEE80211_AUTH_MAX_TRIES) {
467 printk(KERN_DEBUG "%s: authentication with %pM"
468 " timed out\n", sdata->name, wk->filter_ta);
469
470 /*
471 * Most likely AP is not in the range so remove the
472 * bss struct for that AP.
473 */
474 ieee80211_remove_auth_bss(local, wk);
475
476 return WORK_ACT_TIMEOUT;
477 }
478
479 printk(KERN_DEBUG "%s: authenticate with %pM (try %d)\n",
480 sdata->name, wk->filter_ta, wk->probe_auth.tries);
481
482 ieee80211_send_auth(sdata, 1, wk->probe_auth.algorithm, wk->ie,
483 wk->ie_len, wk->filter_ta, wk->filter_ta, NULL, 0,
484 0);
485 wk->probe_auth.transaction = 2;
486
487 wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
488 run_again(local, wk->timeout);
489
490 return WORK_ACT_NONE;
491}
492
493static enum work_action __must_check
494ieee80211_associate(struct ieee80211_work *wk)
495{
496 struct ieee80211_sub_if_data *sdata = wk->sdata;
497 struct ieee80211_local *local = sdata->local;
498
499 if (!wk->assoc.synced) {
500 int ret = drv_tx_sync(local, sdata, wk->filter_ta,
501 IEEE80211_TX_SYNC_ASSOC);
502 if (ret)
503 return WORK_ACT_TIMEOUT;
504 }
505 wk->assoc.synced = true;
506
507 wk->assoc.tries++;
508 if (wk->assoc.tries > IEEE80211_ASSOC_MAX_TRIES) {
509 printk(KERN_DEBUG "%s: association with %pM"
510 " timed out\n",
511 sdata->name, wk->filter_ta);
512
513 /*
514 * Most likely AP is not in the range so remove the
515 * bss struct for that AP.
516 */
517 if (wk->assoc.bss)
518 cfg80211_unlink_bss(local->hw.wiphy, wk->assoc.bss);
519
520 return WORK_ACT_TIMEOUT;
521 }
522
523 printk(KERN_DEBUG "%s: associate with %pM (try %d)\n",
524 sdata->name, wk->filter_ta, wk->assoc.tries);
525 ieee80211_send_assoc(sdata, wk);
526
527 wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
528 run_again(local, wk->timeout);
529
530 return WORK_ACT_NONE;
531}
532
533static enum work_action __must_check 67static enum work_action __must_check
534ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk) 68ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk)
535{ 69{
@@ -569,300 +103,6 @@ ieee80211_offchannel_tx(struct ieee80211_work *wk)
569 return WORK_ACT_TIMEOUT; 103 return WORK_ACT_TIMEOUT;
570} 104}
571 105
572static enum work_action __must_check
573ieee80211_assoc_beacon_wait(struct ieee80211_work *wk)
574{
575 if (wk->started)
576 return WORK_ACT_TIMEOUT;
577
578 /*
579 * Wait up to one beacon interval ...
580 * should this be more if we miss one?
581 */
582 printk(KERN_DEBUG "%s: waiting for beacon from %pM\n",
583 wk->sdata->name, wk->filter_ta);
584 wk->timeout = TU_TO_EXP_TIME(wk->assoc.bss->beacon_interval);
585 return WORK_ACT_NONE;
586}
587
588static void ieee80211_auth_challenge(struct ieee80211_work *wk,
589 struct ieee80211_mgmt *mgmt,
590 size_t len)
591{
592 struct ieee80211_sub_if_data *sdata = wk->sdata;
593 u8 *pos;
594 struct ieee802_11_elems elems;
595
596 pos = mgmt->u.auth.variable;
597 ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
598 if (!elems.challenge)
599 return;
600 ieee80211_send_auth(sdata, 3, wk->probe_auth.algorithm,
601 elems.challenge - 2, elems.challenge_len + 2,
602 wk->filter_ta, wk->filter_ta, wk->probe_auth.key,
603 wk->probe_auth.key_len, wk->probe_auth.key_idx);
604 wk->probe_auth.transaction = 4;
605}
606
607static enum work_action __must_check
608ieee80211_rx_mgmt_auth(struct ieee80211_work *wk,
609 struct ieee80211_mgmt *mgmt, size_t len)
610{
611 u16 auth_alg, auth_transaction, status_code;
612
613 if (wk->type != IEEE80211_WORK_AUTH)
614 return WORK_ACT_MISMATCH;
615
616 if (len < 24 + 6)
617 return WORK_ACT_NONE;
618
619 auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
620 auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
621 status_code = le16_to_cpu(mgmt->u.auth.status_code);
622
623 if (auth_alg != wk->probe_auth.algorithm ||
624 auth_transaction != wk->probe_auth.transaction)
625 return WORK_ACT_NONE;
626
627 if (status_code != WLAN_STATUS_SUCCESS) {
628 printk(KERN_DEBUG "%s: %pM denied authentication (status %d)\n",
629 wk->sdata->name, mgmt->sa, status_code);
630 return WORK_ACT_DONE;
631 }
632
633 switch (wk->probe_auth.algorithm) {
634 case WLAN_AUTH_OPEN:
635 case WLAN_AUTH_LEAP:
636 case WLAN_AUTH_FT:
637 break;
638 case WLAN_AUTH_SHARED_KEY:
639 if (wk->probe_auth.transaction != 4) {
640 ieee80211_auth_challenge(wk, mgmt, len);
641 /* need another frame */
642 return WORK_ACT_NONE;
643 }
644 break;
645 default:
646 WARN_ON(1);
647 return WORK_ACT_NONE;
648 }
649
650 printk(KERN_DEBUG "%s: authenticated\n", wk->sdata->name);
651 return WORK_ACT_DONE;
652}
653
654static enum work_action __must_check
655ieee80211_rx_mgmt_assoc_resp(struct ieee80211_work *wk,
656 struct ieee80211_mgmt *mgmt, size_t len,
657 bool reassoc)
658{
659 struct ieee80211_sub_if_data *sdata = wk->sdata;
660 struct ieee80211_local *local = sdata->local;
661 u16 capab_info, status_code, aid;
662 struct ieee802_11_elems elems;
663 u8 *pos;
664
665 if (wk->type != IEEE80211_WORK_ASSOC)
666 return WORK_ACT_MISMATCH;
667
668 /*
669 * AssocResp and ReassocResp have identical structure, so process both
670 * of them in this function.
671 */
672
673 if (len < 24 + 6)
674 return WORK_ACT_NONE;
675
676 capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
677 status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
678 aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
679
680 printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x "
681 "status=%d aid=%d)\n",
682 sdata->name, reassoc ? "Rea" : "A", mgmt->sa,
683 capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
684
685 pos = mgmt->u.assoc_resp.variable;
686 ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
687
688 if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
689 elems.timeout_int && elems.timeout_int_len == 5 &&
690 elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) {
691 u32 tu, ms;
692 tu = get_unaligned_le32(elems.timeout_int + 1);
693 ms = tu * 1024 / 1000;
694 printk(KERN_DEBUG "%s: %pM rejected association temporarily; "
695 "comeback duration %u TU (%u ms)\n",
696 sdata->name, mgmt->sa, tu, ms);
697 wk->timeout = jiffies + msecs_to_jiffies(ms);
698 if (ms > IEEE80211_ASSOC_TIMEOUT)
699 run_again(local, wk->timeout);
700 return WORK_ACT_NONE;
701 }
702
703 if (status_code != WLAN_STATUS_SUCCESS)
704 printk(KERN_DEBUG "%s: %pM denied association (code=%d)\n",
705 sdata->name, mgmt->sa, status_code);
706 else
707 printk(KERN_DEBUG "%s: associated\n", sdata->name);
708
709 return WORK_ACT_DONE;
710}
711
712static enum work_action __must_check
713ieee80211_rx_mgmt_probe_resp(struct ieee80211_work *wk,
714 struct ieee80211_mgmt *mgmt, size_t len,
715 struct ieee80211_rx_status *rx_status)
716{
717 struct ieee80211_sub_if_data *sdata = wk->sdata;
718 struct ieee80211_local *local = sdata->local;
719 size_t baselen;
720
721 ASSERT_WORK_MTX(local);
722
723 if (wk->type != IEEE80211_WORK_DIRECT_PROBE)
724 return WORK_ACT_MISMATCH;
725
726 if (len < 24 + 12)
727 return WORK_ACT_NONE;
728
729 baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
730 if (baselen > len)
731 return WORK_ACT_NONE;
732
733 printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name);
734 return WORK_ACT_DONE;
735}
736
737static enum work_action __must_check
738ieee80211_rx_mgmt_beacon(struct ieee80211_work *wk,
739 struct ieee80211_mgmt *mgmt, size_t len)
740{
741 struct ieee80211_sub_if_data *sdata = wk->sdata;
742 struct ieee80211_local *local = sdata->local;
743
744 ASSERT_WORK_MTX(local);
745
746 if (wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT)
747 return WORK_ACT_MISMATCH;
748
749 if (len < 24 + 12)
750 return WORK_ACT_NONE;
751
752 printk(KERN_DEBUG "%s: beacon received\n", sdata->name);
753 return WORK_ACT_DONE;
754}
755
756static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
757 struct sk_buff *skb)
758{
759 struct ieee80211_rx_status *rx_status;
760 struct ieee80211_mgmt *mgmt;
761 struct ieee80211_work *wk;
762 enum work_action rma = WORK_ACT_NONE;
763 u16 fc;
764
765 rx_status = (struct ieee80211_rx_status *) skb->cb;
766 mgmt = (struct ieee80211_mgmt *) skb->data;
767 fc = le16_to_cpu(mgmt->frame_control);
768
769 mutex_lock(&local->mtx);
770
771 list_for_each_entry(wk, &local->work_list, list) {
772 const u8 *bssid = NULL;
773
774 switch (wk->type) {
775 case IEEE80211_WORK_DIRECT_PROBE:
776 case IEEE80211_WORK_AUTH:
777 case IEEE80211_WORK_ASSOC:
778 case IEEE80211_WORK_ASSOC_BEACON_WAIT:
779 bssid = wk->filter_ta;
780 break;
781 default:
782 continue;
783 }
784
785 /*
786 * Before queuing, we already verified mgmt->sa,
787 * so this is needed just for matching.
788 */
789 if (compare_ether_addr(bssid, mgmt->bssid))
790 continue;
791
792 switch (fc & IEEE80211_FCTL_STYPE) {
793 case IEEE80211_STYPE_BEACON:
794 rma = ieee80211_rx_mgmt_beacon(wk, mgmt, skb->len);
795 break;
796 case IEEE80211_STYPE_PROBE_RESP:
797 rma = ieee80211_rx_mgmt_probe_resp(wk, mgmt, skb->len,
798 rx_status);
799 break;
800 case IEEE80211_STYPE_AUTH:
801 rma = ieee80211_rx_mgmt_auth(wk, mgmt, skb->len);
802 break;
803 case IEEE80211_STYPE_ASSOC_RESP:
804 rma = ieee80211_rx_mgmt_assoc_resp(wk, mgmt,
805 skb->len, false);
806 break;
807 case IEEE80211_STYPE_REASSOC_RESP:
808 rma = ieee80211_rx_mgmt_assoc_resp(wk, mgmt,
809 skb->len, true);
810 break;
811 default:
812 WARN_ON(1);
813 rma = WORK_ACT_NONE;
814 }
815
816 /*
817 * We've either received an unexpected frame, or we have
818 * multiple work items and need to match the frame to the
819 * right one.
820 */
821 if (rma == WORK_ACT_MISMATCH)
822 continue;
823
824 /*
825 * We've processed this frame for that work, so it can't
826 * belong to another work struct.
827 * NB: this is also required for correctness for 'rma'!
828 */
829 break;
830 }
831
832 switch (rma) {
833 case WORK_ACT_MISMATCH:
834 /* ignore this unmatched frame */
835 break;
836 case WORK_ACT_NONE:
837 break;
838 case WORK_ACT_DONE:
839 list_del_rcu(&wk->list);
840 break;
841 default:
842 WARN(1, "unexpected: %d", rma);
843 }
844
845 mutex_unlock(&local->mtx);
846
847 if (rma != WORK_ACT_DONE)
848 goto out;
849
850 switch (wk->done(wk, skb)) {
851 case WORK_DONE_DESTROY:
852 free_work(wk);
853 break;
854 case WORK_DONE_REQUEUE:
855 synchronize_rcu();
856 wk->started = false; /* restart */
857 mutex_lock(&local->mtx);
858 list_add_tail(&wk->list, &local->work_list);
859 mutex_unlock(&local->mtx);
860 }
861
862 out:
863 kfree_skb(skb);
864}
865
866static void ieee80211_work_timer(unsigned long data) 106static void ieee80211_work_timer(unsigned long data)
867{ 107{
868 struct ieee80211_local *local = (void *) data; 108 struct ieee80211_local *local = (void *) data;
@@ -877,7 +117,6 @@ static void ieee80211_work_work(struct work_struct *work)
877{ 117{
878 struct ieee80211_local *local = 118 struct ieee80211_local *local =
879 container_of(work, struct ieee80211_local, work_work); 119 container_of(work, struct ieee80211_local, work_work);
880 struct sk_buff *skb;
881 struct ieee80211_work *wk, *tmp; 120 struct ieee80211_work *wk, *tmp;
882 LIST_HEAD(free_work); 121 LIST_HEAD(free_work);
883 enum work_action rma; 122 enum work_action rma;
@@ -893,10 +132,6 @@ static void ieee80211_work_work(struct work_struct *work)
893 if (WARN(local->suspended, "work scheduled while going to suspend\n")) 132 if (WARN(local->suspended, "work scheduled while going to suspend\n"))
894 return; 133 return;
895 134
896 /* first process frames to avoid timing out while a frame is pending */
897 while ((skb = skb_dequeue(&local->work_skb_queue)))
898 ieee80211_work_rx_queued_mgmt(local, skb);
899
900 mutex_lock(&local->mtx); 135 mutex_lock(&local->mtx);
901 136
902 ieee80211_recalc_idle(local); 137 ieee80211_recalc_idle(local);
@@ -947,24 +182,12 @@ static void ieee80211_work_work(struct work_struct *work)
947 case IEEE80211_WORK_ABORT: 182 case IEEE80211_WORK_ABORT:
948 rma = WORK_ACT_TIMEOUT; 183 rma = WORK_ACT_TIMEOUT;
949 break; 184 break;
950 case IEEE80211_WORK_DIRECT_PROBE:
951 rma = ieee80211_direct_probe(wk);
952 break;
953 case IEEE80211_WORK_AUTH:
954 rma = ieee80211_authenticate(wk);
955 break;
956 case IEEE80211_WORK_ASSOC:
957 rma = ieee80211_associate(wk);
958 break;
959 case IEEE80211_WORK_REMAIN_ON_CHANNEL: 185 case IEEE80211_WORK_REMAIN_ON_CHANNEL:
960 rma = ieee80211_remain_on_channel_timeout(wk); 186 rma = ieee80211_remain_on_channel_timeout(wk);
961 break; 187 break;
962 case IEEE80211_WORK_OFFCHANNEL_TX: 188 case IEEE80211_WORK_OFFCHANNEL_TX:
963 rma = ieee80211_offchannel_tx(wk); 189 rma = ieee80211_offchannel_tx(wk);
964 break; 190 break;
965 case IEEE80211_WORK_ASSOC_BEACON_WAIT:
966 rma = ieee80211_assoc_beacon_wait(wk);
967 break;
968 } 191 }
969 192
970 wk->started = started; 193 wk->started = started;
@@ -1052,7 +275,6 @@ void ieee80211_work_init(struct ieee80211_local *local)
1052 setup_timer(&local->work_timer, ieee80211_work_timer, 275 setup_timer(&local->work_timer, ieee80211_work_timer,
1053 (unsigned long)local); 276 (unsigned long)local);
1054 INIT_WORK(&local->work_work, ieee80211_work_work); 277 INIT_WORK(&local->work_work, ieee80211_work_work);
1055 skb_queue_head_init(&local->work_skb_queue);
1056} 278}
1057 279
1058void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata) 280void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata)
@@ -1086,43 +308,6 @@ void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata)
1086 mutex_unlock(&local->mtx); 308 mutex_unlock(&local->mtx);
1087} 309}
1088 310
1089ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata,
1090 struct sk_buff *skb)
1091{
1092 struct ieee80211_local *local = sdata->local;
1093 struct ieee80211_mgmt *mgmt;
1094 struct ieee80211_work *wk;
1095 u16 fc;
1096
1097 if (skb->len < 24)
1098 return RX_DROP_MONITOR;
1099
1100 mgmt = (struct ieee80211_mgmt *) skb->data;
1101 fc = le16_to_cpu(mgmt->frame_control);
1102
1103 list_for_each_entry_rcu(wk, &local->work_list, list) {
1104 if (sdata != wk->sdata)
1105 continue;
1106 if (compare_ether_addr(wk->filter_ta, mgmt->sa))
1107 continue;
1108 if (compare_ether_addr(wk->filter_ta, mgmt->bssid))
1109 continue;
1110
1111 switch (fc & IEEE80211_FCTL_STYPE) {
1112 case IEEE80211_STYPE_AUTH:
1113 case IEEE80211_STYPE_PROBE_RESP:
1114 case IEEE80211_STYPE_ASSOC_RESP:
1115 case IEEE80211_STYPE_REASSOC_RESP:
1116 case IEEE80211_STYPE_BEACON:
1117 skb_queue_tail(&local->work_skb_queue, skb);
1118 ieee80211_queue_work(&local->hw, &local->work_work);
1119 return RX_QUEUED;
1120 }
1121 }
1122
1123 return RX_CONTINUE;
1124}
1125
1126static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk, 311static enum work_done_result ieee80211_remain_done(struct ieee80211_work *wk,
1127 struct sk_buff *skb) 312 struct sk_buff *skb)
1128{ 313{