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 ad9bb9e10cbb..9e49f557fa5c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -2492,8 +2492,11 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2492 | u16 capab_info, aid; | 2492 | u16 capab_info, aid; |
2493 | struct ieee802_11_elems elems; | 2493 | struct ieee802_11_elems elems; |
2494 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | 2494 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
2495 | const struct cfg80211_bss_ies *bss_ies = NULL; | ||
2496 | struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; | ||
2495 | u32 changed = 0; | 2497 | u32 changed = 0; |
2496 | int err; | 2498 | int err; |
2499 | bool ret; | ||
2497 | 2500 | ||
2498 | /* AssocResp and ReassocResp have identical structure */ | 2501 | /* AssocResp and ReassocResp have identical structure */ |
2499 | 2502 | ||
@@ -2525,21 +2528,86 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2525 | ifmgd->aid = aid; | 2528 | ifmgd->aid = aid; |
2526 | 2529 | ||
2527 | /* | 2530 | /* |
2531 | * Some APs are erroneously not including some information in their | ||
2532 | * (re)association response frames. Try to recover by using the data | ||
2533 | * from the beacon or probe response. This seems to afflict mobile | ||
2534 | * 2G/3G/4G wifi routers, reported models include the "Onda PN51T", | ||
2535 | * "Vodafone PocketWiFi 2", "ZTE MF60" and a similar T-Mobile device. | ||
2536 | */ | ||
2537 | if ((assoc_data->wmm && !elems.wmm_param) || | ||
2538 | (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && | ||
2539 | (!elems.ht_cap_elem || !elems.ht_operation)) || | ||
2540 | (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && | ||
2541 | (!elems.vht_cap_elem || !elems.vht_operation))) { | ||
2542 | const struct cfg80211_bss_ies *ies; | ||
2543 | struct ieee802_11_elems bss_elems; | ||
2544 | |||
2545 | rcu_read_lock(); | ||
2546 | ies = rcu_dereference(cbss->ies); | ||
2547 | if (ies) | ||
2548 | bss_ies = kmemdup(ies, sizeof(*ies) + ies->len, | ||
2549 | GFP_ATOMIC); | ||
2550 | rcu_read_unlock(); | ||
2551 | if (!bss_ies) | ||
2552 | return false; | ||
2553 | |||
2554 | ieee802_11_parse_elems(bss_ies->data, bss_ies->len, | ||
2555 | false, &bss_elems); | ||
2556 | if (assoc_data->wmm && | ||
2557 | !elems.wmm_param && bss_elems.wmm_param) { | ||
2558 | elems.wmm_param = bss_elems.wmm_param; | ||
2559 | sdata_info(sdata, | ||
2560 | "AP bug: WMM param missing from AssocResp\n"); | ||
2561 | } | ||
2562 | |||
2563 | /* | ||
2564 | * Also check if we requested HT/VHT, otherwise the AP doesn't | ||
2565 | * have to include the IEs in the (re)association response. | ||
2566 | */ | ||
2567 | if (!elems.ht_cap_elem && bss_elems.ht_cap_elem && | ||
2568 | !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { | ||
2569 | elems.ht_cap_elem = bss_elems.ht_cap_elem; | ||
2570 | sdata_info(sdata, | ||
2571 | "AP bug: HT capability missing from AssocResp\n"); | ||
2572 | } | ||
2573 | if (!elems.ht_operation && bss_elems.ht_operation && | ||
2574 | !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { | ||
2575 | elems.ht_operation = bss_elems.ht_operation; | ||
2576 | sdata_info(sdata, | ||
2577 | "AP bug: HT operation missing from AssocResp\n"); | ||
2578 | } | ||
2579 | if (!elems.vht_cap_elem && bss_elems.vht_cap_elem && | ||
2580 | !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) { | ||
2581 | elems.vht_cap_elem = bss_elems.vht_cap_elem; | ||
2582 | sdata_info(sdata, | ||
2583 | "AP bug: VHT capa missing from AssocResp\n"); | ||
2584 | } | ||
2585 | if (!elems.vht_operation && bss_elems.vht_operation && | ||
2586 | !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) { | ||
2587 | elems.vht_operation = bss_elems.vht_operation; | ||
2588 | sdata_info(sdata, | ||
2589 | "AP bug: VHT operation missing from AssocResp\n"); | ||
2590 | } | ||
2591 | } | ||
2592 | |||
2593 | /* | ||
2528 | * We previously checked these in the beacon/probe response, so | 2594 | * We previously checked these in the beacon/probe response, so |
2529 | * they should be present here. This is just a safety net. | 2595 | * they should be present here. This is just a safety net. |
2530 | */ | 2596 | */ |
2531 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && | 2597 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && |
2532 | (!elems.wmm_param || !elems.ht_cap_elem || !elems.ht_operation)) { | 2598 | (!elems.wmm_param || !elems.ht_cap_elem || !elems.ht_operation)) { |
2533 | sdata_info(sdata, | 2599 | sdata_info(sdata, |
2534 | "HT AP is missing WMM params or HT capability/operation in AssocResp\n"); | 2600 | "HT AP is missing WMM params or HT capability/operation\n"); |
2535 | return false; | 2601 | ret = false; |
2602 | goto out; | ||
2536 | } | 2603 | } |
2537 | 2604 | ||
2538 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && | 2605 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && |
2539 | (!elems.vht_cap_elem || !elems.vht_operation)) { | 2606 | (!elems.vht_cap_elem || !elems.vht_operation)) { |
2540 | sdata_info(sdata, | 2607 | sdata_info(sdata, |
2541 | "VHT AP is missing VHT capability/operation in AssocResp\n"); | 2608 | "VHT AP is missing VHT capability/operation\n"); |
2542 | return false; | 2609 | ret = false; |
2610 | goto out; | ||
2543 | } | 2611 | } |
2544 | 2612 | ||
2545 | mutex_lock(&sdata->local->sta_mtx); | 2613 | mutex_lock(&sdata->local->sta_mtx); |
@@ -2550,7 +2618,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2550 | sta = sta_info_get(sdata, cbss->bssid); | 2618 | sta = sta_info_get(sdata, cbss->bssid); |
2551 | if (WARN_ON(!sta)) { | 2619 | if (WARN_ON(!sta)) { |
2552 | mutex_unlock(&sdata->local->sta_mtx); | 2620 | mutex_unlock(&sdata->local->sta_mtx); |
2553 | return false; | 2621 | ret = false; |
2622 | goto out; | ||
2554 | } | 2623 | } |
2555 | 2624 | ||
2556 | sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; | 2625 | sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; |
@@ -2603,7 +2672,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2603 | sta->sta.addr); | 2672 | sta->sta.addr); |
2604 | WARN_ON(__sta_info_destroy(sta)); | 2673 | WARN_ON(__sta_info_destroy(sta)); |
2605 | mutex_unlock(&sdata->local->sta_mtx); | 2674 | mutex_unlock(&sdata->local->sta_mtx); |
2606 | return false; | 2675 | ret = false; |
2676 | goto out; | ||
2607 | } | 2677 | } |
2608 | 2678 | ||
2609 | mutex_unlock(&sdata->local->sta_mtx); | 2679 | mutex_unlock(&sdata->local->sta_mtx); |
@@ -2643,7 +2713,10 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, | |||
2643 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); | 2713 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); |
2644 | ieee80211_sta_reset_beacon_monitor(sdata); | 2714 | ieee80211_sta_reset_beacon_monitor(sdata); |
2645 | 2715 | ||
2646 | return true; | 2716 | ret = true; |
2717 | out: | ||
2718 | kfree(bss_ies); | ||
2719 | return ret; | ||
2647 | } | 2720 | } |
2648 | 2721 | ||
2649 | static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | 2722 | static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, |