diff options
author | Tosoni <jp.tosoni@acksys.fr> | 2018-03-14 17:58:34 +0100 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2018-03-21 11:27:11 +0100 |
commit | 1ad22fb5bb53ce6bf5377f25529c0a007c61c6f5 (patch) | |
tree | 3932788cc832ac2f081e81f6588fbb1c6729bddd /net/mac80211/mlme.c | |
parent | mac80211_hwsim: fix use-after-free bug in hwsim_exit_net (diff) | |
download | linux-1ad22fb5bb53ce6bf5377f25529c0a007c61c6f5.tar.xz linux-1ad22fb5bb53ce6bf5377f25529c0a007c61c6f5.zip |
mac80211: inform wireless layer when frame RSSI is invalid
When the low-level driver returns an invalid RSSI indication,
set the signal value to 0 as an indication to the upper layer.
Also, skip average level computation if signal is invalid.
Signed-off-by: Jean Pierre TOSONI <jp.tosoni@acksys.fr>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 160 |
1 files changed, 86 insertions, 74 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0024eff9bb84..ea3ba03fb952 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3306,82 +3306,14 @@ static const u64 care_about_ies = (1ULL << WLAN_EID_HT_OPERATION) | (1ULL << WLAN_EID_EXT_CHANSWITCH_ANN); -static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, - struct ieee80211_mgmt *mgmt, size_t len, - struct ieee80211_rx_status *rx_status) +static void ieee80211_handle_beacon_sig(struct ieee80211_sub_if_data *sdata, + struct ieee80211_if_managed *ifmgd, + struct ieee80211_bss_conf *bss_conf, + struct ieee80211_local *local, + struct ieee80211_rx_status *rx_status) { - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; - size_t baselen; - struct ieee802_11_elems elems; - struct ieee80211_local *local = sdata->local; - struct ieee80211_chanctx_conf *chanctx_conf; - struct ieee80211_channel *chan; - struct sta_info *sta; - u32 changed = 0; - bool erp_valid; - u8 erp_value = 0; - u32 ncrc; - u8 *bssid; - u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN]; - - sdata_assert_lock(sdata); - - /* Process beacon from the current BSS */ - baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; - if (baselen > len) - return; - - rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); - if (!chanctx_conf) { - rcu_read_unlock(); - return; - } - - if (rx_status->freq != chanctx_conf->def.chan->center_freq) { - rcu_read_unlock(); - return; - } - chan = chanctx_conf->def.chan; - rcu_read_unlock(); - - if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon && - ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) { - ieee802_11_parse_elems(mgmt->u.beacon.variable, - len - baselen, false, &elems); - - ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); - if (elems.tim && !elems.parse_error) { - const struct ieee80211_tim_ie *tim_ie = elems.tim; - ifmgd->dtim_period = tim_ie->dtim_period; - } - ifmgd->have_beacon = true; - ifmgd->assoc_data->need_beacon = false; - if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) { - sdata->vif.bss_conf.sync_tsf = - le64_to_cpu(mgmt->u.beacon.timestamp); - sdata->vif.bss_conf.sync_device_ts = - rx_status->device_timestamp; - if (elems.tim) - sdata->vif.bss_conf.sync_dtim_count = - elems.tim->dtim_count; - else - sdata->vif.bss_conf.sync_dtim_count = 0; - } - /* continue assoc process */ - ifmgd->assoc_data->timeout = jiffies; - ifmgd->assoc_data->timeout_started = true; - run_again(sdata, ifmgd->assoc_data->timeout); - return; - } - - if (!ifmgd->associated || - !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) - return; - bssid = ifmgd->associated->bssid; - /* Track average RSSI from the Beacon frames of the current AP */ + if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) { ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE; ewma_beacon_signal_init(&ifmgd->ave_beacon_signal); @@ -3468,6 +3400,86 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, sig, GFP_KERNEL); } } +} + +static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgmt *mgmt, size_t len, + struct ieee80211_rx_status *rx_status) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; + size_t baselen; + struct ieee802_11_elems elems; + struct ieee80211_local *local = sdata->local; + struct ieee80211_chanctx_conf *chanctx_conf; + struct ieee80211_channel *chan; + struct sta_info *sta; + u32 changed = 0; + bool erp_valid; + u8 erp_value = 0; + u32 ncrc; + u8 *bssid; + u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN]; + + sdata_assert_lock(sdata); + + /* Process beacon from the current BSS */ + baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; + if (baselen > len) + return; + + rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (!chanctx_conf) { + rcu_read_unlock(); + return; + } + + if (rx_status->freq != chanctx_conf->def.chan->center_freq) { + rcu_read_unlock(); + return; + } + chan = chanctx_conf->def.chan; + rcu_read_unlock(); + + if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon && + ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) { + ieee802_11_parse_elems(mgmt->u.beacon.variable, + len - baselen, false, &elems); + + ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); + if (elems.tim && !elems.parse_error) { + const struct ieee80211_tim_ie *tim_ie = elems.tim; + ifmgd->dtim_period = tim_ie->dtim_period; + } + ifmgd->have_beacon = true; + ifmgd->assoc_data->need_beacon = false; + if (ieee80211_hw_check(&local->hw, TIMING_BEACON_ONLY)) { + sdata->vif.bss_conf.sync_tsf = + le64_to_cpu(mgmt->u.beacon.timestamp); + sdata->vif.bss_conf.sync_device_ts = + rx_status->device_timestamp; + if (elems.tim) + sdata->vif.bss_conf.sync_dtim_count = + elems.tim->dtim_count; + else + sdata->vif.bss_conf.sync_dtim_count = 0; + } + /* continue assoc process */ + ifmgd->assoc_data->timeout = jiffies; + ifmgd->assoc_data->timeout_started = true; + run_again(sdata, ifmgd->assoc_data->timeout); + return; + } + + if (!ifmgd->associated || + !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) + return; + bssid = ifmgd->associated->bssid; + + if (!(rx_status->flag & RX_FLAG_NO_SIGNAL_VAL)) + ieee80211_handle_beacon_sig(sdata, ifmgd, bss_conf, + local, rx_status); if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) { mlme_dbg_ratelimited(sdata, |