aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c87
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
2649static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, 2722static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,