diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-12-23 07:15:35 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-12-28 16:54:55 -0500 |
commit | af6b63741cc4e4dfd575d06beb333b11a8a6e0c0 (patch) | |
tree | a2c1a27b6b6b0fb171606f3653b5c280537b32a3 /net/mac80211/mlme.c | |
parent | f679f65d417c3ea3f91b4bbfb68e3951c9eb8f04 (diff) |
mac80211: generalise work handling
In order to use auth/assoc for different purposes
other than MLME, it needs to be split up. For other
purposes, a generic work handling (potentially on
another channel) will be useful.
To achieve that, this patch moves much of the MLME
work handling out of mlme into a new work API. The
API can currently handle probing a specific AP,
authentication and association. The MLME previously
handled probe/authentication as one step and will
continue to do so, but they are separate in the new
work handling.
Work items are RCU-managed to be able to check for
existence of an item for a specific frame in the RX
path, but they can be re-used which the MLME right
now will do for its combined probe/auth step.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 956 |
1 files changed, 147 insertions, 809 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index c65225f29bb..7c1f91bcc83 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -77,12 +77,6 @@ enum rx_mgmt_action { | |||
77 | 77 | ||
78 | /* caller must tell cfg80211 about internal error */ | 78 | /* caller must tell cfg80211 about internal error */ |
79 | RX_MGMT_CFG80211_ASSOC_ERROR, | 79 | RX_MGMT_CFG80211_ASSOC_ERROR, |
80 | |||
81 | /* caller must call cfg80211_auth_timeout() & free work */ | ||
82 | RX_MGMT_CFG80211_AUTH_TO, | ||
83 | |||
84 | /* caller must call cfg80211_assoc_timeout() & free work */ | ||
85 | RX_MGMT_CFG80211_ASSOC_TO, | ||
86 | }; | 80 | }; |
87 | 81 | ||
88 | /* utils */ | 82 | /* utils */ |
@@ -125,27 +119,6 @@ static int ecw2cw(int ecw) | |||
125 | return (1 << ecw) - 1; | 119 | return (1 << ecw) - 1; |
126 | } | 120 | } |
127 | 121 | ||
128 | static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, | ||
129 | struct ieee80211_supported_band *sband, | ||
130 | u32 *rates) | ||
131 | { | ||
132 | int i, j, count; | ||
133 | *rates = 0; | ||
134 | count = 0; | ||
135 | for (i = 0; i < supp_rates_len; i++) { | ||
136 | int rate = (supp_rates[i] & 0x7F) * 5; | ||
137 | |||
138 | for (j = 0; j < sband->n_bitrates; j++) | ||
139 | if (sband->bitrates[j].bitrate == rate) { | ||
140 | *rates |= BIT(j); | ||
141 | count++; | ||
142 | break; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | return count; | ||
147 | } | ||
148 | |||
149 | /* | 122 | /* |
150 | * ieee80211_enable_ht should be called only after the operating band | 123 | * ieee80211_enable_ht should be called only after the operating band |
151 | * has been determined as ht configuration depends on the hw's | 124 | * has been determined as ht configuration depends on the hw's |
@@ -231,266 +204,6 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
231 | 204 | ||
232 | /* frame sending functions */ | 205 | /* frame sending functions */ |
233 | 206 | ||
234 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | ||
235 | struct ieee80211_work *wk) | ||
236 | { | ||
237 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
238 | struct ieee80211_local *local = sdata->local; | ||
239 | struct sk_buff *skb; | ||
240 | struct ieee80211_mgmt *mgmt; | ||
241 | u8 *pos; | ||
242 | const u8 *ies, *ht_ie; | ||
243 | int i, len, count, rates_len, supp_rates_len; | ||
244 | u16 capab; | ||
245 | int wmm = 0; | ||
246 | struct ieee80211_supported_band *sband; | ||
247 | u32 rates = 0; | ||
248 | |||
249 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
250 | sizeof(*mgmt) + 200 + wk->ie_len + | ||
251 | wk->assoc.ssid_len); | ||
252 | if (!skb) { | ||
253 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " | ||
254 | "frame\n", sdata->name); | ||
255 | return; | ||
256 | } | ||
257 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
258 | |||
259 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
260 | |||
261 | capab = ifmgd->capab; | ||
262 | |||
263 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { | ||
264 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) | ||
265 | capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; | ||
266 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) | ||
267 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; | ||
268 | } | ||
269 | |||
270 | if (wk->assoc.capability & WLAN_CAPABILITY_PRIVACY) | ||
271 | capab |= WLAN_CAPABILITY_PRIVACY; | ||
272 | if (wk->assoc.wmm_used) | ||
273 | wmm = 1; | ||
274 | |||
275 | /* get all rates supported by the device and the AP as | ||
276 | * some APs don't like getting a superset of their rates | ||
277 | * in the association request (e.g. D-Link DAP 1353 in | ||
278 | * b-only mode) */ | ||
279 | rates_len = ieee80211_compatible_rates(wk->assoc.supp_rates, | ||
280 | wk->assoc.supp_rates_len, | ||
281 | sband, &rates); | ||
282 | |||
283 | if ((wk->assoc.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && | ||
284 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) | ||
285 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; | ||
286 | |||
287 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
288 | memset(mgmt, 0, 24); | ||
289 | memcpy(mgmt->da, wk->assoc.bssid, ETH_ALEN); | ||
290 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
291 | memcpy(mgmt->bssid, wk->assoc.bssid, ETH_ALEN); | ||
292 | |||
293 | if (!is_zero_ether_addr(wk->assoc.prev_bssid)) { | ||
294 | skb_put(skb, 10); | ||
295 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
296 | IEEE80211_STYPE_REASSOC_REQ); | ||
297 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); | ||
298 | mgmt->u.reassoc_req.listen_interval = | ||
299 | cpu_to_le16(local->hw.conf.listen_interval); | ||
300 | memcpy(mgmt->u.reassoc_req.current_ap, wk->assoc.prev_bssid, | ||
301 | ETH_ALEN); | ||
302 | } else { | ||
303 | skb_put(skb, 4); | ||
304 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
305 | IEEE80211_STYPE_ASSOC_REQ); | ||
306 | mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); | ||
307 | mgmt->u.assoc_req.listen_interval = | ||
308 | cpu_to_le16(local->hw.conf.listen_interval); | ||
309 | } | ||
310 | |||
311 | /* SSID */ | ||
312 | ies = pos = skb_put(skb, 2 + wk->assoc.ssid_len); | ||
313 | *pos++ = WLAN_EID_SSID; | ||
314 | *pos++ = wk->assoc.ssid_len; | ||
315 | memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len); | ||
316 | |||
317 | /* add all rates which were marked to be used above */ | ||
318 | supp_rates_len = rates_len; | ||
319 | if (supp_rates_len > 8) | ||
320 | supp_rates_len = 8; | ||
321 | |||
322 | len = sband->n_bitrates; | ||
323 | pos = skb_put(skb, supp_rates_len + 2); | ||
324 | *pos++ = WLAN_EID_SUPP_RATES; | ||
325 | *pos++ = supp_rates_len; | ||
326 | |||
327 | count = 0; | ||
328 | for (i = 0; i < sband->n_bitrates; i++) { | ||
329 | if (BIT(i) & rates) { | ||
330 | int rate = sband->bitrates[i].bitrate; | ||
331 | *pos++ = (u8) (rate / 5); | ||
332 | if (++count == 8) | ||
333 | break; | ||
334 | } | ||
335 | } | ||
336 | |||
337 | if (rates_len > count) { | ||
338 | pos = skb_put(skb, rates_len - count + 2); | ||
339 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
340 | *pos++ = rates_len - count; | ||
341 | |||
342 | for (i++; i < sband->n_bitrates; i++) { | ||
343 | if (BIT(i) & rates) { | ||
344 | int rate = sband->bitrates[i].bitrate; | ||
345 | *pos++ = (u8) (rate / 5); | ||
346 | } | ||
347 | } | ||
348 | } | ||
349 | |||
350 | if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { | ||
351 | /* 1. power capabilities */ | ||
352 | pos = skb_put(skb, 4); | ||
353 | *pos++ = WLAN_EID_PWR_CAPABILITY; | ||
354 | *pos++ = 2; | ||
355 | *pos++ = 0; /* min tx power */ | ||
356 | *pos++ = local->hw.conf.channel->max_power; /* max tx power */ | ||
357 | |||
358 | /* 2. supported channels */ | ||
359 | /* TODO: get this in reg domain format */ | ||
360 | pos = skb_put(skb, 2 * sband->n_channels + 2); | ||
361 | *pos++ = WLAN_EID_SUPPORTED_CHANNELS; | ||
362 | *pos++ = 2 * sband->n_channels; | ||
363 | for (i = 0; i < sband->n_channels; i++) { | ||
364 | *pos++ = ieee80211_frequency_to_channel( | ||
365 | sband->channels[i].center_freq); | ||
366 | *pos++ = 1; /* one channel in the subband*/ | ||
367 | } | ||
368 | } | ||
369 | |||
370 | if (wk->ie_len && wk->ie) { | ||
371 | pos = skb_put(skb, wk->ie_len); | ||
372 | memcpy(pos, wk->ie, wk->ie_len); | ||
373 | } | ||
374 | |||
375 | if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) { | ||
376 | pos = skb_put(skb, 9); | ||
377 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | ||
378 | *pos++ = 7; /* len */ | ||
379 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
380 | *pos++ = 0x50; | ||
381 | *pos++ = 0xf2; | ||
382 | *pos++ = 2; /* WME */ | ||
383 | *pos++ = 0; /* WME info */ | ||
384 | *pos++ = 1; /* WME ver */ | ||
385 | *pos++ = 0; | ||
386 | } | ||
387 | |||
388 | /* wmm support is a must to HT */ | ||
389 | /* | ||
390 | * IEEE802.11n does not allow TKIP/WEP as pairwise | ||
391 | * ciphers in HT mode. We still associate in non-ht | ||
392 | * mode (11a/b/g) if any one of these ciphers is | ||
393 | * configured as pairwise. | ||
394 | */ | ||
395 | if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && | ||
396 | sband->ht_cap.ht_supported && | ||
397 | (ht_ie = wk->assoc.ht_information_ie) && | ||
398 | ht_ie[1] >= sizeof(struct ieee80211_ht_info) && | ||
399 | (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))) { | ||
400 | struct ieee80211_ht_info *ht_info = | ||
401 | (struct ieee80211_ht_info *)(ht_ie + 2); | ||
402 | u16 cap = sband->ht_cap.cap; | ||
403 | __le16 tmp; | ||
404 | u32 flags = local->hw.conf.channel->flags; | ||
405 | |||
406 | /* determine capability flags */ | ||
407 | |||
408 | if (ieee80211_disable_40mhz_24ghz && | ||
409 | sband->band == IEEE80211_BAND_2GHZ) { | ||
410 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
411 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
412 | } | ||
413 | |||
414 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
415 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
416 | if (flags & IEEE80211_CHAN_NO_HT40PLUS) { | ||
417 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
418 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
419 | } | ||
420 | break; | ||
421 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
422 | if (flags & IEEE80211_CHAN_NO_HT40MINUS) { | ||
423 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
424 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
425 | } | ||
426 | break; | ||
427 | } | ||
428 | |||
429 | /* set SM PS mode properly */ | ||
430 | cap &= ~IEEE80211_HT_CAP_SM_PS; | ||
431 | /* new association always uses requested smps mode */ | ||
432 | if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) { | ||
433 | if (ifmgd->powersave) | ||
434 | ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC; | ||
435 | else | ||
436 | ifmgd->ap_smps = IEEE80211_SMPS_OFF; | ||
437 | } else | ||
438 | ifmgd->ap_smps = ifmgd->req_smps; | ||
439 | |||
440 | switch (ifmgd->ap_smps) { | ||
441 | case IEEE80211_SMPS_AUTOMATIC: | ||
442 | case IEEE80211_SMPS_NUM_MODES: | ||
443 | WARN_ON(1); | ||
444 | case IEEE80211_SMPS_OFF: | ||
445 | cap |= WLAN_HT_CAP_SM_PS_DISABLED << | ||
446 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
447 | break; | ||
448 | case IEEE80211_SMPS_STATIC: | ||
449 | cap |= WLAN_HT_CAP_SM_PS_STATIC << | ||
450 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
451 | break; | ||
452 | case IEEE80211_SMPS_DYNAMIC: | ||
453 | cap |= WLAN_HT_CAP_SM_PS_DYNAMIC << | ||
454 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
455 | break; | ||
456 | } | ||
457 | |||
458 | /* reserve and fill IE */ | ||
459 | |||
460 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); | ||
461 | *pos++ = WLAN_EID_HT_CAPABILITY; | ||
462 | *pos++ = sizeof(struct ieee80211_ht_cap); | ||
463 | memset(pos, 0, sizeof(struct ieee80211_ht_cap)); | ||
464 | |||
465 | /* capability flags */ | ||
466 | tmp = cpu_to_le16(cap); | ||
467 | memcpy(pos, &tmp, sizeof(u16)); | ||
468 | pos += sizeof(u16); | ||
469 | |||
470 | /* AMPDU parameters */ | ||
471 | *pos++ = sband->ht_cap.ampdu_factor | | ||
472 | (sband->ht_cap.ampdu_density << | ||
473 | IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); | ||
474 | |||
475 | /* MCS set */ | ||
476 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); | ||
477 | pos += sizeof(sband->ht_cap.mcs); | ||
478 | |||
479 | /* extended capabilities */ | ||
480 | pos += sizeof(__le16); | ||
481 | |||
482 | /* BF capabilities */ | ||
483 | pos += sizeof(__le32); | ||
484 | |||
485 | /* antenna selection */ | ||
486 | pos += sizeof(u8); | ||
487 | } | ||
488 | |||
489 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
490 | ieee80211_tx_skb(sdata, skb); | ||
491 | } | ||
492 | |||
493 | |||
494 | static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | 207 | static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, |
495 | const u8 *bssid, u16 stype, u16 reason, | 208 | const u8 *bssid, u16 stype, u16 reason, |
496 | void *cookie) | 209 | void *cookie) |
@@ -751,6 +464,11 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
751 | return; | 464 | return; |
752 | } | 465 | } |
753 | 466 | ||
467 | if (!list_empty(&local->work_list)) { | ||
468 | local->ps_sdata = NULL; | ||
469 | goto change; | ||
470 | } | ||
471 | |||
754 | list_for_each_entry(sdata, &local->interfaces, list) { | 472 | list_for_each_entry(sdata, &local->interfaces, list) { |
755 | if (!ieee80211_sdata_running(sdata)) | 473 | if (!ieee80211_sdata_running(sdata)) |
756 | continue; | 474 | continue; |
@@ -761,7 +479,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
761 | } | 479 | } |
762 | 480 | ||
763 | if (count == 1 && found->u.mgd.powersave && | 481 | if (count == 1 && found->u.mgd.powersave && |
764 | found->u.mgd.associated && list_empty(&found->u.mgd.work_list) && | 482 | found->u.mgd.associated && |
765 | !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | | 483 | !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | |
766 | IEEE80211_STA_CONNECTION_POLL))) { | 484 | IEEE80211_STA_CONNECTION_POLL))) { |
767 | s32 beaconint_us; | 485 | s32 beaconint_us; |
@@ -789,6 +507,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
789 | local->ps_sdata = NULL; | 507 | local->ps_sdata = NULL; |
790 | } | 508 | } |
791 | 509 | ||
510 | change: | ||
792 | ieee80211_change_ps(local); | 511 | ieee80211_change_ps(local); |
793 | } | 512 | } |
794 | 513 | ||
@@ -848,7 +567,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
848 | int count; | 567 | int count; |
849 | u8 *pos; | 568 | u8 *pos; |
850 | 569 | ||
851 | if (!(ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) | 570 | if (local->hw.queues < 4) |
852 | return; | 571 | return; |
853 | 572 | ||
854 | if (!wmm_param) | 573 | if (!wmm_param) |
@@ -1005,110 +724,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
1005 | netif_carrier_on(sdata->dev); | 724 | netif_carrier_on(sdata->dev); |
1006 | } | 725 | } |
1007 | 726 | ||
1008 | static void ieee80211_remove_auth_bss(struct ieee80211_local *local, | ||
1009 | struct ieee80211_work *wk) | ||
1010 | { | ||
1011 | struct cfg80211_bss *cbss; | ||
1012 | u16 capa_val = WLAN_CAPABILITY_ESS; | ||
1013 | |||
1014 | if (wk->auth.privacy) | ||
1015 | capa_val |= WLAN_CAPABILITY_PRIVACY; | ||
1016 | |||
1017 | cbss = cfg80211_get_bss(local->hw.wiphy, wk->chan, wk->auth.bssid, | ||
1018 | wk->auth.ssid, wk->auth.ssid_len, | ||
1019 | WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, | ||
1020 | capa_val); | ||
1021 | if (!cbss) | ||
1022 | return; | ||
1023 | |||
1024 | cfg80211_unlink_bss(local->hw.wiphy, cbss); | ||
1025 | cfg80211_put_bss(cbss); | ||
1026 | } | ||
1027 | |||
1028 | static enum rx_mgmt_action __must_check | ||
1029 | ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, | ||
1030 | struct ieee80211_work *wk) | ||
1031 | { | ||
1032 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1033 | struct ieee80211_local *local = sdata->local; | ||
1034 | |||
1035 | wk->auth.tries++; | ||
1036 | if (wk->auth.tries > IEEE80211_AUTH_MAX_TRIES) { | ||
1037 | printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", | ||
1038 | sdata->name, wk->auth.bssid); | ||
1039 | |||
1040 | /* | ||
1041 | * Most likely AP is not in the range so remove the | ||
1042 | * bss struct for that AP. | ||
1043 | */ | ||
1044 | ieee80211_remove_auth_bss(local, wk); | ||
1045 | |||
1046 | /* | ||
1047 | * We might have a pending scan which had no chance to run yet | ||
1048 | * due to work needing to be done. Hence, queue the STAs work | ||
1049 | * again for that. | ||
1050 | */ | ||
1051 | ieee80211_queue_work(&local->hw, &ifmgd->work); | ||
1052 | return RX_MGMT_CFG80211_AUTH_TO; | ||
1053 | } | ||
1054 | |||
1055 | printk(KERN_DEBUG "%s: direct probe to AP %pM (try %d)\n", | ||
1056 | sdata->name, wk->auth.bssid, wk->auth.tries); | ||
1057 | |||
1058 | /* | ||
1059 | * Direct probe is sent to broadcast address as some APs | ||
1060 | * will not answer to direct packet in unassociated state. | ||
1061 | */ | ||
1062 | ieee80211_send_probe_req(sdata, NULL, wk->auth.ssid, wk->auth.ssid_len, | ||
1063 | NULL, 0); | ||
1064 | |||
1065 | wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | ||
1066 | run_again(ifmgd, wk->timeout); | ||
1067 | |||
1068 | return RX_MGMT_NONE; | ||
1069 | } | ||
1070 | |||
1071 | |||
1072 | static enum rx_mgmt_action __must_check | ||
1073 | ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, | ||
1074 | struct ieee80211_work *wk) | ||
1075 | { | ||
1076 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1077 | struct ieee80211_local *local = sdata->local; | ||
1078 | |||
1079 | wk->auth.tries++; | ||
1080 | if (wk->auth.tries > IEEE80211_AUTH_MAX_TRIES) { | ||
1081 | printk(KERN_DEBUG "%s: authentication with AP %pM" | ||
1082 | " timed out\n", sdata->name, wk->auth.bssid); | ||
1083 | |||
1084 | /* | ||
1085 | * Most likely AP is not in the range so remove the | ||
1086 | * bss struct for that AP. | ||
1087 | */ | ||
1088 | ieee80211_remove_auth_bss(local, wk); | ||
1089 | |||
1090 | /* | ||
1091 | * We might have a pending scan which had no chance to run yet | ||
1092 | * due to work needing to be done. Hence, queue the STAs work | ||
1093 | * again for that. | ||
1094 | */ | ||
1095 | ieee80211_queue_work(&local->hw, &ifmgd->work); | ||
1096 | return RX_MGMT_CFG80211_AUTH_TO; | ||
1097 | } | ||
1098 | |||
1099 | printk(KERN_DEBUG "%s: authenticate with AP %pM (try %d)\n", | ||
1100 | sdata->name, wk->auth.bssid, wk->auth.tries); | ||
1101 | |||
1102 | ieee80211_send_auth(sdata, 1, wk->auth.algorithm, wk->ie, wk->ie_len, | ||
1103 | wk->auth.bssid, NULL, 0, 0); | ||
1104 | wk->auth.transaction = 2; | ||
1105 | |||
1106 | wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | ||
1107 | run_again(ifmgd, wk->timeout); | ||
1108 | |||
1109 | return RX_MGMT_NONE; | ||
1110 | } | ||
1111 | |||
1112 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) | 727 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) |
1113 | { | 728 | { |
1114 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 729 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
@@ -1195,44 +810,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) | |||
1195 | sta_info_destroy(sta); | 810 | sta_info_destroy(sta); |
1196 | } | 811 | } |
1197 | 812 | ||
1198 | static enum rx_mgmt_action __must_check | ||
1199 | ieee80211_associate(struct ieee80211_sub_if_data *sdata, | ||
1200 | struct ieee80211_work *wk) | ||
1201 | { | ||
1202 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1203 | struct ieee80211_local *local = sdata->local; | ||
1204 | |||
1205 | wk->assoc.tries++; | ||
1206 | if (wk->assoc.tries > IEEE80211_ASSOC_MAX_TRIES) { | ||
1207 | printk(KERN_DEBUG "%s: association with AP %pM" | ||
1208 | " timed out\n", | ||
1209 | sdata->name, wk->assoc.bssid); | ||
1210 | |||
1211 | /* | ||
1212 | * Most likely AP is not in the range so remove the | ||
1213 | * bss struct for that AP. | ||
1214 | */ | ||
1215 | cfg80211_unlink_bss(local->hw.wiphy, &wk->assoc.bss->cbss); | ||
1216 | |||
1217 | /* | ||
1218 | * We might have a pending scan which had no chance to run yet | ||
1219 | * due to work needing to be done. Hence, queue the STAs work | ||
1220 | * again for that. | ||
1221 | */ | ||
1222 | ieee80211_queue_work(&local->hw, &ifmgd->work); | ||
1223 | return RX_MGMT_CFG80211_ASSOC_TO; | ||
1224 | } | ||
1225 | |||
1226 | printk(KERN_DEBUG "%s: associate with AP %pM (try %d)\n", | ||
1227 | sdata->name, wk->assoc.bssid, wk->assoc.tries); | ||
1228 | ieee80211_send_assoc(sdata, wk); | ||
1229 | |||
1230 | wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; | ||
1231 | run_again(ifmgd, wk->timeout); | ||
1232 | |||
1233 | return RX_MGMT_NONE; | ||
1234 | } | ||
1235 | |||
1236 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 813 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
1237 | struct ieee80211_hdr *hdr) | 814 | struct ieee80211_hdr *hdr) |
1238 | { | 815 | { |
@@ -1338,86 +915,6 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif) | |||
1338 | } | 915 | } |
1339 | EXPORT_SYMBOL(ieee80211_beacon_loss); | 916 | EXPORT_SYMBOL(ieee80211_beacon_loss); |
1340 | 917 | ||
1341 | static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, | ||
1342 | struct ieee80211_work *wk) | ||
1343 | { | ||
1344 | list_del(&wk->list); | ||
1345 | kfree(wk); | ||
1346 | printk(KERN_DEBUG "%s: authenticated\n", sdata->name); | ||
1347 | } | ||
1348 | |||
1349 | |||
1350 | static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | ||
1351 | struct ieee80211_work *wk, | ||
1352 | struct ieee80211_mgmt *mgmt, | ||
1353 | size_t len) | ||
1354 | { | ||
1355 | u8 *pos; | ||
1356 | struct ieee802_11_elems elems; | ||
1357 | |||
1358 | pos = mgmt->u.auth.variable; | ||
1359 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
1360 | if (!elems.challenge) | ||
1361 | return; | ||
1362 | ieee80211_send_auth(sdata, 3, wk->auth.algorithm, | ||
1363 | elems.challenge - 2, elems.challenge_len + 2, | ||
1364 | wk->auth.bssid, wk->auth.key, wk->auth.key_len, | ||
1365 | wk->auth.key_idx); | ||
1366 | wk->auth.transaction = 4; | ||
1367 | } | ||
1368 | |||
1369 | static enum rx_mgmt_action __must_check | ||
1370 | ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | ||
1371 | struct ieee80211_work *wk, | ||
1372 | struct ieee80211_mgmt *mgmt, size_t len) | ||
1373 | { | ||
1374 | u16 auth_alg, auth_transaction, status_code; | ||
1375 | |||
1376 | if (wk->type != IEEE80211_WORK_AUTH) | ||
1377 | return RX_MGMT_NONE; | ||
1378 | |||
1379 | if (len < 24 + 6) | ||
1380 | return RX_MGMT_NONE; | ||
1381 | |||
1382 | if (memcmp(wk->auth.bssid, mgmt->sa, ETH_ALEN) != 0) | ||
1383 | return RX_MGMT_NONE; | ||
1384 | |||
1385 | if (memcmp(wk->auth.bssid, mgmt->bssid, ETH_ALEN) != 0) | ||
1386 | return RX_MGMT_NONE; | ||
1387 | |||
1388 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | ||
1389 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | ||
1390 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | ||
1391 | |||
1392 | if (auth_alg != wk->auth.algorithm || | ||
1393 | auth_transaction != wk->auth.transaction) | ||
1394 | return RX_MGMT_NONE; | ||
1395 | |||
1396 | if (status_code != WLAN_STATUS_SUCCESS) { | ||
1397 | list_del(&wk->list); | ||
1398 | kfree(wk); | ||
1399 | return RX_MGMT_CFG80211_AUTH; | ||
1400 | } | ||
1401 | |||
1402 | switch (wk->auth.algorithm) { | ||
1403 | case WLAN_AUTH_OPEN: | ||
1404 | case WLAN_AUTH_LEAP: | ||
1405 | case WLAN_AUTH_FT: | ||
1406 | ieee80211_auth_completed(sdata, wk); | ||
1407 | return RX_MGMT_CFG80211_AUTH; | ||
1408 | case WLAN_AUTH_SHARED_KEY: | ||
1409 | if (wk->auth.transaction == 4) { | ||
1410 | ieee80211_auth_completed(sdata, wk); | ||
1411 | return RX_MGMT_CFG80211_AUTH; | ||
1412 | } else | ||
1413 | ieee80211_auth_challenge(sdata, wk, mgmt, len); | ||
1414 | break; | ||
1415 | } | ||
1416 | |||
1417 | return RX_MGMT_NONE; | ||
1418 | } | ||
1419 | |||
1420 | |||
1421 | static enum rx_mgmt_action __must_check | 918 | static enum rx_mgmt_action __must_check |
1422 | ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | 919 | ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, |
1423 | struct ieee80211_mgmt *mgmt, size_t len) | 920 | struct ieee80211_mgmt *mgmt, size_t len) |
@@ -1474,98 +971,51 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1474 | } | 971 | } |
1475 | 972 | ||
1476 | 973 | ||
1477 | static enum rx_mgmt_action __must_check | 974 | static bool ieee80211_assoc_success(struct ieee80211_work *wk, |
1478 | ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | 975 | struct ieee80211_mgmt *mgmt, size_t len) |
1479 | struct ieee80211_work *wk, | ||
1480 | struct ieee80211_mgmt *mgmt, size_t len, | ||
1481 | bool reassoc) | ||
1482 | { | 976 | { |
977 | struct ieee80211_sub_if_data *sdata = wk->sdata; | ||
1483 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 978 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1484 | struct ieee80211_local *local = sdata->local; | 979 | struct ieee80211_local *local = sdata->local; |
1485 | struct ieee80211_supported_band *sband; | 980 | struct ieee80211_supported_band *sband; |
1486 | struct sta_info *sta; | 981 | struct sta_info *sta; |
1487 | struct ieee80211_bss *bss = wk->assoc.bss; | 982 | struct ieee80211_bss *bss = wk->assoc.bss; |
983 | u8 *pos; | ||
1488 | u32 rates, basic_rates; | 984 | u32 rates, basic_rates; |
1489 | u16 capab_info, status_code, aid; | 985 | u16 capab_info, aid; |
1490 | struct ieee802_11_elems elems; | 986 | struct ieee802_11_elems elems; |
1491 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | 987 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
1492 | u8 *pos; | ||
1493 | u32 changed = 0; | 988 | u32 changed = 0; |
1494 | int i, j, err; | 989 | int i, j, err; |
1495 | bool have_higher_than_11mbit = false; | 990 | bool have_higher_than_11mbit = false; |
1496 | u16 ap_ht_cap_flags; | 991 | u16 ap_ht_cap_flags; |
1497 | 992 | ||
1498 | /* | 993 | /* AssocResp and ReassocResp have identical structure */ |
1499 | * AssocResp and ReassocResp have identical structure, so process both | ||
1500 | * of them in this function. | ||
1501 | */ | ||
1502 | |||
1503 | if (len < 24 + 6) | ||
1504 | return RX_MGMT_NONE; | ||
1505 | 994 | ||
1506 | if (memcmp(bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0) | ||
1507 | return RX_MGMT_NONE; | ||
1508 | |||
1509 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | ||
1510 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | ||
1511 | aid = le16_to_cpu(mgmt->u.assoc_resp.aid); | 995 | aid = le16_to_cpu(mgmt->u.assoc_resp.aid); |
1512 | 996 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | |
1513 | printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x " | ||
1514 | "status=%d aid=%d)\n", | ||
1515 | sdata->name, reassoc ? "Rea" : "A", mgmt->sa, | ||
1516 | capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); | ||
1517 | |||
1518 | pos = mgmt->u.assoc_resp.variable; | ||
1519 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
1520 | |||
1521 | if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && | ||
1522 | elems.timeout_int && elems.timeout_int_len == 5 && | ||
1523 | elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) { | ||
1524 | u32 tu, ms; | ||
1525 | tu = get_unaligned_le32(elems.timeout_int + 1); | ||
1526 | ms = tu * 1024 / 1000; | ||
1527 | printk(KERN_DEBUG "%s: AP rejected association temporarily; " | ||
1528 | "comeback duration %u TU (%u ms)\n", | ||
1529 | sdata->name, tu, ms); | ||
1530 | wk->timeout = jiffies + msecs_to_jiffies(ms); | ||
1531 | if (ms > IEEE80211_ASSOC_TIMEOUT) | ||
1532 | run_again(ifmgd, jiffies + msecs_to_jiffies(ms)); | ||
1533 | return RX_MGMT_NONE; | ||
1534 | } | ||
1535 | |||
1536 | /* | ||
1537 | * Here the association was either successful or not. | ||
1538 | */ | ||
1539 | |||
1540 | /* delete work item -- must be before set_associated for PS */ | ||
1541 | list_del(&wk->list); | ||
1542 | kfree(wk); | ||
1543 | |||
1544 | if (status_code != WLAN_STATUS_SUCCESS) { | ||
1545 | printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", | ||
1546 | sdata->name, status_code); | ||
1547 | return RX_MGMT_CFG80211_ASSOC; | ||
1548 | } | ||
1549 | 997 | ||
1550 | if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) | 998 | if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) |
1551 | printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " | 999 | printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " |
1552 | "set\n", sdata->name, aid); | 1000 | "set\n", sdata->name, aid); |
1553 | aid &= ~(BIT(15) | BIT(14)); | 1001 | aid &= ~(BIT(15) | BIT(14)); |
1554 | 1002 | ||
1003 | pos = mgmt->u.assoc_resp.variable; | ||
1004 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
1005 | |||
1555 | if (!elems.supp_rates) { | 1006 | if (!elems.supp_rates) { |
1556 | printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", | 1007 | printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", |
1557 | sdata->name); | 1008 | sdata->name); |
1558 | return RX_MGMT_NONE; | 1009 | return false; |
1559 | } | 1010 | } |
1560 | 1011 | ||
1561 | printk(KERN_DEBUG "%s: associated\n", sdata->name); | ||
1562 | ifmgd->aid = aid; | 1012 | ifmgd->aid = aid; |
1563 | 1013 | ||
1564 | sta = sta_info_alloc(sdata, bss->cbss.bssid, GFP_KERNEL); | 1014 | sta = sta_info_alloc(sdata, bss->cbss.bssid, GFP_KERNEL); |
1565 | if (!sta) { | 1015 | if (!sta) { |
1566 | printk(KERN_DEBUG "%s: failed to alloc STA entry for" | 1016 | printk(KERN_DEBUG "%s: failed to alloc STA entry for" |
1567 | " the AP\n", sdata->name); | 1017 | " the AP\n", sdata->name); |
1568 | return RX_MGMT_CFG80211_ASSOC_ERROR; | 1018 | return false; |
1569 | } | 1019 | } |
1570 | 1020 | ||
1571 | set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | | 1021 | set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | |
@@ -1650,7 +1100,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1650 | ieee80211_set_wmm_default(sdata); | 1100 | ieee80211_set_wmm_default(sdata); |
1651 | 1101 | ||
1652 | if (elems.ht_info_elem && elems.wmm_param && | 1102 | if (elems.ht_info_elem && elems.wmm_param && |
1653 | (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && | 1103 | (sdata->local->hw.queues >= 4) && |
1654 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) | 1104 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) |
1655 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, | 1105 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, |
1656 | bss->cbss.bssid, | 1106 | bss->cbss.bssid, |
@@ -1669,7 +1119,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1669 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); | 1119 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); |
1670 | mod_beacon_timer(sdata); | 1120 | mod_beacon_timer(sdata); |
1671 | 1121 | ||
1672 | return RX_MGMT_CFG80211_ASSOC; | 1122 | return true; |
1673 | } | 1123 | } |
1674 | 1124 | ||
1675 | 1125 | ||
@@ -1714,12 +1164,12 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1714 | 1164 | ||
1715 | 1165 | ||
1716 | static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | 1166 | static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, |
1717 | struct ieee80211_work *wk, | 1167 | struct sk_buff *skb) |
1718 | struct ieee80211_mgmt *mgmt, size_t len, | ||
1719 | struct ieee80211_rx_status *rx_status) | ||
1720 | { | 1168 | { |
1169 | struct ieee80211_mgmt *mgmt = (void *)skb->data; | ||
1721 | struct ieee80211_if_managed *ifmgd; | 1170 | struct ieee80211_if_managed *ifmgd; |
1722 | size_t baselen; | 1171 | struct ieee80211_rx_status *rx_status = (void *) skb->cb; |
1172 | size_t baselen, len = skb->len; | ||
1723 | struct ieee802_11_elems elems; | 1173 | struct ieee802_11_elems elems; |
1724 | 1174 | ||
1725 | ifmgd = &sdata->u.mgd; | 1175 | ifmgd = &sdata->u.mgd; |
@@ -1738,15 +1188,6 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1738 | 1188 | ||
1739 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); | 1189 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); |
1740 | 1190 | ||
1741 | /* direct probe may be part of the association flow */ | ||
1742 | if (wk && wk->type == IEEE80211_WORK_AUTH_PROBE) { | ||
1743 | printk(KERN_DEBUG "%s: direct probe responded\n", | ||
1744 | sdata->name); | ||
1745 | wk->auth.tries = 0; | ||
1746 | wk->type = IEEE80211_WORK_AUTH; | ||
1747 | WARN_ON(ieee80211_authenticate(sdata, wk) != RX_MGMT_NONE); | ||
1748 | } | ||
1749 | |||
1750 | if (ifmgd->associated && | 1191 | if (ifmgd->associated && |
1751 | memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 && | 1192 | memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 && |
1752 | ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 1193 | ifmgd->flags & (IEEE80211_STA_BEACON_POLL | |
@@ -1960,9 +1401,6 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1960 | switch (fc & IEEE80211_FCTL_STYPE) { | 1401 | switch (fc & IEEE80211_FCTL_STYPE) { |
1961 | case IEEE80211_STYPE_PROBE_RESP: | 1402 | case IEEE80211_STYPE_PROBE_RESP: |
1962 | case IEEE80211_STYPE_BEACON: | 1403 | case IEEE80211_STYPE_BEACON: |
1963 | case IEEE80211_STYPE_AUTH: | ||
1964 | case IEEE80211_STYPE_ASSOC_RESP: | ||
1965 | case IEEE80211_STYPE_REASSOC_RESP: | ||
1966 | case IEEE80211_STYPE_DEAUTH: | 1404 | case IEEE80211_STYPE_DEAUTH: |
1967 | case IEEE80211_STYPE_DISASSOC: | 1405 | case IEEE80211_STYPE_DISASSOC: |
1968 | case IEEE80211_STYPE_ACTION: | 1406 | case IEEE80211_STYPE_ACTION: |
@@ -1980,7 +1418,6 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1980 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1418 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1981 | struct ieee80211_rx_status *rx_status; | 1419 | struct ieee80211_rx_status *rx_status; |
1982 | struct ieee80211_mgmt *mgmt; | 1420 | struct ieee80211_mgmt *mgmt; |
1983 | struct ieee80211_work *wk; | ||
1984 | enum rx_mgmt_action rma = RX_MGMT_NONE; | 1421 | enum rx_mgmt_action rma = RX_MGMT_NONE; |
1985 | u16 fc; | 1422 | u16 fc; |
1986 | 1423 | ||
@@ -1999,8 +1436,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1999 | rx_status); | 1436 | rx_status); |
2000 | break; | 1437 | break; |
2001 | case IEEE80211_STYPE_PROBE_RESP: | 1438 | case IEEE80211_STYPE_PROBE_RESP: |
2002 | ieee80211_rx_mgmt_probe_resp(sdata, NULL, mgmt, | 1439 | ieee80211_rx_mgmt_probe_resp(sdata, skb); |
2003 | skb->len, rx_status); | ||
2004 | break; | 1440 | break; |
2005 | case IEEE80211_STYPE_DEAUTH: | 1441 | case IEEE80211_STYPE_DEAUTH: |
2006 | rma = ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); | 1442 | rma = ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); |
@@ -2033,88 +1469,11 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
2033 | goto out; | 1469 | goto out; |
2034 | } | 1470 | } |
2035 | 1471 | ||
2036 | list_for_each_entry(wk, &ifmgd->work_list, list) { | ||
2037 | const u8 *bssid = NULL; | ||
2038 | |||
2039 | switch (wk->type) { | ||
2040 | case IEEE80211_WORK_AUTH_PROBE: | ||
2041 | case IEEE80211_WORK_AUTH: | ||
2042 | bssid = wk->auth.bssid; | ||
2043 | break; | ||
2044 | case IEEE80211_WORK_ASSOC: | ||
2045 | bssid = wk->assoc.bssid; | ||
2046 | break; | ||
2047 | default: | ||
2048 | continue; | ||
2049 | } | ||
2050 | if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0) | ||
2051 | continue; | ||
2052 | |||
2053 | switch (fc & IEEE80211_FCTL_STYPE) { | ||
2054 | case IEEE80211_STYPE_PROBE_RESP: | ||
2055 | ieee80211_rx_mgmt_probe_resp(sdata, wk, mgmt, skb->len, | ||
2056 | rx_status); | ||
2057 | break; | ||
2058 | case IEEE80211_STYPE_AUTH: | ||
2059 | rma = ieee80211_rx_mgmt_auth(sdata, wk, mgmt, skb->len); | ||
2060 | break; | ||
2061 | case IEEE80211_STYPE_ASSOC_RESP: | ||
2062 | rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt, | ||
2063 | skb->len, false); | ||
2064 | break; | ||
2065 | case IEEE80211_STYPE_REASSOC_RESP: | ||
2066 | rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt, | ||
2067 | skb->len, true); | ||
2068 | break; | ||
2069 | case IEEE80211_STYPE_DEAUTH: | ||
2070 | if (skb->len >= 24 + 2 /* mgmt + deauth reason */) { | ||
2071 | /* | ||
2072 | * We get here if we get deauth while | ||
2073 | * trying to auth/assoc. Telling cfg80211 | ||
2074 | * is handled below, unconditionally. | ||
2075 | */ | ||
2076 | list_del(&wk->list); | ||
2077 | kfree(wk); | ||
2078 | } | ||
2079 | break; | ||
2080 | } | ||
2081 | /* | ||
2082 | * We've processed this frame for that work, so it can't | ||
2083 | * belong to another work struct. | ||
2084 | * NB: this is also required for correctness because the | ||
2085 | * called functions can free 'wk', and for 'rma'! | ||
2086 | */ | ||
2087 | break; | ||
2088 | } | ||
2089 | |||
2090 | mutex_unlock(&ifmgd->mtx); | 1472 | mutex_unlock(&ifmgd->mtx); |
2091 | 1473 | ||
2092 | if (skb->len >= 24 + 2 /* mgmt + deauth reason */ && | 1474 | if (skb->len >= 24 + 2 /* mgmt + deauth reason */ && |
2093 | (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH) { | 1475 | (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH) |
2094 | WARN_ON(rma != RX_MGMT_NONE); | ||
2095 | rma = RX_MGMT_CFG80211_DEAUTH; | ||
2096 | } | ||
2097 | |||
2098 | switch (rma) { | ||
2099 | case RX_MGMT_NONE: | ||
2100 | /* no action */ | ||
2101 | break; | ||
2102 | case RX_MGMT_CFG80211_AUTH: | ||
2103 | cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, skb->len); | ||
2104 | break; | ||
2105 | case RX_MGMT_CFG80211_ASSOC: | ||
2106 | cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len); | ||
2107 | break; | ||
2108 | case RX_MGMT_CFG80211_DEAUTH: | ||
2109 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); | 1476 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); |
2110 | break; | ||
2111 | case RX_MGMT_CFG80211_ASSOC_ERROR: | ||
2112 | /* an internal error -- pretend timeout for now */ | ||
2113 | cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid); | ||
2114 | break; | ||
2115 | default: | ||
2116 | WARN(1, "unexpected: %d", rma); | ||
2117 | } | ||
2118 | 1477 | ||
2119 | out: | 1478 | out: |
2120 | kfree_skb(skb); | 1479 | kfree_skb(skb); |
@@ -2142,9 +1501,6 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2142 | struct ieee80211_local *local = sdata->local; | 1501 | struct ieee80211_local *local = sdata->local; |
2143 | struct ieee80211_if_managed *ifmgd; | 1502 | struct ieee80211_if_managed *ifmgd; |
2144 | struct sk_buff *skb; | 1503 | struct sk_buff *skb; |
2145 | struct ieee80211_work *wk, *tmp; | ||
2146 | LIST_HEAD(free_work); | ||
2147 | enum rx_mgmt_action rma; | ||
2148 | 1504 | ||
2149 | if (!ieee80211_sdata_running(sdata)) | 1505 | if (!ieee80211_sdata_running(sdata)) |
2150 | return; | 1506 | return; |
@@ -2214,84 +1570,7 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2214 | } | 1570 | } |
2215 | } | 1571 | } |
2216 | 1572 | ||
2217 | |||
2218 | ieee80211_recalc_idle(local); | ||
2219 | |||
2220 | list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) { | ||
2221 | if (time_is_after_jiffies(wk->timeout)) { | ||
2222 | /* | ||
2223 | * This work item isn't supposed to be worked on | ||
2224 | * right now, but take care to adjust the timer | ||
2225 | * properly. | ||
2226 | */ | ||
2227 | run_again(ifmgd, wk->timeout); | ||
2228 | continue; | ||
2229 | } | ||
2230 | |||
2231 | switch (wk->type) { | ||
2232 | default: | ||
2233 | WARN_ON(1); | ||
2234 | /* nothing */ | ||
2235 | rma = RX_MGMT_NONE; | ||
2236 | break; | ||
2237 | case IEEE80211_WORK_AUTH_PROBE: | ||
2238 | rma = ieee80211_direct_probe(sdata, wk); | ||
2239 | break; | ||
2240 | case IEEE80211_WORK_AUTH: | ||
2241 | rma = ieee80211_authenticate(sdata, wk); | ||
2242 | break; | ||
2243 | case IEEE80211_WORK_ASSOC: | ||
2244 | rma = ieee80211_associate(sdata, wk); | ||
2245 | break; | ||
2246 | } | ||
2247 | |||
2248 | switch (rma) { | ||
2249 | case RX_MGMT_NONE: | ||
2250 | /* no action required */ | ||
2251 | break; | ||
2252 | case RX_MGMT_CFG80211_AUTH_TO: | ||
2253 | case RX_MGMT_CFG80211_ASSOC_TO: | ||
2254 | list_del(&wk->list); | ||
2255 | list_add(&wk->list, &free_work); | ||
2256 | /* | ||
2257 | * small abuse but only local -- keep the | ||
2258 | * action type in wk->timeout while the item | ||
2259 | * is on the cleanup list | ||
2260 | */ | ||
2261 | wk->timeout = rma; | ||
2262 | break; | ||
2263 | default: | ||
2264 | WARN(1, "unexpected: %d", rma); | ||
2265 | } | ||
2266 | } | ||
2267 | |||
2268 | if (list_empty(&ifmgd->work_list) && | ||
2269 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) | ||
2270 | ieee80211_queue_delayed_work(&local->hw, | ||
2271 | &local->scan_work, | ||
2272 | round_jiffies_relative(0)); | ||
2273 | |||
2274 | mutex_unlock(&ifmgd->mtx); | 1573 | mutex_unlock(&ifmgd->mtx); |
2275 | |||
2276 | list_for_each_entry_safe(wk, tmp, &free_work, list) { | ||
2277 | /* see above how we're using wk->timeout */ | ||
2278 | switch (wk->timeout) { | ||
2279 | case RX_MGMT_CFG80211_AUTH_TO: | ||
2280 | cfg80211_send_auth_timeout(sdata->dev, wk->auth.bssid); | ||
2281 | break; | ||
2282 | case RX_MGMT_CFG80211_ASSOC_TO: | ||
2283 | cfg80211_send_assoc_timeout(sdata->dev, | ||
2284 | wk->assoc.bssid); | ||
2285 | break; | ||
2286 | default: | ||
2287 | WARN(1, "unexpected: %lu", wk->timeout); | ||
2288 | } | ||
2289 | |||
2290 | list_del(&wk->list); | ||
2291 | kfree(wk); | ||
2292 | } | ||
2293 | |||
2294 | ieee80211_recalc_idle(local); | ||
2295 | } | 1574 | } |
2296 | 1575 | ||
2297 | static void ieee80211_sta_bcn_mon_timer(unsigned long data) | 1576 | static void ieee80211_sta_bcn_mon_timer(unsigned long data) |
@@ -2400,12 +1679,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
2400 | (unsigned long) sdata); | 1679 | (unsigned long) sdata); |
2401 | skb_queue_head_init(&ifmgd->skb_queue); | 1680 | skb_queue_head_init(&ifmgd->skb_queue); |
2402 | 1681 | ||
2403 | INIT_LIST_HEAD(&ifmgd->work_list); | ||
2404 | |||
2405 | ifmgd->capab = WLAN_CAPABILITY_ESS; | ||
2406 | ifmgd->flags = 0; | 1682 | ifmgd->flags = 0; |
2407 | if (sdata->local->hw.queues >= 4) | ||
2408 | ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; | ||
2409 | 1683 | ||
2410 | mutex_init(&ifmgd->mtx); | 1684 | mutex_init(&ifmgd->mtx); |
2411 | 1685 | ||
@@ -2443,10 +1717,32 @@ int ieee80211_max_network_latency(struct notifier_block *nb, | |||
2443 | } | 1717 | } |
2444 | 1718 | ||
2445 | /* config hooks */ | 1719 | /* config hooks */ |
1720 | static enum work_done_result | ||
1721 | ieee80211_probe_auth_done(struct ieee80211_work *wk, | ||
1722 | struct sk_buff *skb) | ||
1723 | { | ||
1724 | if (!skb) { | ||
1725 | cfg80211_send_auth_timeout(wk->sdata->dev, wk->filter_ta); | ||
1726 | return WORK_DONE_DESTROY; | ||
1727 | } | ||
1728 | |||
1729 | if (wk->type == IEEE80211_WORK_AUTH) { | ||
1730 | cfg80211_send_rx_auth(wk->sdata->dev, skb->data, skb->len); | ||
1731 | return WORK_DONE_DESTROY; | ||
1732 | } | ||
1733 | |||
1734 | mutex_lock(&wk->sdata->u.mgd.mtx); | ||
1735 | ieee80211_rx_mgmt_probe_resp(wk->sdata, skb); | ||
1736 | mutex_unlock(&wk->sdata->u.mgd.mtx); | ||
1737 | |||
1738 | wk->type = IEEE80211_WORK_AUTH; | ||
1739 | wk->probe_auth.tries = 0; | ||
1740 | return WORK_DONE_REQUEUE; | ||
1741 | } | ||
1742 | |||
2446 | int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | 1743 | int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, |
2447 | struct cfg80211_auth_request *req) | 1744 | struct cfg80211_auth_request *req) |
2448 | { | 1745 | { |
2449 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2450 | const u8 *ssid; | 1746 | const u8 *ssid; |
2451 | struct ieee80211_work *wk; | 1747 | struct ieee80211_work *wk; |
2452 | u16 auth_alg; | 1748 | u16 auth_alg; |
@@ -2472,7 +1768,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
2472 | if (!wk) | 1768 | if (!wk) |
2473 | return -ENOMEM; | 1769 | return -ENOMEM; |
2474 | 1770 | ||
2475 | memcpy(wk->auth.bssid, req->bss->bssid, ETH_ALEN);; | 1771 | memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN);; |
2476 | 1772 | ||
2477 | if (req->ie && req->ie_len) { | 1773 | if (req->ie && req->ie_len) { |
2478 | memcpy(wk->ie, req->ie, req->ie_len); | 1774 | memcpy(wk->ie, req->ie, req->ie_len); |
@@ -2480,21 +1776,22 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
2480 | } | 1776 | } |
2481 | 1777 | ||
2482 | if (req->key && req->key_len) { | 1778 | if (req->key && req->key_len) { |
2483 | wk->auth.key_len = req->key_len; | 1779 | wk->probe_auth.key_len = req->key_len; |
2484 | wk->auth.key_idx = req->key_idx; | 1780 | wk->probe_auth.key_idx = req->key_idx; |
2485 | memcpy(wk->auth.key, req->key, req->key_len); | 1781 | memcpy(wk->probe_auth.key, req->key, req->key_len); |
2486 | } | 1782 | } |
2487 | 1783 | ||
2488 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); | 1784 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); |
2489 | memcpy(wk->auth.ssid, ssid + 2, ssid[1]); | 1785 | memcpy(wk->probe_auth.ssid, ssid + 2, ssid[1]); |
2490 | wk->auth.ssid_len = ssid[1]; | 1786 | wk->probe_auth.ssid_len = ssid[1]; |
2491 | 1787 | ||
2492 | wk->auth.algorithm = auth_alg; | 1788 | wk->probe_auth.algorithm = auth_alg; |
2493 | wk->auth.privacy = req->bss->capability & WLAN_CAPABILITY_PRIVACY; | 1789 | wk->probe_auth.privacy = req->bss->capability & WLAN_CAPABILITY_PRIVACY; |
2494 | 1790 | ||
2495 | wk->type = IEEE80211_WORK_AUTH_PROBE; | 1791 | wk->type = IEEE80211_WORK_DIRECT_PROBE; |
2496 | wk->timeout = jiffies; /* run right away */ | ||
2497 | wk->chan = req->bss->channel; | 1792 | wk->chan = req->bss->channel; |
1793 | wk->sdata = sdata; | ||
1794 | wk->done = ieee80211_probe_auth_done; | ||
2498 | 1795 | ||
2499 | /* | 1796 | /* |
2500 | * XXX: if still associated need to tell AP that we're going | 1797 | * XXX: if still associated need to tell AP that we're going |
@@ -2505,29 +1802,58 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
2505 | sdata->local->oper_channel = req->bss->channel; | 1802 | sdata->local->oper_channel = req->bss->channel; |
2506 | ieee80211_hw_config(sdata->local, 0); | 1803 | ieee80211_hw_config(sdata->local, 0); |
2507 | 1804 | ||
2508 | mutex_lock(&ifmgd->mtx); | 1805 | ieee80211_add_work(wk); |
2509 | list_add(&wk->list, &sdata->u.mgd.work_list); | ||
2510 | mutex_unlock(&ifmgd->mtx); | ||
2511 | |||
2512 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work); | ||
2513 | return 0; | 1806 | return 0; |
2514 | } | 1807 | } |
2515 | 1808 | ||
1809 | static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, | ||
1810 | struct sk_buff *skb) | ||
1811 | { | ||
1812 | struct ieee80211_mgmt *mgmt; | ||
1813 | u16 status; | ||
1814 | |||
1815 | if (!skb) { | ||
1816 | cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta); | ||
1817 | return WORK_DONE_DESTROY; | ||
1818 | } | ||
1819 | |||
1820 | mgmt = (void *)skb->data; | ||
1821 | status = le16_to_cpu(mgmt->u.assoc_resp.status_code); | ||
1822 | |||
1823 | if (status == WLAN_STATUS_SUCCESS) { | ||
1824 | mutex_lock(&wk->sdata->u.mgd.mtx); | ||
1825 | if (!ieee80211_assoc_success(wk, mgmt, skb->len)) { | ||
1826 | mutex_unlock(&wk->sdata->u.mgd.mtx); | ||
1827 | /* oops -- internal error -- send timeout for now */ | ||
1828 | cfg80211_send_assoc_timeout(wk->sdata->dev, | ||
1829 | wk->filter_ta); | ||
1830 | return WORK_DONE_DESTROY; | ||
1831 | } | ||
1832 | mutex_unlock(&wk->sdata->u.mgd.mtx); | ||
1833 | } | ||
1834 | |||
1835 | cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len); | ||
1836 | return WORK_DONE_DESTROY; | ||
1837 | } | ||
1838 | |||
2516 | int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | 1839 | int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, |
2517 | struct cfg80211_assoc_request *req) | 1840 | struct cfg80211_assoc_request *req) |
2518 | { | 1841 | { |
2519 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1842 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2520 | struct ieee80211_work *wk; | 1843 | struct ieee80211_work *wk; |
2521 | const u8 *ssid; | 1844 | const u8 *ssid; |
2522 | int i, err; | 1845 | int i; |
2523 | 1846 | ||
2524 | mutex_lock(&ifmgd->mtx); | 1847 | mutex_lock(&ifmgd->mtx); |
1848 | if (ifmgd->associated) { | ||
1849 | mutex_unlock(&ifmgd->mtx); | ||
1850 | return -EALREADY; | ||
1851 | } | ||
1852 | mutex_unlock(&ifmgd->mtx); | ||
2525 | 1853 | ||
2526 | wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL); | 1854 | wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL); |
2527 | if (!wk) { | 1855 | if (!wk) |
2528 | err = -ENOMEM; | 1856 | return -ENOMEM; |
2529 | goto out; | ||
2530 | } | ||
2531 | 1857 | ||
2532 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; | 1858 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; |
2533 | 1859 | ||
@@ -2546,8 +1872,19 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2546 | 1872 | ||
2547 | wk->assoc.bss = (void *)req->bss; | 1873 | wk->assoc.bss = (void *)req->bss; |
2548 | 1874 | ||
2549 | memcpy(wk->assoc.bssid, req->bss->bssid, ETH_ALEN); | 1875 | memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN); |
2550 | 1876 | ||
1877 | /* new association always uses requested smps mode */ | ||
1878 | if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) { | ||
1879 | if (ifmgd->powersave) | ||
1880 | ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC; | ||
1881 | else | ||
1882 | ifmgd->ap_smps = IEEE80211_SMPS_OFF; | ||
1883 | } else | ||
1884 | ifmgd->ap_smps = ifmgd->req_smps; | ||
1885 | |||
1886 | wk->assoc.smps = ifmgd->ap_smps; | ||
1887 | wk->assoc.use_11n = !(ifmgd->flags & IEEE80211_STA_DISABLE_11N); | ||
2551 | wk->assoc.capability = req->bss->capability; | 1888 | wk->assoc.capability = req->bss->capability; |
2552 | wk->assoc.wmm_used = wk->assoc.bss->wmm_used; | 1889 | wk->assoc.wmm_used = wk->assoc.bss->wmm_used; |
2553 | wk->assoc.supp_rates = wk->assoc.bss->supp_rates; | 1890 | wk->assoc.supp_rates = wk->assoc.bss->supp_rates; |
@@ -2563,8 +1900,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2563 | memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN); | 1900 | memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN); |
2564 | 1901 | ||
2565 | wk->type = IEEE80211_WORK_ASSOC; | 1902 | wk->type = IEEE80211_WORK_ASSOC; |
2566 | wk->timeout = jiffies; /* run right away */ | ||
2567 | wk->chan = req->bss->channel; | 1903 | wk->chan = req->bss->channel; |
1904 | wk->sdata = sdata; | ||
1905 | wk->done = ieee80211_assoc_done; | ||
2568 | 1906 | ||
2569 | if (req->use_mfp) { | 1907 | if (req->use_mfp) { |
2570 | ifmgd->mfp = IEEE80211_MFP_REQUIRED; | 1908 | ifmgd->mfp = IEEE80211_MFP_REQUIRED; |
@@ -2582,56 +1920,56 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2582 | sdata->local->oper_channel = req->bss->channel; | 1920 | sdata->local->oper_channel = req->bss->channel; |
2583 | ieee80211_hw_config(sdata->local, 0); | 1921 | ieee80211_hw_config(sdata->local, 0); |
2584 | 1922 | ||
2585 | list_add(&wk->list, &ifmgd->work_list); | 1923 | ieee80211_add_work(wk); |
2586 | ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work); | 1924 | return 0; |
2587 | |||
2588 | err = 0; | ||
2589 | |||
2590 | out: | ||
2591 | mutex_unlock(&ifmgd->mtx); | ||
2592 | return err; | ||
2593 | } | 1925 | } |
2594 | 1926 | ||
2595 | int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | 1927 | int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, |
2596 | struct cfg80211_deauth_request *req, | 1928 | struct cfg80211_deauth_request *req, |
2597 | void *cookie) | 1929 | void *cookie) |
2598 | { | 1930 | { |
1931 | struct ieee80211_local *local = sdata->local; | ||
2599 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1932 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2600 | struct ieee80211_work *wk; | 1933 | struct ieee80211_work *wk; |
2601 | const u8 *bssid = req->bss->bssid; | 1934 | const u8 *bssid = req->bss->bssid; |
2602 | bool not_auth_yet = false; | ||
2603 | 1935 | ||
2604 | mutex_lock(&ifmgd->mtx); | 1936 | mutex_lock(&ifmgd->mtx); |
2605 | 1937 | ||
2606 | if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { | 1938 | if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { |
2607 | bssid = req->bss->bssid; | 1939 | bssid = req->bss->bssid; |
2608 | ieee80211_set_disassoc(sdata); | 1940 | ieee80211_set_disassoc(sdata); |
2609 | } else list_for_each_entry(wk, &ifmgd->work_list, list) { | 1941 | mutex_unlock(&ifmgd->mtx); |
2610 | if (wk->type != IEEE80211_WORK_AUTH_PROBE) | 1942 | } else { |
2611 | continue; | 1943 | bool not_auth_yet = false; |
2612 | if (memcmp(req->bss->bssid, wk->auth.bssid, ETH_ALEN)) | ||
2613 | continue; | ||
2614 | not_auth_yet = true; | ||
2615 | list_del(&wk->list); | ||
2616 | kfree(wk); | ||
2617 | break; | ||
2618 | } | ||
2619 | 1944 | ||
2620 | /* | ||
2621 | * If somebody requests authentication and we haven't | ||
2622 | * sent out an auth frame yet there's no need to send | ||
2623 | * out a deauth frame either. If the state was PROBE, | ||
2624 | * then this is the case. If it's AUTH we have sent a | ||
2625 | * frame, and if it's IDLE we have completed the auth | ||
2626 | * process already. | ||
2627 | */ | ||
2628 | if (not_auth_yet) { | ||
2629 | mutex_unlock(&ifmgd->mtx); | 1945 | mutex_unlock(&ifmgd->mtx); |
2630 | __cfg80211_auth_canceled(sdata->dev, bssid); | ||
2631 | return 0; | ||
2632 | } | ||
2633 | 1946 | ||
2634 | mutex_unlock(&ifmgd->mtx); | 1947 | mutex_lock(&local->work_mtx); |
1948 | list_for_each_entry(wk, &local->work_list, list) { | ||
1949 | if (wk->type != IEEE80211_WORK_DIRECT_PROBE) | ||
1950 | continue; | ||
1951 | if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN)) | ||
1952 | continue; | ||
1953 | not_auth_yet = true; | ||
1954 | list_del(&wk->list); | ||
1955 | free_work(wk); | ||
1956 | break; | ||
1957 | } | ||
1958 | mutex_unlock(&local->work_mtx); | ||
1959 | |||
1960 | /* | ||
1961 | * If somebody requests authentication and we haven't | ||
1962 | * sent out an auth frame yet there's no need to send | ||
1963 | * out a deauth frame either. If the state was PROBE, | ||
1964 | * then this is the case. If it's AUTH we have sent a | ||
1965 | * frame, and if it's IDLE we have completed the auth | ||
1966 | * process already. | ||
1967 | */ | ||
1968 | if (not_auth_yet) { | ||
1969 | __cfg80211_auth_canceled(sdata->dev, bssid); | ||
1970 | return 0; | ||
1971 | } | ||
1972 | } | ||
2635 | 1973 | ||
2636 | printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", | 1974 | printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", |
2637 | sdata->name, bssid, req->reason_code); | 1975 | sdata->name, bssid, req->reason_code); |