aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-12-10 09:38:14 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-01-03 07:00:00 -0500
commit826262c3d23743cb032a9e1a65a0f9be75091a5e (patch)
tree353570411d99f50dd45355dc80075570bb24b5c6 /net/mac80211/mlme.c
parenta56f992cdabc63f56b4b142885deebebf936ff76 (diff)
mac80211: fix dtim_period in hidden SSID AP association
When AP's SSID is hidden the BSS can appear several times in cfg80211's BSS list: once with a zero-length SSID that comes from the beacon, and once for each SSID from probe reponses. Since the mac80211 stores its data in ieee80211_bss which is embedded into cfg80211_bss, mac80211's data will be duplicated too. This becomes a problem when a driver needs the dtim_period since this data exists only in the beacon's instance in cfg80211 bss table which isn't the instance that is used when associating. Remove the DTIM period from the BSS table and track it explicitly to avoid this problem. Cc: stable@vger.kernel.org Tested-by: Efi Tubul <efi.tubul@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c75
1 files changed, 54 insertions, 21 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 7753a9ca98a6..a3552929a21d 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1074,12 +1074,8 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
1074 if (beaconint_us > latency) { 1074 if (beaconint_us > latency) {
1075 local->ps_sdata = NULL; 1075 local->ps_sdata = NULL;
1076 } else { 1076 } else {
1077 struct ieee80211_bss *bss;
1078 int maxslp = 1; 1077 int maxslp = 1;
1079 u8 dtimper; 1078 u8 dtimper = found->u.mgd.dtim_period;
1080
1081 bss = (void *)found->u.mgd.associated->priv;
1082 dtimper = bss->dtim_period;
1083 1079
1084 /* If the TIM IE is invalid, pretend the value is 1 */ 1080 /* If the TIM IE is invalid, pretend the value is 1 */
1085 if (!dtimper) 1081 if (!dtimper)
@@ -1410,10 +1406,17 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
1410 1406
1411 ieee80211_led_assoc(local, 1); 1407 ieee80211_led_assoc(local, 1);
1412 1408
1413 if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) 1409 if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) {
1414 bss_conf->dtim_period = bss->dtim_period; 1410 /*
1415 else 1411 * If the AP is buggy we may get here with no DTIM period
1412 * known, so assume it's 1 which is the only safe assumption
1413 * in that case, although if the TIM IE is broken powersave
1414 * probably just won't work at all.
1415 */
1416 bss_conf->dtim_period = sdata->u.mgd.dtim_period ?: 1;
1417 } else {
1416 bss_conf->dtim_period = 0; 1418 bss_conf->dtim_period = 0;
1419 }
1417 1420
1418 bss_conf->assoc = 1; 1421 bss_conf->assoc = 1;
1419 1422
@@ -1562,6 +1565,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
1562 1565
1563 sdata->u.mgd.timers_running = 0; 1566 sdata->u.mgd.timers_running = 0;
1564 1567
1568 sdata->vif.bss_conf.dtim_period = 0;
1569
1565 ifmgd->flags = 0; 1570 ifmgd->flags = 0;
1566 ieee80211_vif_release_channel(sdata); 1571 ieee80211_vif_release_channel(sdata);
1567} 1572}
@@ -2373,11 +2378,18 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
2373 struct ieee80211_channel *channel; 2378 struct ieee80211_channel *channel;
2374 bool need_ps = false; 2379 bool need_ps = false;
2375 2380
2376 if (sdata->u.mgd.associated && 2381 if ((sdata->u.mgd.associated &&
2377 ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) { 2382 ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) ||
2378 bss = (void *)sdata->u.mgd.associated->priv; 2383 (sdata->u.mgd.assoc_data &&
2384 ether_addr_equal(mgmt->bssid,
2385 sdata->u.mgd.assoc_data->bss->bssid))) {
2379 /* not previously set so we may need to recalc */ 2386 /* not previously set so we may need to recalc */
2380 need_ps = !bss->dtim_period; 2387 need_ps = sdata->u.mgd.associated && !sdata->u.mgd.dtim_period;
2388
2389 if (elems->tim && !elems->parse_error) {
2390 struct ieee80211_tim_ie *tim_ie = elems->tim;
2391 sdata->u.mgd.dtim_period = tim_ie->dtim_period;
2392 }
2381 } 2393 }
2382 2394
2383 if (elems->ds_params && elems->ds_params_len == 1) 2395 if (elems->ds_params && elems->ds_params_len == 1)
@@ -3896,20 +3908,41 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
3896 /* kick off associate process */ 3908 /* kick off associate process */
3897 3909
3898 ifmgd->assoc_data = assoc_data; 3910 ifmgd->assoc_data = assoc_data;
3911 ifmgd->dtim_period = 0;
3899 3912
3900 err = ieee80211_prep_connection(sdata, req->bss, true); 3913 err = ieee80211_prep_connection(sdata, req->bss, true);
3901 if (err) 3914 if (err)
3902 goto err_clear; 3915 goto err_clear;
3903 3916
3904 if (!bss->dtim_period && 3917 if (sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) {
3905 sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) { 3918 const struct cfg80211_bss_ies *beacon_ies;
3906 /* 3919
3907 * Wait up to one beacon interval ... 3920 rcu_read_lock();
3908 * should this be more if we miss one? 3921 beacon_ies = rcu_dereference(req->bss->beacon_ies);
3909 */ 3922 if (!beacon_ies) {
3910 sdata_info(sdata, "waiting for beacon from %pM\n", 3923 /*
3911 ifmgd->bssid); 3924 * Wait up to one beacon interval ...
3912 assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval); 3925 * should this be more if we miss one?
3926 */
3927 sdata_info(sdata, "waiting for beacon from %pM\n",
3928 ifmgd->bssid);
3929 assoc_data->timeout =
3930 TU_TO_EXP_TIME(req->bss->beacon_interval);
3931 } else {
3932 const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM,
3933 beacon_ies->data,
3934 beacon_ies->len);
3935 if (tim_ie && tim_ie[1] >=
3936 sizeof(struct ieee80211_tim_ie)) {
3937 const struct ieee80211_tim_ie *tim;
3938 tim = (void *)(tim_ie + 2);
3939 ifmgd->dtim_period = tim->dtim_period;
3940 }
3941 assoc_data->have_beacon = true;
3942 assoc_data->sent_assoc = false;
3943 assoc_data->timeout = jiffies;
3944 }
3945 rcu_read_unlock();
3913 } else { 3946 } else {
3914 assoc_data->have_beacon = true; 3947 assoc_data->have_beacon = true;
3915 assoc_data->sent_assoc = false; 3948 assoc_data->sent_assoc = false;