mac80211: wait for beacon before enabling powersave
Because DTIM information is required for powersave but is only conveyed in beacons, wait for a beacon before enabling powersave, and change the way the information is conveyed to the driver accordingly. mwl8k doesn't currently seem to implement PS but requires the DTIM period in a different way; after talking to Lennert we agreed to just have mwl8k do the parsing itself in the finalize_join work. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Acked-by: Lennert Buytenhek <buytenh@marvell.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
c21dbf9214
commit
56007a028c
7 changed files with 47 additions and 35 deletions
|
@ -319,7 +319,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
|
|||
priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
|
||||
|
||||
if (priv->vif)
|
||||
dtimper = priv->vif->bss_conf.dtim_period;
|
||||
dtimper = priv->hw->conf.ps_dtim_period;
|
||||
else
|
||||
dtimper = 1;
|
||||
|
||||
|
|
|
@ -3881,12 +3881,16 @@ static void mwl8k_finalize_join_worker(struct work_struct *work)
|
|||
struct mwl8k_priv *priv =
|
||||
container_of(work, struct mwl8k_priv, finalize_join_worker);
|
||||
struct sk_buff *skb = priv->beacon_skb;
|
||||
struct mwl8k_vif *mwl8k_vif;
|
||||
struct ieee80211_mgmt *mgmt = (void *)skb->data;
|
||||
int len = skb->len - offsetof(struct ieee80211_mgmt, u.beacon.variable);
|
||||
const u8 *tim = cfg80211_find_ie(WLAN_EID_TIM,
|
||||
mgmt->u.beacon.variable, len);
|
||||
int dtim_period = 1;
|
||||
|
||||
mwl8k_vif = mwl8k_first_vif(priv);
|
||||
if (mwl8k_vif != NULL)
|
||||
mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len,
|
||||
mwl8k_vif->vif->bss_conf.dtim_period);
|
||||
if (tim && tim[1] >= 2)
|
||||
dtim_period = tim[3];
|
||||
|
||||
mwl8k_cmd_finalize_join(priv->hw, skb->data, skb->len, dtim_period);
|
||||
|
||||
dev_kfree_skb(skb);
|
||||
priv->beacon_skb = NULL;
|
||||
|
|
|
@ -341,9 +341,6 @@ struct wl1251 {
|
|||
/* Are we currently scanning */
|
||||
bool scanning;
|
||||
|
||||
/* Our association ID */
|
||||
u16 aid;
|
||||
|
||||
/* Default key (for WEP) */
|
||||
u32 default_key;
|
||||
|
||||
|
|
|
@ -617,10 +617,13 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
|
|||
|
||||
wl->psm_requested = true;
|
||||
|
||||
wl->dtim_period = conf->ps_dtim_period;
|
||||
|
||||
ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int,
|
||||
wl->dtim_period);
|
||||
|
||||
/*
|
||||
* We enter PSM only if we're already associated.
|
||||
* If we're not, we'll enter it when joining an SSID,
|
||||
* through the bss_info_changed() hook.
|
||||
* mac80211 enables PSM only if we're already associated.
|
||||
*/
|
||||
ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
|
||||
if (ret < 0)
|
||||
|
@ -943,7 +946,6 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
|
|||
struct ieee80211_bss_conf *bss_conf,
|
||||
u32 changed)
|
||||
{
|
||||
enum wl1251_cmd_ps_mode mode;
|
||||
struct wl1251 *wl = hw->priv;
|
||||
struct sk_buff *beacon, *skb;
|
||||
int ret;
|
||||
|
@ -984,11 +986,6 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
|
|||
if (changed & BSS_CHANGED_ASSOC) {
|
||||
if (bss_conf->assoc) {
|
||||
wl->beacon_int = bss_conf->beacon_int;
|
||||
wl->dtim_period = bss_conf->dtim_period;
|
||||
|
||||
ret = wl1251_acx_wr_tbtt_and_dtim(wl, wl->beacon_int,
|
||||
wl->dtim_period);
|
||||
wl->aid = bss_conf->aid;
|
||||
|
||||
skb = ieee80211_pspoll_get(wl->hw, wl->vif);
|
||||
if (!skb)
|
||||
|
@ -1001,17 +998,9 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
|
|||
if (ret < 0)
|
||||
goto out_sleep;
|
||||
|
||||
ret = wl1251_acx_aid(wl, wl->aid);
|
||||
ret = wl1251_acx_aid(wl, bss_conf->aid);
|
||||
if (ret < 0)
|
||||
goto out_sleep;
|
||||
|
||||
/* If we want to go in PSM but we're not there yet */
|
||||
if (wl->psm_requested && !wl->psm) {
|
||||
mode = STATION_POWER_SAVE_MODE;
|
||||
ret = wl1251_ps_set_mode(wl, mode);
|
||||
if (ret < 0)
|
||||
goto out_sleep;
|
||||
}
|
||||
} else {
|
||||
/* use defaults when not associated */
|
||||
wl->beacon_int = WL1251_DEFAULT_BEACON_INT;
|
||||
|
|
|
@ -186,7 +186,8 @@ enum ieee80211_bss_change {
|
|||
* @use_short_slot: use short slot time (only relevant for ERP);
|
||||
* if the hardware cannot handle this it must set the
|
||||
* IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag
|
||||
* @dtim_period: num of beacons before the next DTIM, for PSM
|
||||
* @dtim_period: num of beacons before the next DTIM, for beaconing,
|
||||
* not valid in station mode (cf. hw conf ps_dtim_period)
|
||||
* @timestamp: beacon timestamp
|
||||
* @beacon_int: beacon interval
|
||||
* @assoc_capability: capabilities taken from assoc resp
|
||||
|
@ -648,6 +649,9 @@ enum ieee80211_smps_mode {
|
|||
* value will be only achievable between DTIM frames, the hardware
|
||||
* needs to check for the multicast traffic bit in DTIM beacons.
|
||||
* This variable is valid only when the CONF_PS flag is set.
|
||||
* @ps_dtim_period: The DTIM period of the AP we're connected to, for use
|
||||
* in power saving. Power saving will not be enabled until a beacon
|
||||
* has been received and the DTIM period is known.
|
||||
* @dynamic_ps_timeout: The dynamic powersave timeout (in ms), see the
|
||||
* powersave documentation below. This variable is valid only when
|
||||
* the CONF_PS flag is set.
|
||||
|
@ -674,6 +678,7 @@ struct ieee80211_conf {
|
|||
int max_sleep_period;
|
||||
|
||||
u16 listen_interval;
|
||||
u8 ps_dtim_period;
|
||||
|
||||
u8 long_frame_max_tx_count, short_frame_max_tx_count;
|
||||
|
||||
|
|
|
@ -484,6 +484,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
|
|||
|
||||
if (count == 1 && found->u.mgd.powersave &&
|
||||
found->u.mgd.associated &&
|
||||
found->u.mgd.associated->beacon_ies &&
|
||||
!(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
|
||||
IEEE80211_STA_CONNECTION_POLL))) {
|
||||
s32 beaconint_us;
|
||||
|
@ -497,14 +498,22 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
|
|||
if (beaconint_us > latency) {
|
||||
local->ps_sdata = NULL;
|
||||
} else {
|
||||
u8 dtimper = found->vif.bss_conf.dtim_period;
|
||||
struct ieee80211_bss *bss;
|
||||
int maxslp = 1;
|
||||
u8 dtimper;
|
||||
|
||||
if (dtimper > 1)
|
||||
bss = (void *)found->u.mgd.associated->priv;
|
||||
dtimper = bss->dtim_period;
|
||||
|
||||
/* If the TIM IE is invalid, pretend the value is 1 */
|
||||
if (!dtimper)
|
||||
dtimper = 1;
|
||||
else if (dtimper > 1)
|
||||
maxslp = min_t(int, dtimper,
|
||||
latency / beaconint_us);
|
||||
|
||||
local->hw.conf.max_sleep_period = maxslp;
|
||||
local->hw.conf.ps_dtim_period = dtimper;
|
||||
local->ps_sdata = found;
|
||||
}
|
||||
} else {
|
||||
|
@ -702,7 +711,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
|
|||
/* set timing information */
|
||||
sdata->vif.bss_conf.beacon_int = cbss->beacon_interval;
|
||||
sdata->vif.bss_conf.timestamp = cbss->tsf;
|
||||
sdata->vif.bss_conf.dtim_period = bss->dtim_period;
|
||||
|
||||
bss_info_changed |= BSS_CHANGED_BEACON_INT;
|
||||
bss_info_changed |= ieee80211_handle_bss_capability(sdata,
|
||||
|
@ -1168,6 +1176,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
int freq;
|
||||
struct ieee80211_bss *bss;
|
||||
struct ieee80211_channel *channel;
|
||||
bool need_ps = false;
|
||||
|
||||
if (sdata->u.mgd.associated) {
|
||||
bss = (void *)sdata->u.mgd.associated->priv;
|
||||
/* not previously set so we may need to recalc */
|
||||
need_ps = !bss->dtim_period;
|
||||
}
|
||||
|
||||
if (elems->ds_params && elems->ds_params_len == 1)
|
||||
freq = ieee80211_channel_to_frequency(elems->ds_params[0]);
|
||||
|
@ -1187,6 +1202,12 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
|
|||
if (!sdata->u.mgd.associated)
|
||||
return;
|
||||
|
||||
if (need_ps) {
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
ieee80211_recalc_ps(local, -1);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
}
|
||||
|
||||
if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) &&
|
||||
(memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid,
|
||||
ETH_ALEN) == 0)) {
|
||||
|
|
|
@ -111,10 +111,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
|
|||
bss->dtim_period = tim_ie->dtim_period;
|
||||
}
|
||||
|
||||
/* set default value for buggy AP/no TIM element */
|
||||
if (bss->dtim_period == 0)
|
||||
bss->dtim_period = 1;
|
||||
|
||||
bss->supp_rates_len = 0;
|
||||
if (elems->supp_rates) {
|
||||
clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
|
||||
|
|
Loading…
Reference in a new issue