diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 87 |
1 files changed, 80 insertions, 7 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a8c2130c8ba4..741448b30825 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -2522,8 +2522,11 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2522 | u16 capab_info, aid; | 2522 | u16 capab_info, aid; |
2523 | struct ieee802_11_elems elems; | 2523 | struct ieee802_11_elems elems; |
2524 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | 2524 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
2525 | const struct cfg80211_bss_ies *bss_ies = NULL; | ||
2526 | struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; | ||
2525 | u32 changed = 0; | 2527 | u32 changed = 0; |
2526 | int err; | 2528 | int err; |
2529 | bool ret; | ||
2527 | 2530 | ||
2528 | /* AssocResp and ReassocResp have identical structure */ | 2531 | /* AssocResp and ReassocResp have identical structure */ |
2529 | 2532 | ||
@@ -2555,21 +2558,86 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2555 | ifmgd->aid = aid; | 2558 | ifmgd->aid = aid; |
2556 | 2559 | ||
2557 | /* | 2560 | /* |
2561 | * Some APs are erroneously not including some information in their | ||
2562 | * (re)association response frames. Try to recover by using the data | ||
2563 | * from the beacon or probe response. This seems to afflict mobile | ||
2564 | * 2G/3G/4G wifi routers, reported models include the "Onda PN51T", | ||
2565 | * "Vodafone PocketWiFi 2", "ZTE MF60" and a similar T-Mobile device. | ||
2566 | */ | ||
2567 | if ((assoc_data->wmm && !elems.wmm_param) || | ||
2568 | (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && | ||
2569 | (!elems.ht_cap_elem || !elems.ht_operation)) || | ||
2570 | (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && | ||
2571 | (!elems.vht_cap_elem || !elems.vht_operation))) { | ||
2572 | const struct cfg80211_bss_ies *ies; | ||
2573 | struct ieee802_11_elems bss_elems; | ||
2574 | |||
2575 | rcu_read_lock(); | ||
2576 | ies = rcu_dereference(cbss->ies); | ||
2577 | if (ies) | ||
2578 | bss_ies = kmemdup(ies, sizeof(*ies) + ies->len, | ||
2579 | GFP_ATOMIC); | ||
2580 | rcu_read_unlock(); | ||
2581 | if (!bss_ies) | ||
2582 | return false; | ||
2583 | |||
2584 | ieee802_11_parse_elems(bss_ies->data, bss_ies->len, | ||
2585 | false, &bss_elems); | ||
2586 | if (assoc_data->wmm && | ||
2587 | !elems.wmm_param && bss_elems.wmm_param) { | ||
2588 | elems.wmm_param = bss_elems.wmm_param; | ||
2589 | sdata_info(sdata, | ||
2590 | "AP bug: WMM param missing from AssocResp\n"); | ||
2591 | } | ||
2592 | |||
2593 | /* | ||
2594 | * Also check if we requested HT/VHT, otherwise the AP doesn't | ||
2595 | * have to include the IEs in the (re)association response. | ||
2596 | */ | ||
2597 | if (!elems.ht_cap_elem && bss_elems.ht_cap_elem && | ||
2598 | !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { | ||
2599 | elems.ht_cap_elem = bss_elems.ht_cap_elem; | ||
2600 | sdata_info(sdata, | ||
2601 | "AP bug: HT capability missing from AssocResp\n"); | ||
2602 | } | ||
2603 | if (!elems.ht_operation && bss_elems.ht_operation && | ||
2604 | !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { | ||
2605 | elems.ht_operation = bss_elems.ht_operation; | ||
2606 | sdata_info(sdata, | ||
2607 | "AP bug: HT operation missing from AssocResp\n"); | ||
2608 | } | ||
2609 | if (!elems.vht_cap_elem && bss_elems.vht_cap_elem && | ||
2610 | !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) { | ||
2611 | elems.vht_cap_elem = bss_elems.vht_cap_elem; | ||
2612 | sdata_info(sdata, | ||
2613 | "AP bug: VHT capa missing from AssocResp\n"); | ||
2614 | } | ||
2615 | if (!elems.vht_operation && bss_elems.vht_operation && | ||
2616 | !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) { | ||
2617 | elems.vht_operation = bss_elems.vht_operation; | ||
2618 | sdata_info(sdata, | ||
2619 | "AP bug: VHT operation missing from AssocResp\n"); | ||
2620 | } | ||
2621 | } | ||
2622 | |||
2623 | /* | ||
2558 | * We previously checked these in the beacon/probe response, so | 2624 | * We previously checked these in the beacon/probe response, so |
2559 | * they should be present here. This is just a safety net. | 2625 | * they should be present here. This is just a safety net. |
2560 | */ | 2626 | */ |
2561 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && | 2627 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && |
2562 | (!elems.wmm_param || !elems.ht_cap_elem || !elems.ht_operation)) { | 2628 | (!elems.wmm_param || !elems.ht_cap_elem || !elems.ht_operation)) { |
2563 | sdata_info(sdata, | 2629 | sdata_info(sdata, |
2564 | "HT AP is missing WMM params or HT capability/operation in AssocResp\n"); | 2630 | "HT AP is missing WMM params or HT capability/operation\n"); |
2565 | return false; | 2631 | ret = false; |
2632 | goto out; | ||
2566 | } | 2633 | } |
2567 | 2634 | ||
2568 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && | 2635 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && |
2569 | (!elems.vht_cap_elem || !elems.vht_operation)) { | 2636 | (!elems.vht_cap_elem || !elems.vht_operation)) { |
2570 | sdata_info(sdata, | 2637 | sdata_info(sdata, |
2571 | "VHT AP is missing VHT capability/operation in AssocResp\n"); | 2638 | "VHT AP is missing VHT capability/operation\n"); |
2572 | return false; | 2639 | ret = false; |
2640 | goto out; | ||
2573 | } | 2641 | } |
2574 | 2642 | ||
2575 | mutex_lock(&sdata->local->sta_mtx); | 2643 | mutex_lock(&sdata->local->sta_mtx); |
@@ -2580,7 +2648,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2580 | sta = sta_info_get(sdata, cbss->bssid); | 2648 | sta = sta_info_get(sdata, cbss->bssid); |
2581 | if (WARN_ON(!sta)) { | 2649 | if (WARN_ON(!sta)) { |
2582 | mutex_unlock(&sdata->local->sta_mtx); | 2650 | mutex_unlock(&sdata->local->sta_mtx); |
2583 | return false; | 2651 | ret = false; |
2652 | goto out; | ||
2584 | } | 2653 | } |
2585 | 2654 | ||
2586 | sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; | 2655 | sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; |
@@ -2633,7 +2702,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2633 | sta->sta.addr); | 2702 | sta->sta.addr); |
2634 | WARN_ON(__sta_info_destroy(sta)); | 2703 | WARN_ON(__sta_info_destroy(sta)); |
2635 | mutex_unlock(&sdata->local->sta_mtx); | 2704 | mutex_unlock(&sdata->local->sta_mtx); |
2636 | return false; | 2705 | ret = false; |
2706 | goto out; | ||
2637 | } | 2707 | } |
2638 | 2708 | ||
2639 | mutex_unlock(&sdata->local->sta_mtx); | 2709 | mutex_unlock(&sdata->local->sta_mtx); |
@@ -2673,7 +2743,10 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2673 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); | 2743 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); |
2674 | ieee80211_sta_reset_beacon_monitor(sdata); | 2744 | ieee80211_sta_reset_beacon_monitor(sdata); |
2675 | 2745 | ||
2676 | return true; | 2746 | ret = true; |
2747 | out: | ||
2748 | kfree(bss_ies); | ||
2749 | return ret; | ||
2677 | } | 2750 | } |
2678 | 2751 | ||
2679 | static enum rx_mgmt_action __must_check | 2752 | static enum rx_mgmt_action __must_check |