diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 1390 |
1 files changed, 1002 insertions, 388 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 49fd1acd5d15..52133dab9297 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -30,6 +30,12 @@ | |||
30 | #include "rate.h" | 30 | #include "rate.h" |
31 | #include "led.h" | 31 | #include "led.h" |
32 | 32 | ||
33 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) | ||
34 | #define IEEE80211_AUTH_MAX_TRIES 3 | ||
35 | #define IEEE80211_AUTH_WAIT_ASSOC (HZ * 5) | ||
36 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | ||
37 | #define IEEE80211_ASSOC_MAX_TRIES 3 | ||
38 | |||
33 | static int max_nullfunc_tries = 2; | 39 | static int max_nullfunc_tries = 2; |
34 | module_param(max_nullfunc_tries, int, 0644); | 40 | module_param(max_nullfunc_tries, int, 0644); |
35 | MODULE_PARM_DESC(max_nullfunc_tries, | 41 | MODULE_PARM_DESC(max_nullfunc_tries, |
@@ -97,6 +103,15 @@ enum rx_mgmt_action { | |||
97 | 103 | ||
98 | /* caller must call cfg80211_send_disassoc() */ | 104 | /* caller must call cfg80211_send_disassoc() */ |
99 | RX_MGMT_CFG80211_DISASSOC, | 105 | RX_MGMT_CFG80211_DISASSOC, |
106 | |||
107 | /* caller must call cfg80211_send_rx_auth() */ | ||
108 | RX_MGMT_CFG80211_RX_AUTH, | ||
109 | |||
110 | /* caller must call cfg80211_send_rx_assoc() */ | ||
111 | RX_MGMT_CFG80211_RX_ASSOC, | ||
112 | |||
113 | /* caller must call cfg80211_send_assoc_timeout() */ | ||
114 | RX_MGMT_CFG80211_ASSOC_TIMEOUT, | ||
100 | }; | 115 | }; |
101 | 116 | ||
102 | /* utils */ | 117 | /* utils */ |
@@ -115,8 +130,7 @@ static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd) | |||
115 | * has happened -- the work that runs from this timer will | 130 | * has happened -- the work that runs from this timer will |
116 | * do that. | 131 | * do that. |
117 | */ | 132 | */ |
118 | static void run_again(struct ieee80211_if_managed *ifmgd, | 133 | static void run_again(struct ieee80211_if_managed *ifmgd, unsigned long timeout) |
119 | unsigned long timeout) | ||
120 | { | 134 | { |
121 | ASSERT_MGD_MTX(ifmgd); | 135 | ASSERT_MGD_MTX(ifmgd); |
122 | 136 | ||
@@ -284,6 +298,319 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
284 | 298 | ||
285 | /* frame sending functions */ | 299 | /* frame sending functions */ |
286 | 300 | ||
301 | static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, | ||
302 | struct ieee80211_supported_band *sband, | ||
303 | u32 *rates) | ||
304 | { | ||
305 | int i, j, count; | ||
306 | *rates = 0; | ||
307 | count = 0; | ||
308 | for (i = 0; i < supp_rates_len; i++) { | ||
309 | int rate = (supp_rates[i] & 0x7F) * 5; | ||
310 | |||
311 | for (j = 0; j < sband->n_bitrates; j++) | ||
312 | if (sband->bitrates[j].bitrate == rate) { | ||
313 | *rates |= BIT(j); | ||
314 | count++; | ||
315 | break; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | return count; | ||
320 | } | ||
321 | |||
322 | static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, | ||
323 | struct sk_buff *skb, const u8 *ht_info_ie, | ||
324 | struct ieee80211_supported_band *sband, | ||
325 | struct ieee80211_channel *channel, | ||
326 | enum ieee80211_smps_mode smps) | ||
327 | { | ||
328 | struct ieee80211_ht_info *ht_info; | ||
329 | u8 *pos; | ||
330 | u32 flags = channel->flags; | ||
331 | u16 cap; | ||
332 | struct ieee80211_sta_ht_cap ht_cap; | ||
333 | |||
334 | BUILD_BUG_ON(sizeof(ht_cap) != sizeof(sband->ht_cap)); | ||
335 | |||
336 | if (!sband->ht_cap.ht_supported) | ||
337 | return; | ||
338 | |||
339 | if (!ht_info_ie) | ||
340 | return; | ||
341 | |||
342 | if (ht_info_ie[1] < sizeof(struct ieee80211_ht_info)) | ||
343 | return; | ||
344 | |||
345 | memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); | ||
346 | ieee80211_apply_htcap_overrides(sdata, &ht_cap); | ||
347 | |||
348 | ht_info = (struct ieee80211_ht_info *)(ht_info_ie + 2); | ||
349 | |||
350 | /* determine capability flags */ | ||
351 | cap = ht_cap.cap; | ||
352 | |||
353 | switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { | ||
354 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | ||
355 | if (flags & IEEE80211_CHAN_NO_HT40PLUS) { | ||
356 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
357 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
358 | } | ||
359 | break; | ||
360 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
361 | if (flags & IEEE80211_CHAN_NO_HT40MINUS) { | ||
362 | cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
363 | cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
364 | } | ||
365 | break; | ||
366 | } | ||
367 | |||
368 | /* set SM PS mode properly */ | ||
369 | cap &= ~IEEE80211_HT_CAP_SM_PS; | ||
370 | switch (smps) { | ||
371 | case IEEE80211_SMPS_AUTOMATIC: | ||
372 | case IEEE80211_SMPS_NUM_MODES: | ||
373 | WARN_ON(1); | ||
374 | case IEEE80211_SMPS_OFF: | ||
375 | cap |= WLAN_HT_CAP_SM_PS_DISABLED << | ||
376 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
377 | break; | ||
378 | case IEEE80211_SMPS_STATIC: | ||
379 | cap |= WLAN_HT_CAP_SM_PS_STATIC << | ||
380 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
381 | break; | ||
382 | case IEEE80211_SMPS_DYNAMIC: | ||
383 | cap |= WLAN_HT_CAP_SM_PS_DYNAMIC << | ||
384 | IEEE80211_HT_CAP_SM_PS_SHIFT; | ||
385 | break; | ||
386 | } | ||
387 | |||
388 | /* reserve and fill IE */ | ||
389 | pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2); | ||
390 | ieee80211_ie_build_ht_cap(pos, &ht_cap, cap); | ||
391 | } | ||
392 | |||
393 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | ||
394 | { | ||
395 | struct ieee80211_local *local = sdata->local; | ||
396 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
397 | struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; | ||
398 | struct sk_buff *skb; | ||
399 | struct ieee80211_mgmt *mgmt; | ||
400 | u8 *pos, qos_info; | ||
401 | size_t offset = 0, noffset; | ||
402 | int i, count, rates_len, supp_rates_len; | ||
403 | u16 capab; | ||
404 | struct ieee80211_supported_band *sband; | ||
405 | u32 rates = 0; | ||
406 | struct ieee80211_bss *bss = (void *)assoc_data->bss->priv; | ||
407 | |||
408 | lockdep_assert_held(&ifmgd->mtx); | ||
409 | |||
410 | sband = local->hw.wiphy->bands[local->oper_channel->band]; | ||
411 | |||
412 | if (assoc_data->supp_rates_len) { | ||
413 | /* | ||
414 | * Get all rates supported by the device and the AP as | ||
415 | * some APs don't like getting a superset of their rates | ||
416 | * in the association request (e.g. D-Link DAP 1353 in | ||
417 | * b-only mode)... | ||
418 | */ | ||
419 | rates_len = ieee80211_compatible_rates(assoc_data->supp_rates, | ||
420 | assoc_data->supp_rates_len, | ||
421 | sband, &rates); | ||
422 | } else { | ||
423 | /* | ||
424 | * In case AP not provide any supported rates information | ||
425 | * before association, we send information element(s) with | ||
426 | * all rates that we support. | ||
427 | */ | ||
428 | rates = ~0; | ||
429 | rates_len = sband->n_bitrates; | ||
430 | } | ||
431 | |||
432 | skb = alloc_skb(local->hw.extra_tx_headroom + | ||
433 | sizeof(*mgmt) + /* bit too much but doesn't matter */ | ||
434 | 2 + assoc_data->ssid_len + /* SSID */ | ||
435 | 4 + rates_len + /* (extended) rates */ | ||
436 | 4 + /* power capability */ | ||
437 | 2 + 2 * sband->n_channels + /* supported channels */ | ||
438 | 2 + sizeof(struct ieee80211_ht_cap) + /* HT */ | ||
439 | assoc_data->ie_len + /* extra IEs */ | ||
440 | 9, /* WMM */ | ||
441 | GFP_KERNEL); | ||
442 | if (!skb) | ||
443 | return; | ||
444 | |||
445 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
446 | |||
447 | capab = WLAN_CAPABILITY_ESS; | ||
448 | |||
449 | if (sband->band == IEEE80211_BAND_2GHZ) { | ||
450 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) | ||
451 | capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; | ||
452 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) | ||
453 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; | ||
454 | } | ||
455 | |||
456 | if (assoc_data->capability & WLAN_CAPABILITY_PRIVACY) | ||
457 | capab |= WLAN_CAPABILITY_PRIVACY; | ||
458 | |||
459 | if ((assoc_data->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && | ||
460 | (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) | ||
461 | capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; | ||
462 | |||
463 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
464 | memset(mgmt, 0, 24); | ||
465 | memcpy(mgmt->da, assoc_data->bss->bssid, ETH_ALEN); | ||
466 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); | ||
467 | memcpy(mgmt->bssid, assoc_data->bss->bssid, ETH_ALEN); | ||
468 | |||
469 | if (!is_zero_ether_addr(assoc_data->prev_bssid)) { | ||
470 | skb_put(skb, 10); | ||
471 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
472 | IEEE80211_STYPE_REASSOC_REQ); | ||
473 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); | ||
474 | mgmt->u.reassoc_req.listen_interval = | ||
475 | cpu_to_le16(local->hw.conf.listen_interval); | ||
476 | memcpy(mgmt->u.reassoc_req.current_ap, assoc_data->prev_bssid, | ||
477 | ETH_ALEN); | ||
478 | } else { | ||
479 | skb_put(skb, 4); | ||
480 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
481 | IEEE80211_STYPE_ASSOC_REQ); | ||
482 | mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); | ||
483 | mgmt->u.assoc_req.listen_interval = | ||
484 | cpu_to_le16(local->hw.conf.listen_interval); | ||
485 | } | ||
486 | |||
487 | /* SSID */ | ||
488 | pos = skb_put(skb, 2 + assoc_data->ssid_len); | ||
489 | *pos++ = WLAN_EID_SSID; | ||
490 | *pos++ = assoc_data->ssid_len; | ||
491 | memcpy(pos, assoc_data->ssid, assoc_data->ssid_len); | ||
492 | |||
493 | /* add all rates which were marked to be used above */ | ||
494 | supp_rates_len = rates_len; | ||
495 | if (supp_rates_len > 8) | ||
496 | supp_rates_len = 8; | ||
497 | |||
498 | pos = skb_put(skb, supp_rates_len + 2); | ||
499 | *pos++ = WLAN_EID_SUPP_RATES; | ||
500 | *pos++ = supp_rates_len; | ||
501 | |||
502 | count = 0; | ||
503 | for (i = 0; i < sband->n_bitrates; i++) { | ||
504 | if (BIT(i) & rates) { | ||
505 | int rate = sband->bitrates[i].bitrate; | ||
506 | *pos++ = (u8) (rate / 5); | ||
507 | if (++count == 8) | ||
508 | break; | ||
509 | } | ||
510 | } | ||
511 | |||
512 | if (rates_len > count) { | ||
513 | pos = skb_put(skb, rates_len - count + 2); | ||
514 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
515 | *pos++ = rates_len - count; | ||
516 | |||
517 | for (i++; i < sband->n_bitrates; i++) { | ||
518 | if (BIT(i) & rates) { | ||
519 | int rate = sband->bitrates[i].bitrate; | ||
520 | *pos++ = (u8) (rate / 5); | ||
521 | } | ||
522 | } | ||
523 | } | ||
524 | |||
525 | if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT) { | ||
526 | /* 1. power capabilities */ | ||
527 | pos = skb_put(skb, 4); | ||
528 | *pos++ = WLAN_EID_PWR_CAPABILITY; | ||
529 | *pos++ = 2; | ||
530 | *pos++ = 0; /* min tx power */ | ||
531 | *pos++ = local->oper_channel->max_power; /* max tx power */ | ||
532 | |||
533 | /* 2. supported channels */ | ||
534 | /* TODO: get this in reg domain format */ | ||
535 | pos = skb_put(skb, 2 * sband->n_channels + 2); | ||
536 | *pos++ = WLAN_EID_SUPPORTED_CHANNELS; | ||
537 | *pos++ = 2 * sband->n_channels; | ||
538 | for (i = 0; i < sband->n_channels; i++) { | ||
539 | *pos++ = ieee80211_frequency_to_channel( | ||
540 | sband->channels[i].center_freq); | ||
541 | *pos++ = 1; /* one channel in the subband*/ | ||
542 | } | ||
543 | } | ||
544 | |||
545 | /* if present, add any custom IEs that go before HT */ | ||
546 | if (assoc_data->ie_len && assoc_data->ie) { | ||
547 | static const u8 before_ht[] = { | ||
548 | WLAN_EID_SSID, | ||
549 | WLAN_EID_SUPP_RATES, | ||
550 | WLAN_EID_EXT_SUPP_RATES, | ||
551 | WLAN_EID_PWR_CAPABILITY, | ||
552 | WLAN_EID_SUPPORTED_CHANNELS, | ||
553 | WLAN_EID_RSN, | ||
554 | WLAN_EID_QOS_CAPA, | ||
555 | WLAN_EID_RRM_ENABLED_CAPABILITIES, | ||
556 | WLAN_EID_MOBILITY_DOMAIN, | ||
557 | WLAN_EID_SUPPORTED_REGULATORY_CLASSES, | ||
558 | }; | ||
559 | noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len, | ||
560 | before_ht, ARRAY_SIZE(before_ht), | ||
561 | offset); | ||
562 | pos = skb_put(skb, noffset - offset); | ||
563 | memcpy(pos, assoc_data->ie + offset, noffset - offset); | ||
564 | offset = noffset; | ||
565 | } | ||
566 | |||
567 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N) && | ||
568 | bss->wmm_used && local->hw.queues >= 4) | ||
569 | ieee80211_add_ht_ie(sdata, skb, assoc_data->ht_information_ie, | ||
570 | sband, local->oper_channel, ifmgd->ap_smps); | ||
571 | |||
572 | /* if present, add any custom non-vendor IEs that go after HT */ | ||
573 | if (assoc_data->ie_len && assoc_data->ie) { | ||
574 | noffset = ieee80211_ie_split_vendor(assoc_data->ie, | ||
575 | assoc_data->ie_len, | ||
576 | offset); | ||
577 | pos = skb_put(skb, noffset - offset); | ||
578 | memcpy(pos, assoc_data->ie + offset, noffset - offset); | ||
579 | offset = noffset; | ||
580 | } | ||
581 | |||
582 | if (assoc_data->wmm_used && local->hw.queues >= 4) { | ||
583 | if (assoc_data->uapsd_used) { | ||
584 | qos_info = local->uapsd_queues; | ||
585 | qos_info |= (local->uapsd_max_sp_len << | ||
586 | IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT); | ||
587 | } else { | ||
588 | qos_info = 0; | ||
589 | } | ||
590 | |||
591 | pos = skb_put(skb, 9); | ||
592 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | ||
593 | *pos++ = 7; /* len */ | ||
594 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ | ||
595 | *pos++ = 0x50; | ||
596 | *pos++ = 0xf2; | ||
597 | *pos++ = 2; /* WME */ | ||
598 | *pos++ = 0; /* WME info */ | ||
599 | *pos++ = 1; /* WME ver */ | ||
600 | *pos++ = qos_info; | ||
601 | } | ||
602 | |||
603 | /* add any remaining custom (i.e. vendor specific here) IEs */ | ||
604 | if (assoc_data->ie_len && assoc_data->ie) { | ||
605 | noffset = assoc_data->ie_len; | ||
606 | pos = skb_put(skb, noffset - offset); | ||
607 | memcpy(pos, assoc_data->ie + offset, noffset - offset); | ||
608 | } | ||
609 | |||
610 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | ||
611 | ieee80211_tx_skb(sdata, skb); | ||
612 | } | ||
613 | |||
287 | static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | 614 | static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, |
288 | const u8 *bssid, u16 stype, u16 reason, | 615 | const u8 *bssid, u16 stype, u16 reason, |
289 | void *cookie, bool send_frame) | 616 | void *cookie, bool send_frame) |
@@ -1423,6 +1750,135 @@ void ieee80211_connection_loss(struct ieee80211_vif *vif) | |||
1423 | EXPORT_SYMBOL(ieee80211_connection_loss); | 1750 | EXPORT_SYMBOL(ieee80211_connection_loss); |
1424 | 1751 | ||
1425 | 1752 | ||
1753 | static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, | ||
1754 | bool assoc) | ||
1755 | { | ||
1756 | struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data; | ||
1757 | |||
1758 | lockdep_assert_held(&sdata->u.mgd.mtx); | ||
1759 | |||
1760 | if (auth_data->synced) | ||
1761 | drv_finish_tx_sync(sdata->local, sdata, | ||
1762 | auth_data->bss->bssid, | ||
1763 | IEEE80211_TX_SYNC_AUTH); | ||
1764 | |||
1765 | if (!assoc) { | ||
1766 | sta_info_destroy_addr(sdata, auth_data->bss->bssid); | ||
1767 | |||
1768 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); | ||
1769 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); | ||
1770 | } | ||
1771 | |||
1772 | cfg80211_put_bss(auth_data->bss); | ||
1773 | kfree(auth_data); | ||
1774 | sdata->u.mgd.auth_data = NULL; | ||
1775 | } | ||
1776 | |||
1777 | static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | ||
1778 | struct ieee80211_mgmt *mgmt, size_t len) | ||
1779 | { | ||
1780 | struct ieee80211_mgd_auth_data *auth_data = sdata->u.mgd.auth_data; | ||
1781 | u8 *pos; | ||
1782 | struct ieee802_11_elems elems; | ||
1783 | |||
1784 | pos = mgmt->u.auth.variable; | ||
1785 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
1786 | if (!elems.challenge) | ||
1787 | return; | ||
1788 | auth_data->expected_transaction = 4; | ||
1789 | ieee80211_send_auth(sdata, 3, auth_data->algorithm, | ||
1790 | elems.challenge - 2, elems.challenge_len + 2, | ||
1791 | auth_data->bss->bssid, auth_data->bss->bssid, | ||
1792 | auth_data->key, auth_data->key_len, | ||
1793 | auth_data->key_idx); | ||
1794 | } | ||
1795 | |||
1796 | static enum rx_mgmt_action __must_check | ||
1797 | ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | ||
1798 | struct ieee80211_mgmt *mgmt, size_t len) | ||
1799 | { | ||
1800 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1801 | u8 bssid[ETH_ALEN]; | ||
1802 | u16 auth_alg, auth_transaction, status_code; | ||
1803 | struct sta_info *sta; | ||
1804 | |||
1805 | lockdep_assert_held(&ifmgd->mtx); | ||
1806 | |||
1807 | if (len < 24 + 6) | ||
1808 | return RX_MGMT_NONE; | ||
1809 | |||
1810 | if (!ifmgd->auth_data || ifmgd->auth_data->done) | ||
1811 | return RX_MGMT_NONE; | ||
1812 | |||
1813 | memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN); | ||
1814 | |||
1815 | if (memcmp(bssid, mgmt->bssid, ETH_ALEN)) | ||
1816 | return RX_MGMT_NONE; | ||
1817 | |||
1818 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | ||
1819 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | ||
1820 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | ||
1821 | |||
1822 | if (auth_alg != ifmgd->auth_data->algorithm || | ||
1823 | auth_transaction != ifmgd->auth_data->expected_transaction) | ||
1824 | return RX_MGMT_NONE; | ||
1825 | |||
1826 | if (status_code != WLAN_STATUS_SUCCESS) { | ||
1827 | printk(KERN_DEBUG "%s: %pM denied authentication (status %d)\n", | ||
1828 | sdata->name, mgmt->sa, status_code); | ||
1829 | goto out; | ||
1830 | } | ||
1831 | |||
1832 | switch (ifmgd->auth_data->algorithm) { | ||
1833 | case WLAN_AUTH_OPEN: | ||
1834 | case WLAN_AUTH_LEAP: | ||
1835 | case WLAN_AUTH_FT: | ||
1836 | break; | ||
1837 | case WLAN_AUTH_SHARED_KEY: | ||
1838 | if (ifmgd->auth_data->expected_transaction != 4) { | ||
1839 | ieee80211_auth_challenge(sdata, mgmt, len); | ||
1840 | /* need another frame */ | ||
1841 | return RX_MGMT_NONE; | ||
1842 | } | ||
1843 | break; | ||
1844 | default: | ||
1845 | WARN_ONCE(1, "invalid auth alg %d", | ||
1846 | ifmgd->auth_data->algorithm); | ||
1847 | return RX_MGMT_NONE; | ||
1848 | } | ||
1849 | |||
1850 | printk(KERN_DEBUG "%s: authenticated\n", sdata->name); | ||
1851 | out: | ||
1852 | if (ifmgd->auth_data->synced) | ||
1853 | drv_finish_tx_sync(sdata->local, sdata, bssid, | ||
1854 | IEEE80211_TX_SYNC_AUTH); | ||
1855 | ifmgd->auth_data->synced = false; | ||
1856 | ifmgd->auth_data->done = true; | ||
1857 | ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; | ||
1858 | run_again(ifmgd, ifmgd->auth_data->timeout); | ||
1859 | |||
1860 | /* move station state to auth */ | ||
1861 | mutex_lock(&sdata->local->sta_mtx); | ||
1862 | sta = sta_info_get(sdata, bssid); | ||
1863 | if (!sta) { | ||
1864 | WARN_ONCE(1, "%s: STA %pM not found", sdata->name, bssid); | ||
1865 | goto out_err; | ||
1866 | } | ||
1867 | if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) { | ||
1868 | printk(KERN_DEBUG "%s: failed moving %pM to auth\n", | ||
1869 | sdata->name, bssid); | ||
1870 | goto out_err; | ||
1871 | } | ||
1872 | mutex_unlock(&sdata->local->sta_mtx); | ||
1873 | |||
1874 | return RX_MGMT_CFG80211_RX_AUTH; | ||
1875 | out_err: | ||
1876 | mutex_unlock(&sdata->local->sta_mtx); | ||
1877 | /* ignore frame -- wait for timeout */ | ||
1878 | return RX_MGMT_NONE; | ||
1879 | } | ||
1880 | |||
1881 | |||
1426 | static enum rx_mgmt_action __must_check | 1882 | static enum rx_mgmt_action __must_check |
1427 | ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | 1883 | ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, |
1428 | struct ieee80211_mgmt *mgmt, size_t len) | 1884 | struct ieee80211_mgmt *mgmt, size_t len) |
@@ -1431,10 +1887,14 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
1431 | const u8 *bssid = NULL; | 1887 | const u8 *bssid = NULL; |
1432 | u16 reason_code; | 1888 | u16 reason_code; |
1433 | 1889 | ||
1890 | lockdep_assert_held(&ifmgd->mtx); | ||
1891 | |||
1434 | if (len < 24 + 2) | 1892 | if (len < 24 + 2) |
1435 | return RX_MGMT_NONE; | 1893 | return RX_MGMT_NONE; |
1436 | 1894 | ||
1437 | ASSERT_MGD_MTX(ifmgd); | 1895 | if (!ifmgd->associated || |
1896 | memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN)) | ||
1897 | return RX_MGMT_NONE; | ||
1438 | 1898 | ||
1439 | bssid = ifmgd->associated->bssid; | 1899 | bssid = ifmgd->associated->bssid; |
1440 | 1900 | ||
@@ -1459,15 +1919,13 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1459 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1919 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1460 | u16 reason_code; | 1920 | u16 reason_code; |
1461 | 1921 | ||
1462 | if (len < 24 + 2) | 1922 | lockdep_assert_held(&ifmgd->mtx); |
1463 | return RX_MGMT_NONE; | ||
1464 | |||
1465 | ASSERT_MGD_MTX(ifmgd); | ||
1466 | 1923 | ||
1467 | if (WARN_ON(!ifmgd->associated)) | 1924 | if (len < 24 + 2) |
1468 | return RX_MGMT_NONE; | 1925 | return RX_MGMT_NONE; |
1469 | 1926 | ||
1470 | if (WARN_ON(memcmp(ifmgd->associated->bssid, mgmt->sa, ETH_ALEN))) | 1927 | if (!ifmgd->associated || |
1928 | memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN)) | ||
1471 | return RX_MGMT_NONE; | 1929 | return RX_MGMT_NONE; |
1472 | 1930 | ||
1473 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); | 1931 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
@@ -1524,15 +1982,37 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband, | |||
1524 | } | 1982 | } |
1525 | } | 1983 | } |
1526 | 1984 | ||
1527 | static bool ieee80211_assoc_success(struct ieee80211_work *wk, | 1985 | static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, |
1986 | bool assoc) | ||
1987 | { | ||
1988 | struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data; | ||
1989 | |||
1990 | lockdep_assert_held(&sdata->u.mgd.mtx); | ||
1991 | |||
1992 | if (assoc_data->synced) | ||
1993 | drv_finish_tx_sync(sdata->local, sdata, | ||
1994 | assoc_data->bss->bssid, | ||
1995 | IEEE80211_TX_SYNC_ASSOC); | ||
1996 | |||
1997 | if (!assoc) { | ||
1998 | sta_info_destroy_addr(sdata, assoc_data->bss->bssid); | ||
1999 | |||
2000 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); | ||
2001 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); | ||
2002 | } | ||
2003 | |||
2004 | kfree(assoc_data); | ||
2005 | sdata->u.mgd.assoc_data = NULL; | ||
2006 | } | ||
2007 | |||
2008 | static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | ||
2009 | struct cfg80211_bss *cbss, | ||
1528 | struct ieee80211_mgmt *mgmt, size_t len) | 2010 | struct ieee80211_mgmt *mgmt, size_t len) |
1529 | { | 2011 | { |
1530 | struct ieee80211_sub_if_data *sdata = wk->sdata; | ||
1531 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2012 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1532 | struct ieee80211_local *local = sdata->local; | 2013 | struct ieee80211_local *local = sdata->local; |
1533 | struct ieee80211_supported_band *sband; | 2014 | struct ieee80211_supported_band *sband; |
1534 | struct sta_info *sta; | 2015 | struct sta_info *sta; |
1535 | struct cfg80211_bss *cbss = wk->assoc.bss; | ||
1536 | u8 *pos; | 2016 | u8 *pos; |
1537 | u32 rates, basic_rates; | 2017 | u32 rates, basic_rates; |
1538 | u16 capab_info, aid; | 2018 | u16 capab_info, aid; |
@@ -1581,29 +2061,15 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1581 | * station info was already allocated and inserted before | 2061 | * station info was already allocated and inserted before |
1582 | * the association and should be available to us | 2062 | * the association and should be available to us |
1583 | */ | 2063 | */ |
1584 | sta = sta_info_get_rx(sdata, cbss->bssid); | 2064 | sta = sta_info_get(sdata, cbss->bssid); |
1585 | if (WARN_ON(!sta)) { | 2065 | if (WARN_ON(!sta)) { |
1586 | mutex_unlock(&sdata->local->sta_mtx); | 2066 | mutex_unlock(&sdata->local->sta_mtx); |
1587 | return false; | 2067 | return false; |
1588 | } | 2068 | } |
1589 | 2069 | ||
1590 | err = sta_info_move_state(sta, IEEE80211_STA_AUTH); | ||
1591 | if (!err) | ||
1592 | err = sta_info_move_state(sta, IEEE80211_STA_ASSOC); | ||
1593 | if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) | ||
1594 | err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); | ||
1595 | if (err) { | ||
1596 | printk(KERN_DEBUG | ||
1597 | "%s: failed to move station %pM to desired state\n", | ||
1598 | sdata->name, sta->sta.addr); | ||
1599 | WARN_ON(__sta_info_destroy(sta)); | ||
1600 | mutex_unlock(&sdata->local->sta_mtx); | ||
1601 | return false; | ||
1602 | } | ||
1603 | |||
1604 | rates = 0; | 2070 | rates = 0; |
1605 | basic_rates = 0; | 2071 | basic_rates = 0; |
1606 | sband = local->hw.wiphy->bands[wk->chan->band]; | 2072 | sband = local->hw.wiphy->bands[local->oper_channel->band]; |
1607 | 2073 | ||
1608 | ieee80211_get_rates(sband, elems.supp_rates, elems.supp_rates_len, | 2074 | ieee80211_get_rates(sband, elems.supp_rates, elems.supp_rates_len, |
1609 | &rates, &basic_rates, &have_higher_than_11mbit, | 2075 | &rates, &basic_rates, &have_higher_than_11mbit, |
@@ -1624,11 +2090,11 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1624 | basic_rates = BIT(min_rate_index); | 2090 | basic_rates = BIT(min_rate_index); |
1625 | } | 2091 | } |
1626 | 2092 | ||
1627 | sta->sta.supp_rates[wk->chan->band] = rates; | 2093 | sta->sta.supp_rates[local->oper_channel->band] = rates; |
1628 | sdata->vif.bss_conf.basic_rates = basic_rates; | 2094 | sdata->vif.bss_conf.basic_rates = basic_rates; |
1629 | 2095 | ||
1630 | /* cf. IEEE 802.11 9.2.12 */ | 2096 | /* cf. IEEE 802.11 9.2.12 */ |
1631 | if (wk->chan->band == IEEE80211_BAND_2GHZ && | 2097 | if (local->oper_channel->band == IEEE80211_BAND_2GHZ && |
1632 | have_higher_than_11mbit) | 2098 | have_higher_than_11mbit) |
1633 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | 2099 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; |
1634 | else | 2100 | else |
@@ -1648,15 +2114,22 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1648 | if (elems.wmm_param) | 2114 | if (elems.wmm_param) |
1649 | set_sta_flag(sta, WLAN_STA_WME); | 2115 | set_sta_flag(sta, WLAN_STA_WME); |
1650 | 2116 | ||
1651 | /* sta_info_reinsert will also unlock the mutex lock */ | 2117 | err = sta_info_move_state(sta, IEEE80211_STA_AUTH); |
1652 | err = sta_info_reinsert(sta); | 2118 | if (!err) |
1653 | sta = NULL; | 2119 | err = sta_info_move_state(sta, IEEE80211_STA_ASSOC); |
2120 | if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) | ||
2121 | err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); | ||
1654 | if (err) { | 2122 | if (err) { |
1655 | printk(KERN_DEBUG "%s: failed to insert STA entry for" | 2123 | printk(KERN_DEBUG |
1656 | " the AP (error %d)\n", sdata->name, err); | 2124 | "%s: failed to move station %pM to desired state\n", |
2125 | sdata->name, sta->sta.addr); | ||
2126 | WARN_ON(__sta_info_destroy(sta)); | ||
2127 | mutex_unlock(&sdata->local->sta_mtx); | ||
1657 | return false; | 2128 | return false; |
1658 | } | 2129 | } |
1659 | 2130 | ||
2131 | mutex_unlock(&sdata->local->sta_mtx); | ||
2132 | |||
1660 | /* | 2133 | /* |
1661 | * Always handle WMM once after association regardless | 2134 | * Always handle WMM once after association regardless |
1662 | * of the first value the AP uses. Setting -1 here has | 2135 | * of the first value the AP uses. Setting -1 here has |
@@ -1671,8 +2144,6 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1671 | else | 2144 | else |
1672 | ieee80211_set_wmm_default(sdata); | 2145 | ieee80211_set_wmm_default(sdata); |
1673 | 2146 | ||
1674 | local->oper_channel = wk->chan; | ||
1675 | |||
1676 | if (elems.ht_info_elem && elems.wmm_param && | 2147 | if (elems.ht_info_elem && elems.wmm_param && |
1677 | (sdata->local->hw.queues >= 4) && | 2148 | (sdata->local->hw.queues >= 4) && |
1678 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) | 2149 | !(ifmgd->flags & IEEE80211_STA_DISABLE_11N)) |
@@ -1703,7 +2174,82 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, | |||
1703 | return true; | 2174 | return true; |
1704 | } | 2175 | } |
1705 | 2176 | ||
2177 | static enum rx_mgmt_action __must_check | ||
2178 | ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | ||
2179 | struct ieee80211_mgmt *mgmt, size_t len, | ||
2180 | struct cfg80211_bss **bss) | ||
2181 | { | ||
2182 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2183 | struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; | ||
2184 | u16 capab_info, status_code, aid; | ||
2185 | struct ieee802_11_elems elems; | ||
2186 | u8 *pos; | ||
2187 | bool reassoc; | ||
2188 | |||
2189 | lockdep_assert_held(&ifmgd->mtx); | ||
2190 | |||
2191 | if (!assoc_data) | ||
2192 | return RX_MGMT_NONE; | ||
2193 | if (memcmp(assoc_data->bss->bssid, mgmt->bssid, ETH_ALEN)) | ||
2194 | return RX_MGMT_NONE; | ||
1706 | 2195 | ||
2196 | /* | ||
2197 | * AssocResp and ReassocResp have identical structure, so process both | ||
2198 | * of them in this function. | ||
2199 | */ | ||
2200 | |||
2201 | if (len < 24 + 6) | ||
2202 | return RX_MGMT_NONE; | ||
2203 | |||
2204 | reassoc = ieee80211_is_reassoc_req(mgmt->frame_control); | ||
2205 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | ||
2206 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | ||
2207 | aid = le16_to_cpu(mgmt->u.assoc_resp.aid); | ||
2208 | |||
2209 | printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x " | ||
2210 | "status=%d aid=%d)\n", | ||
2211 | sdata->name, reassoc ? "Rea" : "A", mgmt->sa, | ||
2212 | capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); | ||
2213 | |||
2214 | pos = mgmt->u.assoc_resp.variable; | ||
2215 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | ||
2216 | |||
2217 | if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && | ||
2218 | elems.timeout_int && elems.timeout_int_len == 5 && | ||
2219 | elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) { | ||
2220 | u32 tu, ms; | ||
2221 | tu = get_unaligned_le32(elems.timeout_int + 1); | ||
2222 | ms = tu * 1024 / 1000; | ||
2223 | printk(KERN_DEBUG "%s: %pM rejected association temporarily; " | ||
2224 | "comeback duration %u TU (%u ms)\n", | ||
2225 | sdata->name, mgmt->sa, tu, ms); | ||
2226 | assoc_data->timeout = jiffies + msecs_to_jiffies(ms); | ||
2227 | if (ms > IEEE80211_ASSOC_TIMEOUT) | ||
2228 | run_again(ifmgd, assoc_data->timeout); | ||
2229 | return RX_MGMT_NONE; | ||
2230 | } | ||
2231 | |||
2232 | *bss = assoc_data->bss; | ||
2233 | |||
2234 | if (status_code != WLAN_STATUS_SUCCESS) { | ||
2235 | printk(KERN_DEBUG "%s: %pM denied association (code=%d)\n", | ||
2236 | sdata->name, mgmt->sa, status_code); | ||
2237 | ieee80211_destroy_assoc_data(sdata, false); | ||
2238 | } else { | ||
2239 | printk(KERN_DEBUG "%s: associated\n", sdata->name); | ||
2240 | |||
2241 | ieee80211_destroy_assoc_data(sdata, true); | ||
2242 | |||
2243 | if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) { | ||
2244 | /* oops -- internal error -- send timeout for now */ | ||
2245 | sta_info_destroy_addr(sdata, mgmt->bssid); | ||
2246 | cfg80211_put_bss(*bss); | ||
2247 | return RX_MGMT_CFG80211_ASSOC_TIMEOUT; | ||
2248 | } | ||
2249 | } | ||
2250 | |||
2251 | return RX_MGMT_CFG80211_RX_ASSOC; | ||
2252 | } | ||
1707 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | 2253 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, |
1708 | struct ieee80211_mgmt *mgmt, | 2254 | struct ieee80211_mgmt *mgmt, |
1709 | size_t len, | 2255 | size_t len, |
@@ -1717,7 +2263,9 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1717 | struct ieee80211_channel *channel; | 2263 | struct ieee80211_channel *channel; |
1718 | bool need_ps = false; | 2264 | bool need_ps = false; |
1719 | 2265 | ||
1720 | if (sdata->u.mgd.associated) { | 2266 | if (sdata->u.mgd.associated && |
2267 | memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, | ||
2268 | ETH_ALEN) == 0) { | ||
1721 | bss = (void *)sdata->u.mgd.associated->priv; | 2269 | bss = (void *)sdata->u.mgd.associated->priv; |
1722 | /* not previously set so we may need to recalc */ | 2270 | /* not previously set so we may need to recalc */ |
1723 | need_ps = !bss->dtim_period; | 2271 | need_ps = !bss->dtim_period; |
@@ -1787,6 +2335,15 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1787 | if (ifmgd->associated && | 2335 | if (ifmgd->associated && |
1788 | memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0) | 2336 | memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0) |
1789 | ieee80211_reset_ap_probe(sdata); | 2337 | ieee80211_reset_ap_probe(sdata); |
2338 | |||
2339 | if (ifmgd->auth_data && !ifmgd->auth_data->bss->proberesp_ies && | ||
2340 | memcmp(mgmt->bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN) == 0) { | ||
2341 | /* got probe response, continue with auth */ | ||
2342 | printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name); | ||
2343 | ifmgd->auth_data->tries = 0; | ||
2344 | ifmgd->auth_data->timeout = jiffies; | ||
2345 | run_again(ifmgd, ifmgd->auth_data->timeout); | ||
2346 | } | ||
1790 | } | 2347 | } |
1791 | 2348 | ||
1792 | /* | 2349 | /* |
@@ -1826,7 +2383,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1826 | u32 ncrc; | 2383 | u32 ncrc; |
1827 | u8 *bssid; | 2384 | u8 *bssid; |
1828 | 2385 | ||
1829 | ASSERT_MGD_MTX(ifmgd); | 2386 | lockdep_assert_held(&ifmgd->mtx); |
1830 | 2387 | ||
1831 | /* Process beacon from the current BSS */ | 2388 | /* Process beacon from the current BSS */ |
1832 | baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; | 2389 | baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; |
@@ -1836,21 +2393,25 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1836 | if (rx_status->freq != local->hw.conf.channel->center_freq) | 2393 | if (rx_status->freq != local->hw.conf.channel->center_freq) |
1837 | return; | 2394 | return; |
1838 | 2395 | ||
1839 | /* | 2396 | if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon && |
1840 | * We might have received a number of frames, among them a | 2397 | memcmp(mgmt->bssid, ifmgd->assoc_data->bss->bssid, ETH_ALEN) == 0) { |
1841 | * disassoc frame and a beacon... | 2398 | ieee802_11_parse_elems(mgmt->u.beacon.variable, |
1842 | */ | 2399 | len - baselen, &elems); |
1843 | if (!ifmgd->associated) | ||
1844 | return; | ||
1845 | 2400 | ||
1846 | bssid = ifmgd->associated->bssid; | 2401 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, |
2402 | false); | ||
2403 | ifmgd->assoc_data->have_beacon = true; | ||
2404 | ifmgd->assoc_data->sent_assoc = false; | ||
2405 | /* continue assoc process */ | ||
2406 | ifmgd->assoc_data->timeout = jiffies; | ||
2407 | run_again(ifmgd, ifmgd->assoc_data->timeout); | ||
2408 | return; | ||
2409 | } | ||
1847 | 2410 | ||
1848 | /* | 2411 | if (!ifmgd->associated || |
1849 | * And in theory even frames from a different AP we were just | 2412 | memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN)) |
1850 | * associated to a split-second ago! | ||
1851 | */ | ||
1852 | if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0) | ||
1853 | return; | 2413 | return; |
2414 | bssid = ifmgd->associated->bssid; | ||
1854 | 2415 | ||
1855 | /* Track average RSSI from the Beacon frames of the current AP */ | 2416 | /* Track average RSSI from the Beacon frames of the current AP */ |
1856 | ifmgd->last_beacon_signal = rx_status->signal; | 2417 | ifmgd->last_beacon_signal = rx_status->signal; |
@@ -2034,6 +2595,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
2034 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2595 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2035 | struct ieee80211_rx_status *rx_status; | 2596 | struct ieee80211_rx_status *rx_status; |
2036 | struct ieee80211_mgmt *mgmt; | 2597 | struct ieee80211_mgmt *mgmt; |
2598 | struct cfg80211_bss *bss = NULL; | ||
2037 | enum rx_mgmt_action rma = RX_MGMT_NONE; | 2599 | enum rx_mgmt_action rma = RX_MGMT_NONE; |
2038 | u16 fc; | 2600 | u16 fc; |
2039 | 2601 | ||
@@ -2043,92 +2605,59 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
2043 | 2605 | ||
2044 | mutex_lock(&ifmgd->mtx); | 2606 | mutex_lock(&ifmgd->mtx); |
2045 | 2607 | ||
2046 | if (ifmgd->associated && | 2608 | switch (fc & IEEE80211_FCTL_STYPE) { |
2047 | memcmp(ifmgd->associated->bssid, mgmt->bssid, ETH_ALEN) == 0) { | 2609 | case IEEE80211_STYPE_BEACON: |
2048 | switch (fc & IEEE80211_FCTL_STYPE) { | 2610 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status); |
2049 | case IEEE80211_STYPE_BEACON: | 2611 | break; |
2050 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, | 2612 | case IEEE80211_STYPE_PROBE_RESP: |
2051 | rx_status); | 2613 | ieee80211_rx_mgmt_probe_resp(sdata, skb); |
2052 | break; | 2614 | break; |
2053 | case IEEE80211_STYPE_PROBE_RESP: | 2615 | case IEEE80211_STYPE_AUTH: |
2054 | ieee80211_rx_mgmt_probe_resp(sdata, skb); | 2616 | rma = ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len); |
2055 | break; | 2617 | break; |
2056 | case IEEE80211_STYPE_DEAUTH: | 2618 | case IEEE80211_STYPE_DEAUTH: |
2057 | rma = ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); | 2619 | rma = ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); |
2058 | break; | 2620 | break; |
2059 | case IEEE80211_STYPE_DISASSOC: | 2621 | case IEEE80211_STYPE_DISASSOC: |
2060 | rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); | 2622 | rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); |
2061 | break; | 2623 | break; |
2062 | case IEEE80211_STYPE_ACTION: | 2624 | case IEEE80211_STYPE_ASSOC_RESP: |
2063 | switch (mgmt->u.action.category) { | 2625 | case IEEE80211_STYPE_REASSOC_RESP: |
2064 | case WLAN_CATEGORY_SPECTRUM_MGMT: | 2626 | rma = ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, &bss); |
2065 | ieee80211_sta_process_chanswitch(sdata, | 2627 | break; |
2066 | &mgmt->u.action.u.chan_switch.sw_elem, | 2628 | case IEEE80211_STYPE_ACTION: |
2067 | (void *)ifmgd->associated->priv, | 2629 | switch (mgmt->u.action.category) { |
2068 | rx_status->mactime); | 2630 | case WLAN_CATEGORY_SPECTRUM_MGMT: |
2069 | break; | 2631 | ieee80211_sta_process_chanswitch(sdata, |
2070 | } | 2632 | &mgmt->u.action.u.chan_switch.sw_elem, |
2071 | } | 2633 | (void *)ifmgd->associated->priv, |
2072 | mutex_unlock(&ifmgd->mtx); | 2634 | rx_status->mactime); |
2073 | |||
2074 | switch (rma) { | ||
2075 | case RX_MGMT_NONE: | ||
2076 | /* no action */ | ||
2077 | break; | ||
2078 | case RX_MGMT_CFG80211_DEAUTH: | ||
2079 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); | ||
2080 | break; | ||
2081 | case RX_MGMT_CFG80211_DISASSOC: | ||
2082 | cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); | ||
2083 | break; | 2635 | break; |
2084 | default: | ||
2085 | WARN(1, "unexpected: %d", rma); | ||
2086 | } | 2636 | } |
2087 | return; | ||
2088 | } | 2637 | } |
2089 | |||
2090 | mutex_unlock(&ifmgd->mtx); | 2638 | mutex_unlock(&ifmgd->mtx); |
2091 | 2639 | ||
2092 | if (skb->len >= 24 + 2 /* mgmt + deauth reason */ && | 2640 | switch (rma) { |
2093 | (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH) { | 2641 | case RX_MGMT_NONE: |
2094 | struct ieee80211_local *local = sdata->local; | 2642 | /* no action */ |
2095 | struct ieee80211_work *wk; | 2643 | break; |
2096 | 2644 | case RX_MGMT_CFG80211_DEAUTH: | |
2097 | mutex_lock(&local->mtx); | ||
2098 | list_for_each_entry(wk, &local->work_list, list) { | ||
2099 | if (wk->sdata != sdata) | ||
2100 | continue; | ||
2101 | |||
2102 | if (wk->type != IEEE80211_WORK_ASSOC && | ||
2103 | wk->type != IEEE80211_WORK_ASSOC_BEACON_WAIT) | ||
2104 | continue; | ||
2105 | |||
2106 | if (memcmp(mgmt->bssid, wk->filter_ta, ETH_ALEN)) | ||
2107 | continue; | ||
2108 | if (memcmp(mgmt->sa, wk->filter_ta, ETH_ALEN)) | ||
2109 | continue; | ||
2110 | |||
2111 | /* | ||
2112 | * Printing the message only here means we can't | ||
2113 | * spuriously print it, but it also means that it | ||
2114 | * won't be printed when the frame comes in before | ||
2115 | * we even tried to associate or in similar cases. | ||
2116 | * | ||
2117 | * Ultimately, I suspect cfg80211 should print the | ||
2118 | * messages instead. | ||
2119 | */ | ||
2120 | printk(KERN_DEBUG | ||
2121 | "%s: deauthenticated from %pM (Reason: %u)\n", | ||
2122 | sdata->name, mgmt->bssid, | ||
2123 | le16_to_cpu(mgmt->u.deauth.reason_code)); | ||
2124 | |||
2125 | list_del_rcu(&wk->list); | ||
2126 | free_work(wk); | ||
2127 | break; | ||
2128 | } | ||
2129 | mutex_unlock(&local->mtx); | ||
2130 | |||
2131 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); | 2645 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); |
2646 | break; | ||
2647 | case RX_MGMT_CFG80211_DISASSOC: | ||
2648 | cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); | ||
2649 | break; | ||
2650 | case RX_MGMT_CFG80211_RX_AUTH: | ||
2651 | cfg80211_send_rx_auth(sdata->dev, (u8 *)mgmt, skb->len); | ||
2652 | break; | ||
2653 | case RX_MGMT_CFG80211_RX_ASSOC: | ||
2654 | cfg80211_send_rx_assoc(sdata->dev, bss, (u8 *)mgmt, skb->len); | ||
2655 | break; | ||
2656 | case RX_MGMT_CFG80211_ASSOC_TIMEOUT: | ||
2657 | cfg80211_send_assoc_timeout(sdata->dev, mgmt->bssid); | ||
2658 | break; | ||
2659 | default: | ||
2660 | WARN(1, "unexpected: %d", rma); | ||
2132 | } | 2661 | } |
2133 | } | 2662 | } |
2134 | 2663 | ||
@@ -2173,14 +2702,160 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | |||
2173 | mutex_lock(&ifmgd->mtx); | 2702 | mutex_lock(&ifmgd->mtx); |
2174 | } | 2703 | } |
2175 | 2704 | ||
2705 | static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) | ||
2706 | { | ||
2707 | struct ieee80211_local *local = sdata->local; | ||
2708 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2709 | struct ieee80211_mgd_auth_data *auth_data = ifmgd->auth_data; | ||
2710 | |||
2711 | lockdep_assert_held(&ifmgd->mtx); | ||
2712 | |||
2713 | if (WARN_ON_ONCE(!auth_data)) | ||
2714 | return -EINVAL; | ||
2715 | |||
2716 | if (!auth_data->synced) { | ||
2717 | int ret = drv_tx_sync(local, sdata, auth_data->bss->bssid, | ||
2718 | IEEE80211_TX_SYNC_AUTH); | ||
2719 | if (ret) | ||
2720 | return ret; | ||
2721 | } | ||
2722 | auth_data->synced = true; | ||
2723 | |||
2724 | auth_data->tries++; | ||
2725 | |||
2726 | if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) { | ||
2727 | printk(KERN_DEBUG "%s: authentication with %pM timed out\n", | ||
2728 | sdata->name, auth_data->bss->bssid); | ||
2729 | |||
2730 | /* | ||
2731 | * Most likely AP is not in the range so remove the | ||
2732 | * bss struct for that AP. | ||
2733 | */ | ||
2734 | cfg80211_unlink_bss(local->hw.wiphy, auth_data->bss); | ||
2735 | |||
2736 | return -ETIMEDOUT; | ||
2737 | } | ||
2738 | |||
2739 | if (auth_data->bss->proberesp_ies) { | ||
2740 | printk(KERN_DEBUG "%s: send auth to %pM (try %d/%d)\n", | ||
2741 | sdata->name, auth_data->bss->bssid, auth_data->tries, | ||
2742 | IEEE80211_AUTH_MAX_TRIES); | ||
2743 | |||
2744 | auth_data->expected_transaction = 2; | ||
2745 | ieee80211_send_auth(sdata, 1, auth_data->algorithm, | ||
2746 | auth_data->ie, auth_data->ie_len, | ||
2747 | auth_data->bss->bssid, | ||
2748 | auth_data->bss->bssid, NULL, 0, 0); | ||
2749 | } else { | ||
2750 | const u8 *ssidie; | ||
2751 | |||
2752 | printk(KERN_DEBUG "%s: direct probe to %pM (try %d/%i)\n", | ||
2753 | sdata->name, auth_data->bss->bssid, auth_data->tries, | ||
2754 | IEEE80211_AUTH_MAX_TRIES); | ||
2755 | |||
2756 | ssidie = ieee80211_bss_get_ie(auth_data->bss, WLAN_EID_SSID); | ||
2757 | if (!ssidie) | ||
2758 | return -EINVAL; | ||
2759 | /* | ||
2760 | * Direct probe is sent to broadcast address as some APs | ||
2761 | * will not answer to direct packet in unassociated state. | ||
2762 | */ | ||
2763 | ieee80211_send_probe_req(sdata, NULL, ssidie + 2, ssidie[1], | ||
2764 | NULL, 0, (u32) -1, true, false); | ||
2765 | } | ||
2766 | |||
2767 | auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; | ||
2768 | run_again(ifmgd, auth_data->timeout); | ||
2769 | |||
2770 | return 0; | ||
2771 | } | ||
2772 | |||
2773 | static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata) | ||
2774 | { | ||
2775 | struct ieee80211_mgd_assoc_data *assoc_data = sdata->u.mgd.assoc_data; | ||
2776 | struct ieee80211_local *local = sdata->local; | ||
2777 | |||
2778 | lockdep_assert_held(&sdata->u.mgd.mtx); | ||
2779 | |||
2780 | if (!assoc_data->synced) { | ||
2781 | int ret = drv_tx_sync(local, sdata, assoc_data->bss->bssid, | ||
2782 | IEEE80211_TX_SYNC_ASSOC); | ||
2783 | if (ret) | ||
2784 | return ret; | ||
2785 | } | ||
2786 | assoc_data->synced = true; | ||
2787 | |||
2788 | assoc_data->tries++; | ||
2789 | if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) { | ||
2790 | printk(KERN_DEBUG "%s: association with %pM timed out\n", | ||
2791 | sdata->name, assoc_data->bss->bssid); | ||
2792 | |||
2793 | /* | ||
2794 | * Most likely AP is not in the range so remove the | ||
2795 | * bss struct for that AP. | ||
2796 | */ | ||
2797 | cfg80211_unlink_bss(local->hw.wiphy, assoc_data->bss); | ||
2798 | |||
2799 | return -ETIMEDOUT; | ||
2800 | } | ||
2801 | |||
2802 | printk(KERN_DEBUG "%s: associate with %pM (try %d/%d)\n", | ||
2803 | sdata->name, assoc_data->bss->bssid, assoc_data->tries, | ||
2804 | IEEE80211_ASSOC_MAX_TRIES); | ||
2805 | ieee80211_send_assoc(sdata); | ||
2806 | |||
2807 | assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; | ||
2808 | run_again(&sdata->u.mgd, assoc_data->timeout); | ||
2809 | |||
2810 | return 0; | ||
2811 | } | ||
2812 | |||
2176 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | 2813 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) |
2177 | { | 2814 | { |
2178 | struct ieee80211_local *local = sdata->local; | 2815 | struct ieee80211_local *local = sdata->local; |
2179 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2816 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2180 | 2817 | ||
2181 | /* then process the rest of the work */ | ||
2182 | mutex_lock(&ifmgd->mtx); | 2818 | mutex_lock(&ifmgd->mtx); |
2183 | 2819 | ||
2820 | if (ifmgd->auth_data && | ||
2821 | time_after(jiffies, ifmgd->auth_data->timeout)) { | ||
2822 | if (ifmgd->auth_data->done) { | ||
2823 | /* | ||
2824 | * ok ... we waited for assoc but userspace didn't, | ||
2825 | * so let's just kill the auth data | ||
2826 | */ | ||
2827 | ieee80211_destroy_auth_data(sdata, false); | ||
2828 | } else if (ieee80211_probe_auth(sdata)) { | ||
2829 | u8 bssid[ETH_ALEN]; | ||
2830 | |||
2831 | memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN); | ||
2832 | |||
2833 | ieee80211_destroy_auth_data(sdata, false); | ||
2834 | |||
2835 | mutex_unlock(&ifmgd->mtx); | ||
2836 | cfg80211_send_auth_timeout(sdata->dev, bssid); | ||
2837 | mutex_lock(&ifmgd->mtx); | ||
2838 | } | ||
2839 | } else if (ifmgd->auth_data) | ||
2840 | run_again(ifmgd, ifmgd->auth_data->timeout); | ||
2841 | |||
2842 | if (ifmgd->assoc_data && | ||
2843 | time_after(jiffies, ifmgd->assoc_data->timeout)) { | ||
2844 | if (!ifmgd->assoc_data->have_beacon || | ||
2845 | ieee80211_do_assoc(sdata)) { | ||
2846 | u8 bssid[ETH_ALEN]; | ||
2847 | |||
2848 | memcpy(bssid, ifmgd->assoc_data->bss->bssid, ETH_ALEN); | ||
2849 | |||
2850 | ieee80211_destroy_assoc_data(sdata, false); | ||
2851 | |||
2852 | mutex_unlock(&ifmgd->mtx); | ||
2853 | cfg80211_send_assoc_timeout(sdata->dev, bssid); | ||
2854 | mutex_lock(&ifmgd->mtx); | ||
2855 | } | ||
2856 | } else if (ifmgd->assoc_data) | ||
2857 | run_again(ifmgd, ifmgd->assoc_data->timeout); | ||
2858 | |||
2184 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 2859 | if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | |
2185 | IEEE80211_STA_CONNECTION_POLL) && | 2860 | IEEE80211_STA_CONNECTION_POLL) && |
2186 | ifmgd->associated) { | 2861 | ifmgd->associated) { |
@@ -2256,6 +2931,10 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
2256 | } | 2931 | } |
2257 | 2932 | ||
2258 | mutex_unlock(&ifmgd->mtx); | 2933 | mutex_unlock(&ifmgd->mtx); |
2934 | |||
2935 | mutex_lock(&local->mtx); | ||
2936 | ieee80211_recalc_idle(local); | ||
2937 | mutex_unlock(&local->mtx); | ||
2259 | } | 2938 | } |
2260 | 2939 | ||
2261 | static void ieee80211_sta_bcn_mon_timer(unsigned long data) | 2940 | static void ieee80211_sta_bcn_mon_timer(unsigned long data) |
@@ -2428,53 +3107,24 @@ int ieee80211_max_network_latency(struct notifier_block *nb, | |||
2428 | } | 3107 | } |
2429 | 3108 | ||
2430 | /* config hooks */ | 3109 | /* config hooks */ |
2431 | static enum work_done_result | ||
2432 | ieee80211_probe_auth_done(struct ieee80211_work *wk, | ||
2433 | struct sk_buff *skb) | ||
2434 | { | ||
2435 | struct ieee80211_local *local = wk->sdata->local; | ||
2436 | |||
2437 | if (!skb) { | ||
2438 | cfg80211_send_auth_timeout(wk->sdata->dev, wk->filter_ta); | ||
2439 | goto destroy; | ||
2440 | } | ||
2441 | |||
2442 | if (wk->type == IEEE80211_WORK_AUTH) { | ||
2443 | cfg80211_send_rx_auth(wk->sdata->dev, skb->data, skb->len); | ||
2444 | goto destroy; | ||
2445 | } | ||
2446 | |||
2447 | mutex_lock(&wk->sdata->u.mgd.mtx); | ||
2448 | ieee80211_rx_mgmt_probe_resp(wk->sdata, skb); | ||
2449 | mutex_unlock(&wk->sdata->u.mgd.mtx); | ||
2450 | |||
2451 | wk->type = IEEE80211_WORK_AUTH; | ||
2452 | wk->probe_auth.tries = 0; | ||
2453 | return WORK_DONE_REQUEUE; | ||
2454 | destroy: | ||
2455 | if (wk->probe_auth.synced) | ||
2456 | drv_finish_tx_sync(local, wk->sdata, wk->filter_ta, | ||
2457 | IEEE80211_TX_SYNC_AUTH); | ||
2458 | |||
2459 | return WORK_DONE_DESTROY; | ||
2460 | } | ||
2461 | |||
2462 | int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | 3110 | int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, |
2463 | struct cfg80211_auth_request *req) | 3111 | struct cfg80211_auth_request *req) |
2464 | { | 3112 | { |
2465 | const u8 *ssid; | 3113 | struct ieee80211_local *local = sdata->local; |
2466 | struct ieee80211_work *wk; | 3114 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
3115 | struct ieee80211_mgd_auth_data *auth_data; | ||
3116 | struct sta_info *sta; | ||
2467 | u16 auth_alg; | 3117 | u16 auth_alg; |
3118 | int err; | ||
2468 | 3119 | ||
2469 | if (req->local_state_change) | 3120 | /* prepare auth data structure */ |
2470 | return 0; /* no need to update mac80211 state */ | ||
2471 | 3121 | ||
2472 | switch (req->auth_type) { | 3122 | switch (req->auth_type) { |
2473 | case NL80211_AUTHTYPE_OPEN_SYSTEM: | 3123 | case NL80211_AUTHTYPE_OPEN_SYSTEM: |
2474 | auth_alg = WLAN_AUTH_OPEN; | 3124 | auth_alg = WLAN_AUTH_OPEN; |
2475 | break; | 3125 | break; |
2476 | case NL80211_AUTHTYPE_SHARED_KEY: | 3126 | case NL80211_AUTHTYPE_SHARED_KEY: |
2477 | if (IS_ERR(sdata->local->wep_tx_tfm)) | 3127 | if (IS_ERR(local->wep_tx_tfm)) |
2478 | return -EOPNOTSUPP; | 3128 | return -EOPNOTSUPP; |
2479 | auth_alg = WLAN_AUTH_SHARED_KEY; | 3129 | auth_alg = WLAN_AUTH_SHARED_KEY; |
2480 | break; | 3130 | break; |
@@ -2488,171 +3138,142 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
2488 | return -EOPNOTSUPP; | 3138 | return -EOPNOTSUPP; |
2489 | } | 3139 | } |
2490 | 3140 | ||
2491 | wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL); | 3141 | auth_data = kzalloc(sizeof(*auth_data) + req->ie_len, GFP_KERNEL); |
2492 | if (!wk) | 3142 | if (!auth_data) |
2493 | return -ENOMEM; | 3143 | return -ENOMEM; |
2494 | 3144 | ||
2495 | memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN); | 3145 | auth_data->bss = req->bss; |
2496 | 3146 | ||
2497 | if (req->ie && req->ie_len) { | 3147 | if (req->ie && req->ie_len) { |
2498 | memcpy(wk->ie, req->ie, req->ie_len); | 3148 | memcpy(auth_data->ie, req->ie, req->ie_len); |
2499 | wk->ie_len = req->ie_len; | 3149 | auth_data->ie_len = req->ie_len; |
2500 | } | 3150 | } |
2501 | 3151 | ||
2502 | if (req->key && req->key_len) { | 3152 | if (req->key && req->key_len) { |
2503 | wk->probe_auth.key_len = req->key_len; | 3153 | auth_data->key_len = req->key_len; |
2504 | wk->probe_auth.key_idx = req->key_idx; | 3154 | auth_data->key_idx = req->key_idx; |
2505 | memcpy(wk->probe_auth.key, req->key, req->key_len); | 3155 | memcpy(auth_data->key, req->key, req->key_len); |
2506 | } | 3156 | } |
2507 | 3157 | ||
2508 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); | 3158 | auth_data->algorithm = auth_alg; |
2509 | memcpy(wk->probe_auth.ssid, ssid + 2, ssid[1]); | ||
2510 | wk->probe_auth.ssid_len = ssid[1]; | ||
2511 | |||
2512 | wk->probe_auth.algorithm = auth_alg; | ||
2513 | wk->probe_auth.privacy = req->bss->capability & WLAN_CAPABILITY_PRIVACY; | ||
2514 | |||
2515 | /* if we already have a probe, don't probe again */ | ||
2516 | if (req->bss->proberesp_ies) | ||
2517 | wk->type = IEEE80211_WORK_AUTH; | ||
2518 | else | ||
2519 | wk->type = IEEE80211_WORK_DIRECT_PROBE; | ||
2520 | wk->chan = req->bss->channel; | ||
2521 | wk->chan_type = NL80211_CHAN_NO_HT; | ||
2522 | wk->sdata = sdata; | ||
2523 | wk->done = ieee80211_probe_auth_done; | ||
2524 | |||
2525 | ieee80211_add_work(wk); | ||
2526 | return 0; | ||
2527 | } | ||
2528 | |||
2529 | /* create and insert a dummy station entry */ | ||
2530 | static int ieee80211_pre_assoc(struct ieee80211_sub_if_data *sdata, | ||
2531 | u8 *bssid) { | ||
2532 | struct sta_info *sta; | ||
2533 | int err; | ||
2534 | 3159 | ||
2535 | sta = sta_info_alloc(sdata, bssid, GFP_KERNEL); | 3160 | /* try to authenticate/probe */ |
2536 | if (!sta) | ||
2537 | return -ENOMEM; | ||
2538 | 3161 | ||
2539 | sta->dummy = true; | 3162 | mutex_lock(&ifmgd->mtx); |
2540 | 3163 | ||
2541 | err = sta_info_insert(sta); | 3164 | if ((ifmgd->auth_data && !ifmgd->auth_data->done) || |
2542 | sta = NULL; | 3165 | ifmgd->assoc_data) { |
2543 | if (err) { | 3166 | err = -EBUSY; |
2544 | printk(KERN_DEBUG "%s: failed to insert Dummy STA entry for" | 3167 | goto err_free; |
2545 | " the AP (error %d)\n", sdata->name, err); | ||
2546 | return err; | ||
2547 | } | 3168 | } |
2548 | 3169 | ||
2549 | return 0; | 3170 | if (ifmgd->auth_data) |
2550 | } | 3171 | ieee80211_destroy_auth_data(sdata, false); |
2551 | 3172 | ||
2552 | static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk, | 3173 | /* prep auth_data so we don't go into idle on disassoc */ |
2553 | struct sk_buff *skb) | 3174 | ifmgd->auth_data = auth_data; |
2554 | { | ||
2555 | struct ieee80211_local *local = wk->sdata->local; | ||
2556 | struct ieee80211_mgmt *mgmt; | ||
2557 | struct ieee80211_rx_status *rx_status; | ||
2558 | struct ieee802_11_elems elems; | ||
2559 | struct cfg80211_bss *cbss = wk->assoc.bss; | ||
2560 | u16 status; | ||
2561 | 3175 | ||
2562 | if (!skb) { | 3176 | if (ifmgd->associated) |
2563 | sta_info_destroy_addr(wk->sdata, cbss->bssid); | 3177 | ieee80211_set_disassoc(sdata, true, false); |
2564 | cfg80211_send_assoc_timeout(wk->sdata->dev, wk->filter_ta); | ||
2565 | goto destroy; | ||
2566 | } | ||
2567 | 3178 | ||
2568 | if (wk->type == IEEE80211_WORK_ASSOC_BEACON_WAIT) { | 3179 | printk(KERN_DEBUG "%s: authenticate with %pM\n", |
2569 | mutex_lock(&wk->sdata->u.mgd.mtx); | 3180 | sdata->name, req->bss->bssid); |
2570 | rx_status = (void *) skb->cb; | ||
2571 | ieee802_11_parse_elems(skb->data + 24 + 12, skb->len - 24 - 12, &elems); | ||
2572 | ieee80211_rx_bss_info(wk->sdata, (void *)skb->data, skb->len, rx_status, | ||
2573 | &elems, true); | ||
2574 | mutex_unlock(&wk->sdata->u.mgd.mtx); | ||
2575 | 3181 | ||
2576 | wk->type = IEEE80211_WORK_ASSOC; | 3182 | mutex_lock(&local->mtx); |
2577 | /* not really done yet */ | 3183 | ieee80211_recalc_idle(sdata->local); |
2578 | return WORK_DONE_REQUEUE; | 3184 | mutex_unlock(&local->mtx); |
2579 | } | ||
2580 | 3185 | ||
2581 | mgmt = (void *)skb->data; | 3186 | /* switch to the right channel */ |
2582 | status = le16_to_cpu(mgmt->u.assoc_resp.status_code); | 3187 | local->oper_channel = req->bss->channel; |
3188 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
2583 | 3189 | ||
2584 | if (status == WLAN_STATUS_SUCCESS) { | 3190 | /* set BSSID */ |
2585 | if (wk->assoc.synced) | 3191 | memcpy(ifmgd->bssid, req->bss->bssid, ETH_ALEN); |
2586 | drv_finish_tx_sync(local, wk->sdata, wk->filter_ta, | 3192 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); |
2587 | IEEE80211_TX_SYNC_ASSOC); | ||
2588 | 3193 | ||
2589 | mutex_lock(&wk->sdata->u.mgd.mtx); | 3194 | /* add station entry */ |
2590 | if (!ieee80211_assoc_success(wk, mgmt, skb->len)) { | 3195 | sta = sta_info_alloc(sdata, req->bss->bssid, GFP_KERNEL); |
2591 | mutex_unlock(&wk->sdata->u.mgd.mtx); | 3196 | if (!sta) { |
2592 | /* oops -- internal error -- send timeout for now */ | 3197 | err = -ENOMEM; |
2593 | sta_info_destroy_addr(wk->sdata, cbss->bssid); | 3198 | goto err_clear; |
2594 | cfg80211_send_assoc_timeout(wk->sdata->dev, | 3199 | } |
2595 | wk->filter_ta); | ||
2596 | return WORK_DONE_DESTROY; | ||
2597 | } | ||
2598 | 3200 | ||
2599 | mutex_unlock(&wk->sdata->u.mgd.mtx); | 3201 | err = sta_info_insert(sta); |
2600 | } else { | 3202 | if (err) { |
2601 | /* assoc failed - destroy the dummy station entry */ | 3203 | printk(KERN_DEBUG |
2602 | sta_info_destroy_addr(wk->sdata, cbss->bssid); | 3204 | "%s: failed to insert STA entry for the AP %pM (error %d)\n", |
3205 | sdata->name, req->bss->bssid, err); | ||
3206 | goto err_clear; | ||
2603 | } | 3207 | } |
2604 | 3208 | ||
2605 | cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len); | 3209 | err = ieee80211_probe_auth(sdata); |
2606 | destroy: | 3210 | if (err) { |
2607 | if (wk->assoc.synced) | 3211 | if (auth_data->synced) |
2608 | drv_finish_tx_sync(local, wk->sdata, wk->filter_ta, | 3212 | drv_finish_tx_sync(local, sdata, req->bss->bssid, |
2609 | IEEE80211_TX_SYNC_ASSOC); | 3213 | IEEE80211_TX_SYNC_AUTH); |
3214 | sta_info_destroy_addr(sdata, req->bss->bssid); | ||
3215 | goto err_clear; | ||
3216 | } | ||
3217 | |||
3218 | /* hold our own reference */ | ||
3219 | cfg80211_ref_bss(auth_data->bss); | ||
3220 | err = 0; | ||
3221 | goto out_unlock; | ||
3222 | |||
3223 | err_clear: | ||
3224 | ifmgd->auth_data = NULL; | ||
3225 | err_free: | ||
3226 | kfree(auth_data); | ||
3227 | out_unlock: | ||
3228 | mutex_unlock(&ifmgd->mtx); | ||
2610 | 3229 | ||
2611 | return WORK_DONE_DESTROY; | 3230 | return err; |
2612 | } | 3231 | } |
2613 | 3232 | ||
2614 | int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | 3233 | int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, |
2615 | struct cfg80211_assoc_request *req) | 3234 | struct cfg80211_assoc_request *req) |
2616 | { | 3235 | { |
3236 | struct ieee80211_local *local = sdata->local; | ||
2617 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3237 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2618 | struct ieee80211_bss *bss = (void *)req->bss->priv; | 3238 | struct ieee80211_bss *bss = (void *)req->bss->priv; |
2619 | struct ieee80211_work *wk; | 3239 | struct ieee80211_mgd_assoc_data *assoc_data; |
2620 | const u8 *ssid; | 3240 | struct sta_info *sta; |
3241 | const u8 *ssidie; | ||
2621 | int i, err; | 3242 | int i, err; |
2622 | 3243 | ||
3244 | ssidie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); | ||
3245 | if (!ssidie) | ||
3246 | return -EINVAL; | ||
3247 | |||
3248 | assoc_data = kzalloc(sizeof(*assoc_data) + req->ie_len, GFP_KERNEL); | ||
3249 | if (!assoc_data) | ||
3250 | return -ENOMEM; | ||
3251 | |||
2623 | mutex_lock(&ifmgd->mtx); | 3252 | mutex_lock(&ifmgd->mtx); |
2624 | if (ifmgd->associated) { | ||
2625 | if (!req->prev_bssid || | ||
2626 | memcmp(req->prev_bssid, ifmgd->associated->bssid, | ||
2627 | ETH_ALEN)) { | ||
2628 | /* | ||
2629 | * We are already associated and the request was not a | ||
2630 | * reassociation request from the current BSS, so | ||
2631 | * reject it. | ||
2632 | */ | ||
2633 | mutex_unlock(&ifmgd->mtx); | ||
2634 | return -EALREADY; | ||
2635 | } | ||
2636 | 3253 | ||
2637 | /* Trying to reassociate - clear previous association state */ | 3254 | if (ifmgd->associated) |
2638 | ieee80211_set_disassoc(sdata, true, false); | 3255 | ieee80211_set_disassoc(sdata, true, false); |
3256 | |||
3257 | if (ifmgd->auth_data && !ifmgd->auth_data->done) { | ||
3258 | err = -EBUSY; | ||
3259 | goto err_free; | ||
2639 | } | 3260 | } |
2640 | mutex_unlock(&ifmgd->mtx); | ||
2641 | 3261 | ||
2642 | wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL); | 3262 | if (ifmgd->assoc_data) { |
2643 | if (!wk) | 3263 | err = -EBUSY; |
2644 | return -ENOMEM; | 3264 | goto err_free; |
3265 | } | ||
2645 | 3266 | ||
2646 | /* | 3267 | if (ifmgd->auth_data) { |
2647 | * create a dummy station info entry in order | 3268 | bool match; |
2648 | * to start accepting incoming EAPOL packets from the station | 3269 | |
2649 | */ | 3270 | /* keep sta info, bssid if matching */ |
2650 | err = ieee80211_pre_assoc(sdata, req->bss->bssid); | 3271 | match = memcmp(ifmgd->bssid, req->bss->bssid, ETH_ALEN) == 0; |
2651 | if (err) { | 3272 | ieee80211_destroy_auth_data(sdata, match); |
2652 | kfree(wk); | ||
2653 | return err; | ||
2654 | } | 3273 | } |
2655 | 3274 | ||
3275 | /* prepare assoc data */ | ||
3276 | |||
2656 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; | 3277 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; |
2657 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; | 3278 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; |
2658 | 3279 | ||
@@ -2664,7 +3285,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2664 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) | 3285 | req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) |
2665 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 3286 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; |
2666 | 3287 | ||
2667 | |||
2668 | if (req->flags & ASSOC_REQ_DISABLE_HT) | 3288 | if (req->flags & ASSOC_REQ_DISABLE_HT) |
2669 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; | 3289 | ifmgd->flags |= IEEE80211_STA_DISABLE_11N; |
2670 | 3290 | ||
@@ -2673,16 +3293,12 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2673 | sizeof(ifmgd->ht_capa_mask)); | 3293 | sizeof(ifmgd->ht_capa_mask)); |
2674 | 3294 | ||
2675 | if (req->ie && req->ie_len) { | 3295 | if (req->ie && req->ie_len) { |
2676 | memcpy(wk->ie, req->ie, req->ie_len); | 3296 | memcpy(assoc_data->ie, req->ie, req->ie_len); |
2677 | wk->ie_len = req->ie_len; | 3297 | assoc_data->ie_len = req->ie_len; |
2678 | } else | 3298 | } |
2679 | wk->ie_len = 0; | ||
2680 | |||
2681 | wk->assoc.bss = req->bss; | ||
2682 | 3299 | ||
2683 | memcpy(wk->filter_ta, req->bss->bssid, ETH_ALEN); | 3300 | assoc_data->bss = req->bss; |
2684 | 3301 | ||
2685 | /* new association always uses requested smps mode */ | ||
2686 | if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) { | 3302 | if (ifmgd->req_smps == IEEE80211_SMPS_AUTOMATIC) { |
2687 | if (ifmgd->powersave) | 3303 | if (ifmgd->powersave) |
2688 | ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC; | 3304 | ifmgd->ap_smps = IEEE80211_SMPS_DYNAMIC; |
@@ -2691,7 +3307,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2691 | } else | 3307 | } else |
2692 | ifmgd->ap_smps = ifmgd->req_smps; | 3308 | ifmgd->ap_smps = ifmgd->req_smps; |
2693 | 3309 | ||
2694 | wk->assoc.smps = ifmgd->ap_smps; | ||
2695 | /* | 3310 | /* |
2696 | * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode. | 3311 | * IEEE802.11n does not allow TKIP/WEP as pairwise ciphers in HT mode. |
2697 | * We still associate in non-HT mode (11a/b/g) if any one of these | 3312 | * We still associate in non-HT mode (11a/b/g) if any one of these |
@@ -2699,39 +3314,27 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2699 | * We can set this to true for non-11n hardware, that'll be checked | 3314 | * We can set this to true for non-11n hardware, that'll be checked |
2700 | * separately along with the peer capabilities. | 3315 | * separately along with the peer capabilities. |
2701 | */ | 3316 | */ |
2702 | wk->assoc.use_11n = !(ifmgd->flags & IEEE80211_STA_DISABLE_11N); | 3317 | assoc_data->capability = req->bss->capability; |
2703 | wk->assoc.capability = req->bss->capability; | 3318 | assoc_data->wmm_used = bss->wmm_used; |
2704 | wk->assoc.wmm_used = bss->wmm_used; | 3319 | assoc_data->supp_rates = bss->supp_rates; |
2705 | wk->assoc.supp_rates = bss->supp_rates; | 3320 | assoc_data->supp_rates_len = bss->supp_rates_len; |
2706 | wk->assoc.supp_rates_len = bss->supp_rates_len; | 3321 | assoc_data->ht_information_ie = |
2707 | wk->assoc.ht_information_ie = | ||
2708 | ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION); | 3322 | ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION); |
2709 | 3323 | ||
2710 | if (bss->wmm_used && bss->uapsd_supported && | 3324 | if (bss->wmm_used && bss->uapsd_supported && |
2711 | (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { | 3325 | (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) { |
2712 | wk->assoc.uapsd_used = true; | 3326 | assoc_data->uapsd_used = true; |
2713 | ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED; | 3327 | ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED; |
2714 | } else { | 3328 | } else { |
2715 | wk->assoc.uapsd_used = false; | 3329 | assoc_data->uapsd_used = false; |
2716 | ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED; | 3330 | ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED; |
2717 | } | 3331 | } |
2718 | 3332 | ||
2719 | ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); | 3333 | memcpy(assoc_data->ssid, ssidie + 2, ssidie[1]); |
2720 | memcpy(wk->assoc.ssid, ssid + 2, ssid[1]); | 3334 | assoc_data->ssid_len = ssidie[1]; |
2721 | wk->assoc.ssid_len = ssid[1]; | ||
2722 | 3335 | ||
2723 | if (req->prev_bssid) | 3336 | if (req->prev_bssid) |
2724 | memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN); | 3337 | memcpy(assoc_data->prev_bssid, req->prev_bssid, ETH_ALEN); |
2725 | |||
2726 | wk->chan = req->bss->channel; | ||
2727 | wk->chan_type = NL80211_CHAN_NO_HT; | ||
2728 | wk->sdata = sdata; | ||
2729 | wk->done = ieee80211_assoc_done; | ||
2730 | if (!bss->dtim_period && | ||
2731 | sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) | ||
2732 | wk->type = IEEE80211_WORK_ASSOC_BEACON_WAIT; | ||
2733 | else | ||
2734 | wk->type = IEEE80211_WORK_ASSOC; | ||
2735 | 3338 | ||
2736 | if (req->use_mfp) { | 3339 | if (req->use_mfp) { |
2737 | ifmgd->mfp = IEEE80211_MFP_REQUIRED; | 3340 | ifmgd->mfp = IEEE80211_MFP_REQUIRED; |
@@ -2749,89 +3352,100 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2749 | sdata->control_port_protocol = req->crypto.control_port_ethertype; | 3352 | sdata->control_port_protocol = req->crypto.control_port_ethertype; |
2750 | sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; | 3353 | sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt; |
2751 | 3354 | ||
2752 | ieee80211_add_work(wk); | 3355 | /* kick off associate process */ |
2753 | return 0; | 3356 | |
3357 | ifmgd->assoc_data = assoc_data; | ||
3358 | |||
3359 | mutex_lock(&local->mtx); | ||
3360 | ieee80211_recalc_idle(sdata->local); | ||
3361 | mutex_unlock(&local->mtx); | ||
3362 | |||
3363 | /* switch to the right channel */ | ||
3364 | local->oper_channel = req->bss->channel; | ||
3365 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
3366 | |||
3367 | rcu_read_lock(); | ||
3368 | sta = sta_info_get(sdata, req->bss->bssid); | ||
3369 | rcu_read_unlock(); | ||
3370 | |||
3371 | if (!sta) { | ||
3372 | /* set BSSID */ | ||
3373 | memcpy(ifmgd->bssid, req->bss->bssid, ETH_ALEN); | ||
3374 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); | ||
3375 | |||
3376 | sta = sta_info_alloc(sdata, req->bss->bssid, GFP_KERNEL); | ||
3377 | if (!sta) { | ||
3378 | err = -ENOMEM; | ||
3379 | goto err_clear; | ||
3380 | } | ||
3381 | |||
3382 | sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); | ||
3383 | |||
3384 | err = sta_info_insert(sta); | ||
3385 | sta = NULL; | ||
3386 | if (err) { | ||
3387 | printk(KERN_DEBUG | ||
3388 | "%s: failed to insert STA entry for the AP (error %d)\n", | ||
3389 | sdata->name, err); | ||
3390 | goto err_clear; | ||
3391 | } | ||
3392 | } else | ||
3393 | WARN_ON_ONCE(memcmp(ifmgd->bssid, req->bss->bssid, ETH_ALEN)); | ||
3394 | |||
3395 | if (!bss->dtim_period && | ||
3396 | sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) { | ||
3397 | /* | ||
3398 | * Wait up to one beacon interval ... | ||
3399 | * should this be more if we miss one? | ||
3400 | */ | ||
3401 | printk(KERN_DEBUG "%s: waiting for beacon from %pM\n", | ||
3402 | sdata->name, ifmgd->bssid); | ||
3403 | assoc_data->timeout = jiffies + | ||
3404 | TU_TO_EXP_TIME(req->bss->beacon_interval); | ||
3405 | } else { | ||
3406 | assoc_data->have_beacon = true; | ||
3407 | assoc_data->sent_assoc = false; | ||
3408 | assoc_data->timeout = jiffies; | ||
3409 | } | ||
3410 | run_again(ifmgd, assoc_data->timeout); | ||
3411 | |||
3412 | err = 0; | ||
3413 | goto out; | ||
3414 | err_clear: | ||
3415 | ifmgd->assoc_data = NULL; | ||
3416 | err_free: | ||
3417 | kfree(assoc_data); | ||
3418 | out: | ||
3419 | mutex_unlock(&ifmgd->mtx); | ||
3420 | |||
3421 | return err; | ||
2754 | } | 3422 | } |
2755 | 3423 | ||
2756 | int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | 3424 | int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, |
2757 | struct cfg80211_deauth_request *req, | 3425 | struct cfg80211_deauth_request *req, |
2758 | void *cookie) | 3426 | void *cookie) |
2759 | { | 3427 | { |
2760 | struct ieee80211_local *local = sdata->local; | ||
2761 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 3428 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2762 | u8 bssid[ETH_ALEN]; | ||
2763 | bool assoc_bss = false; | 3429 | bool assoc_bss = false; |
2764 | 3430 | ||
2765 | mutex_lock(&ifmgd->mtx); | 3431 | mutex_lock(&ifmgd->mtx); |
2766 | 3432 | ||
2767 | memcpy(bssid, req->bss->bssid, ETH_ALEN); | 3433 | if (ifmgd->associated && |
2768 | if (ifmgd->associated == req->bss) { | 3434 | memcmp(ifmgd->associated->bssid, req->bssid, ETH_ALEN) == 0) { |
2769 | ieee80211_set_disassoc(sdata, false, true); | 3435 | ieee80211_set_disassoc(sdata, false, true); |
2770 | mutex_unlock(&ifmgd->mtx); | ||
2771 | assoc_bss = true; | 3436 | assoc_bss = true; |
2772 | } else { | 3437 | } else if (ifmgd->auth_data) { |
2773 | bool not_auth_yet = false; | 3438 | ieee80211_destroy_auth_data(sdata, false); |
2774 | struct ieee80211_work *tmp, *wk = NULL; | ||
2775 | |||
2776 | mutex_unlock(&ifmgd->mtx); | 3439 | mutex_unlock(&ifmgd->mtx); |
2777 | 3440 | return 0; | |
2778 | mutex_lock(&local->mtx); | ||
2779 | list_for_each_entry(tmp, &local->work_list, list) { | ||
2780 | if (tmp->sdata != sdata) | ||
2781 | continue; | ||
2782 | |||
2783 | if (tmp->type != IEEE80211_WORK_DIRECT_PROBE && | ||
2784 | tmp->type != IEEE80211_WORK_AUTH && | ||
2785 | tmp->type != IEEE80211_WORK_ASSOC && | ||
2786 | tmp->type != IEEE80211_WORK_ASSOC_BEACON_WAIT) | ||
2787 | continue; | ||
2788 | |||
2789 | if (memcmp(req->bss->bssid, tmp->filter_ta, ETH_ALEN)) | ||
2790 | continue; | ||
2791 | |||
2792 | not_auth_yet = tmp->type == IEEE80211_WORK_DIRECT_PROBE; | ||
2793 | list_del_rcu(&tmp->list); | ||
2794 | synchronize_rcu(); | ||
2795 | wk = tmp; | ||
2796 | break; | ||
2797 | } | ||
2798 | mutex_unlock(&local->mtx); | ||
2799 | |||
2800 | if (wk && wk->type == IEEE80211_WORK_ASSOC) { | ||
2801 | /* clean up dummy sta & TX sync */ | ||
2802 | sta_info_destroy_addr(wk->sdata, wk->filter_ta); | ||
2803 | if (wk->assoc.synced) | ||
2804 | drv_finish_tx_sync(local, wk->sdata, | ||
2805 | wk->filter_ta, | ||
2806 | IEEE80211_TX_SYNC_ASSOC); | ||
2807 | } else if (wk && wk->type == IEEE80211_WORK_AUTH) { | ||
2808 | if (wk->probe_auth.synced) | ||
2809 | drv_finish_tx_sync(local, wk->sdata, | ||
2810 | wk->filter_ta, | ||
2811 | IEEE80211_TX_SYNC_AUTH); | ||
2812 | } | ||
2813 | kfree(wk); | ||
2814 | |||
2815 | /* | ||
2816 | * If somebody requests authentication and we haven't | ||
2817 | * sent out an auth frame yet there's no need to send | ||
2818 | * out a deauth frame either. If the state was PROBE, | ||
2819 | * then this is the case. If it's AUTH we have sent a | ||
2820 | * frame, and if it's IDLE we have completed the auth | ||
2821 | * process already. | ||
2822 | */ | ||
2823 | if (not_auth_yet) { | ||
2824 | __cfg80211_auth_canceled(sdata->dev, bssid); | ||
2825 | return 0; | ||
2826 | } | ||
2827 | } | 3441 | } |
3442 | mutex_unlock(&ifmgd->mtx); | ||
2828 | 3443 | ||
2829 | printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", | 3444 | printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", |
2830 | sdata->name, bssid, req->reason_code); | 3445 | sdata->name, req->bssid, req->reason_code); |
2831 | 3446 | ||
2832 | ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH, | 3447 | ieee80211_send_deauth_disassoc(sdata, req->bssid, IEEE80211_STYPE_DEAUTH, |
2833 | req->reason_code, cookie, | 3448 | req->reason_code, cookie, true); |
2834 | !req->local_state_change); | ||
2835 | if (assoc_bss) | 3449 | if (assoc_bss) |
2836 | sta_info_flush(sdata->local, sdata); | 3450 | sta_info_flush(sdata->local, sdata); |
2837 | 3451 | ||