Commit 826262c3d23743cb032a9e1a65a0f9be75091a5e

Authored by Johannes Berg
1 parent a56f992cda

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>

Showing 3 changed files with 55 additions and 37 deletions Side-by-side Diff

net/mac80211/ieee80211_i.h
... ... @@ -92,8 +92,6 @@
92 92  
93 93 u32 device_ts;
94 94  
95   - u8 dtim_period;
96   -
97 95 bool wmm_used;
98 96 bool uapsd_supported;
99 97  
... ... @@ -140,7 +138,6 @@
140 138  
141 139 /**
142 140 * enum ieee80211_valid_data_flags - BSS valid data flags
143   - * @IEEE80211_BSS_VALID_DTIM: DTIM data was gathered from non-corrupt IE
144 141 * @IEEE80211_BSS_VALID_WMM: WMM/UAPSD data was gathered from non-corrupt IE
145 142 * @IEEE80211_BSS_VALID_RATES: Supported rates were gathered from non-corrupt IE
146 143 * @IEEE80211_BSS_VALID_ERP: ERP flag was gathered from non-corrupt IE
... ... @@ -151,7 +148,6 @@
151 148 * beacon/probe response.
152 149 */
153 150 enum ieee80211_bss_valid_data_flags {
154   - IEEE80211_BSS_VALID_DTIM = BIT(0),
155 151 IEEE80211_BSS_VALID_WMM = BIT(1),
156 152 IEEE80211_BSS_VALID_RATES = BIT(2),
157 153 IEEE80211_BSS_VALID_ERP = BIT(3)
... ... @@ -440,6 +436,7 @@
440 436 unsigned long timers_running; /* used for quiesce/restart */
441 437 bool powersave; /* powersave requested for this iface */
442 438 bool broken_ap; /* AP is broken -- turn off powersave */
  439 + u8 dtim_period;
443 440 enum ieee80211_smps_mode req_smps, /* requested smps mode */
444 441 driver_smps_mode; /* smps mode request */
445 442  
... ... @@ -1074,13 +1074,9 @@
1074 1074 if (beaconint_us > latency) {
1075 1075 local->ps_sdata = NULL;
1076 1076 } else {
1077   - struct ieee80211_bss *bss;
1078 1077 int maxslp = 1;
1079   - u8 dtimper;
  1078 + u8 dtimper = found->u.mgd.dtim_period;
1080 1079  
1081   - bss = (void *)found->u.mgd.associated->priv;
1082   - dtimper = bss->dtim_period;
1083   -
1084 1080 /* If the TIM IE is invalid, pretend the value is 1 */
1085 1081 if (!dtimper)
1086 1082 dtimper = 1;
1087 1083  
... ... @@ -1410,10 +1406,17 @@
1410 1406  
1411 1407 ieee80211_led_assoc(local, 1);
1412 1408  
1413   - if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD)
1414   - bss_conf->dtim_period = bss->dtim_period;
1415   - else
  1409 + if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) {
  1410 + /*
  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 1418 bss_conf->dtim_period = 0;
  1419 + }
1417 1420  
1418 1421 bss_conf->assoc = 1;
1419 1422  
... ... @@ -1562,6 +1565,8 @@
1562 1565  
1563 1566 sdata->u.mgd.timers_running = 0;
1564 1567  
  1568 + sdata->vif.bss_conf.dtim_period = 0;
  1569 +
1565 1570 ifmgd->flags = 0;
1566 1571 ieee80211_vif_release_channel(sdata);
1567 1572 }
1568 1573  
... ... @@ -2373,11 +2378,18 @@
2373 2378 struct ieee80211_channel *channel;
2374 2379 bool need_ps = false;
2375 2380  
2376   - if (sdata->u.mgd.associated &&
2377   - ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) {
2378   - bss = (void *)sdata->u.mgd.associated->priv;
  2381 + if ((sdata->u.mgd.associated &&
  2382 + ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) ||
  2383 + (sdata->u.mgd.assoc_data &&
  2384 + ether_addr_equal(mgmt->bssid,
  2385 + sdata->u.mgd.assoc_data->bss->bssid))) {
2379 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 2395 if (elems->ds_params && elems->ds_params_len == 1)
2384 2396  
... ... @@ -3896,20 +3908,41 @@
3896 3908 /* kick off associate process */
3897 3909  
3898 3910 ifmgd->assoc_data = assoc_data;
  3911 + ifmgd->dtim_period = 0;
3899 3912  
3900 3913 err = ieee80211_prep_connection(sdata, req->bss, true);
3901 3914 if (err)
3902 3915 goto err_clear;
3903 3916  
3904   - if (!bss->dtim_period &&
3905   - sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) {
3906   - /*
3907   - * Wait up to one beacon interval ...
3908   - * should this be more if we miss one?
3909   - */
3910   - sdata_info(sdata, "waiting for beacon from %pM\n",
3911   - ifmgd->bssid);
3912   - assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval);
  3917 + if (sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) {
  3918 + const struct cfg80211_bss_ies *beacon_ies;
  3919 +
  3920 + rcu_read_lock();
  3921 + beacon_ies = rcu_dereference(req->bss->beacon_ies);
  3922 + if (!beacon_ies) {
  3923 + /*
  3924 + * Wait up to one 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 3946 } else {
3914 3947 assoc_data->have_beacon = true;
3915 3948 assoc_data->sent_assoc = false;
... ... @@ -113,18 +113,6 @@
113 113 bss->valid_data |= IEEE80211_BSS_VALID_ERP;
114 114 }
115 115  
116   - if (elems->tim && (!elems->parse_error ||
117   - !(bss->valid_data & IEEE80211_BSS_VALID_DTIM))) {
118   - struct ieee80211_tim_ie *tim_ie = elems->tim;
119   - bss->dtim_period = tim_ie->dtim_period;
120   - if (!elems->parse_error)
121   - bss->valid_data |= IEEE80211_BSS_VALID_DTIM;
122   - }
123   -
124   - /* If the beacon had no TIM IE, or it was invalid, use 1 */
125   - if (beacon && !bss->dtim_period)
126   - bss->dtim_period = 1;
127   -
128 116 /* replace old supported rates if we get new values */
129 117 if (!elems->parse_error ||
130 118 !(bss->valid_data & IEEE80211_BSS_VALID_RATES)) {