diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 75 |
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; |