Commit 7947d3e0 authored by Avraham Stern's avatar Avraham Stern Committed by Johannes Berg

mac80211: Add support for beacon report radio measurement

Add the following to support beacon report radio measurement
with the measurement mode field set to passive or active:
1. Propagate the required scan duration to the device
2. Report the scan start time (in terms of TSF)
3. Report each BSS's detection time (also in terms of TSF)

TSF times refer to the BSS that the interface that requested the
scan is connected to.
Signed-off-by: default avatarAssaf Krauss <assaf.krauss@intel.com>
Signed-off-by: default avatarAvraham Stern <avraham.stern@intel.com>
[changed ath9k/10k, at76c59x-usb, iwlegacy, wl1251 and wlcore to match
the new API]
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 1d76250b
...@@ -3858,12 +3858,16 @@ void __ath10k_scan_finish(struct ath10k *ar) ...@@ -3858,12 +3858,16 @@ void __ath10k_scan_finish(struct ath10k *ar)
break; break;
case ATH10K_SCAN_RUNNING: case ATH10K_SCAN_RUNNING:
case ATH10K_SCAN_ABORTING: case ATH10K_SCAN_ABORTING:
if (!ar->scan.is_roc) if (!ar->scan.is_roc) {
ieee80211_scan_completed(ar->hw, struct cfg80211_scan_info info = {
(ar->scan.state == .aborted = (ar->scan.state ==
ATH10K_SCAN_ABORTING)); ATH10K_SCAN_ABORTING),
else if (ar->scan.roc_notify) };
ieee80211_scan_completed(ar->hw, &info);
} else if (ar->scan.roc_notify) {
ieee80211_remain_on_channel_expired(ar->hw); ieee80211_remain_on_channel_expired(ar->hw);
}
/* fall through */ /* fall through */
case ATH10K_SCAN_STARTING: case ATH10K_SCAN_STARTING:
ar->scan.state = ATH10K_SCAN_IDLE; ar->scan.state = ATH10K_SCAN_IDLE;
......
...@@ -960,6 +960,9 @@ void ath_roc_complete(struct ath_softc *sc, enum ath_roc_complete_reason reason) ...@@ -960,6 +960,9 @@ void ath_roc_complete(struct ath_softc *sc, enum ath_roc_complete_reason reason)
void ath_scan_complete(struct ath_softc *sc, bool abort) void ath_scan_complete(struct ath_softc *sc, bool abort)
{ {
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct cfg80211_scan_info info = {
.aborted = abort,
};
if (abort) if (abort)
ath_dbg(common, CHAN_CTX, "HW scan aborted\n"); ath_dbg(common, CHAN_CTX, "HW scan aborted\n");
...@@ -969,7 +972,7 @@ void ath_scan_complete(struct ath_softc *sc, bool abort) ...@@ -969,7 +972,7 @@ void ath_scan_complete(struct ath_softc *sc, bool abort)
sc->offchannel.scan_req = NULL; sc->offchannel.scan_req = NULL;
sc->offchannel.scan_vif = NULL; sc->offchannel.scan_vif = NULL;
sc->offchannel.state = ATH_OFFCHANNEL_IDLE; sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
ieee80211_scan_completed(sc->hw, abort); ieee80211_scan_completed(sc->hw, &info);
clear_bit(ATH_OP_SCANNING, &common->op_flags); clear_bit(ATH_OP_SCANNING, &common->op_flags);
spin_lock_bh(&sc->chan_lock); spin_lock_bh(&sc->chan_lock);
if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
......
...@@ -1922,6 +1922,9 @@ static void at76_dwork_hw_scan(struct work_struct *work) ...@@ -1922,6 +1922,9 @@ static void at76_dwork_hw_scan(struct work_struct *work)
{ {
struct at76_priv *priv = container_of(work, struct at76_priv, struct at76_priv *priv = container_of(work, struct at76_priv,
dwork_hw_scan.work); dwork_hw_scan.work);
struct cfg80211_scan_info info = {
.aborted = false,
};
int ret; int ret;
if (priv->device_unplugged) if (priv->device_unplugged)
...@@ -1948,7 +1951,7 @@ static void at76_dwork_hw_scan(struct work_struct *work) ...@@ -1948,7 +1951,7 @@ static void at76_dwork_hw_scan(struct work_struct *work)
mutex_unlock(&priv->mtx); mutex_unlock(&priv->mtx);
ieee80211_scan_completed(priv->hw, false); ieee80211_scan_completed(priv->hw, &info);
ieee80211_wake_queues(priv->hw); ieee80211_wake_queues(priv->hw);
} }
......
...@@ -1305,10 +1305,14 @@ il_send_scan_abort(struct il_priv *il) ...@@ -1305,10 +1305,14 @@ il_send_scan_abort(struct il_priv *il)
static void static void
il_complete_scan(struct il_priv *il, bool aborted) il_complete_scan(struct il_priv *il, bool aborted)
{ {
struct cfg80211_scan_info info = {
.aborted = aborted,
};
/* check if scan was requested from mac80211 */ /* check if scan was requested from mac80211 */
if (il->scan_request) { if (il->scan_request) {
D_SCAN("Complete scan in mac80211\n"); D_SCAN("Complete scan in mac80211\n");
ieee80211_scan_completed(il->hw, aborted); ieee80211_scan_completed(il->hw, &info);
} }
il->scan_vif = NULL; il->scan_vif = NULL;
......
...@@ -94,10 +94,14 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) ...@@ -94,10 +94,14 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
static void iwl_complete_scan(struct iwl_priv *priv, bool aborted) static void iwl_complete_scan(struct iwl_priv *priv, bool aborted)
{ {
struct cfg80211_scan_info info = {
.aborted = aborted,
};
/* check if scan was requested from mac80211 */ /* check if scan was requested from mac80211 */
if (priv->scan_request) { if (priv->scan_request) {
IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n"); IWL_DEBUG_SCAN(priv, "Complete scan in mac80211\n");
ieee80211_scan_completed(priv->hw, aborted); ieee80211_scan_completed(priv->hw, &info);
} }
priv->scan_type = IWL_SCAN_NORMAL; priv->scan_type = IWL_SCAN_NORMAL;
......
...@@ -391,13 +391,16 @@ void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, ...@@ -391,13 +391,16 @@ void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm,
ieee80211_sched_scan_stopped(mvm->hw); ieee80211_sched_scan_stopped(mvm->hw);
mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;
} else if (mvm->scan_status & IWL_MVM_SCAN_REGULAR) { } else if (mvm->scan_status & IWL_MVM_SCAN_REGULAR) {
struct cfg80211_scan_info info = {
.aborted = aborted,
};
IWL_DEBUG_SCAN(mvm, "Regular scan %s, EBS status %s (FW)\n", IWL_DEBUG_SCAN(mvm, "Regular scan %s, EBS status %s (FW)\n",
aborted ? "aborted" : "completed", aborted ? "aborted" : "completed",
iwl_mvm_ebs_status_str(scan_notif->ebs_status)); iwl_mvm_ebs_status_str(scan_notif->ebs_status));
mvm->scan_status &= ~IWL_MVM_SCAN_REGULAR; mvm->scan_status &= ~IWL_MVM_SCAN_REGULAR;
ieee80211_scan_completed(mvm->hw, ieee80211_scan_completed(mvm->hw, &info);
scan_notif->status == IWL_SCAN_OFFLOAD_ABORTED);
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
del_timer(&mvm->scan_timer); del_timer(&mvm->scan_timer);
} else { } else {
...@@ -1430,7 +1433,11 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, ...@@ -1430,7 +1433,11 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
/* if the scan is already stopping, we don't need to notify mac80211 */ /* if the scan is already stopping, we don't need to notify mac80211 */
if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_REGULAR) { if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_REGULAR) {
ieee80211_scan_completed(mvm->hw, aborted); struct cfg80211_scan_info info = {
.aborted = aborted,
};
ieee80211_scan_completed(mvm->hw, &info);
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
del_timer(&mvm->scan_timer); del_timer(&mvm->scan_timer);
} else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_SCHED) { } else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_SCHED) {
...@@ -1564,7 +1571,11 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm) ...@@ -1564,7 +1571,11 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm)
uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_REGULAR); uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_REGULAR);
if (uid >= 0) { if (uid >= 0) {
ieee80211_scan_completed(mvm->hw, true); struct cfg80211_scan_info info = {
.aborted = true,
};
ieee80211_scan_completed(mvm->hw, &info);
mvm->scan_uid_status[uid] = 0; mvm->scan_uid_status[uid] = 0;
} }
uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_SCHED); uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_SCHED);
...@@ -1585,8 +1596,13 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm) ...@@ -1585,8 +1596,13 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm)
mvm->scan_uid_status[i] = 0; mvm->scan_uid_status[i] = 0;
} }
} else { } else {
if (mvm->scan_status & IWL_MVM_SCAN_REGULAR) if (mvm->scan_status & IWL_MVM_SCAN_REGULAR) {
ieee80211_scan_completed(mvm->hw, true); struct cfg80211_scan_info info = {
.aborted = true,
};
ieee80211_scan_completed(mvm->hw, &info);
}
/* Sched scan will be restarted by mac80211 in /* Sched scan will be restarted by mac80211 in
* restart_hw, so do not report if FW is about to be * restart_hw, so do not report if FW is about to be
...@@ -1629,8 +1645,13 @@ int iwl_mvm_scan_stop(struct iwl_mvm *mvm, int type, bool notify) ...@@ -1629,8 +1645,13 @@ int iwl_mvm_scan_stop(struct iwl_mvm *mvm, int type, bool notify)
*/ */
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
del_timer(&mvm->scan_timer); del_timer(&mvm->scan_timer);
if (notify) if (notify) {
ieee80211_scan_completed(mvm->hw, true); struct cfg80211_scan_info info = {
.aborted = true,
};
ieee80211_scan_completed(mvm->hw, &info);
}
} else if (notify) { } else if (notify) {
ieee80211_sched_scan_stopped(mvm->hw); ieee80211_sched_scan_stopped(mvm->hw);
mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;
......
...@@ -1941,8 +1941,12 @@ static void hw_scan_work(struct work_struct *work) ...@@ -1941,8 +1941,12 @@ static void hw_scan_work(struct work_struct *work)
mutex_lock(&hwsim->mutex); mutex_lock(&hwsim->mutex);
if (hwsim->scan_chan_idx >= req->n_channels) { if (hwsim->scan_chan_idx >= req->n_channels) {
struct cfg80211_scan_info info = {
.aborted = false,
};
wiphy_debug(hwsim->hw->wiphy, "hw scan complete\n"); wiphy_debug(hwsim->hw->wiphy, "hw scan complete\n");
ieee80211_scan_completed(hwsim->hw, false); ieee80211_scan_completed(hwsim->hw, &info);
hwsim->hw_scan_request = NULL; hwsim->hw_scan_request = NULL;
hwsim->hw_scan_vif = NULL; hwsim->hw_scan_vif = NULL;
hwsim->tmp_chan = NULL; hwsim->tmp_chan = NULL;
...@@ -2027,13 +2031,16 @@ static void mac80211_hwsim_cancel_hw_scan(struct ieee80211_hw *hw, ...@@ -2027,13 +2031,16 @@ static void mac80211_hwsim_cancel_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif) struct ieee80211_vif *vif)
{ {
struct mac80211_hwsim_data *hwsim = hw->priv; struct mac80211_hwsim_data *hwsim = hw->priv;
struct cfg80211_scan_info info = {
.aborted = true,
};
wiphy_debug(hw->wiphy, "hwsim cancel_hw_scan\n"); wiphy_debug(hw->wiphy, "hwsim cancel_hw_scan\n");
cancel_delayed_work_sync(&hwsim->hw_scan); cancel_delayed_work_sync(&hwsim->hw_scan);
mutex_lock(&hwsim->mutex); mutex_lock(&hwsim->mutex);
ieee80211_scan_completed(hwsim->hw, true); ieee80211_scan_completed(hwsim->hw, &info);
hwsim->tmp_chan = NULL; hwsim->tmp_chan = NULL;
hwsim->hw_scan_request = NULL; hwsim->hw_scan_request = NULL;
hwsim->hw_scan_vif = NULL; hwsim->hw_scan_vif = NULL;
......
...@@ -167,6 +167,10 @@ void cw1200_scan_work(struct work_struct *work) ...@@ -167,6 +167,10 @@ void cw1200_scan_work(struct work_struct *work)
} }
if (!priv->scan.req || (priv->scan.curr == priv->scan.end)) { if (!priv->scan.req || (priv->scan.curr == priv->scan.end)) {
struct cfg80211_scan_info info = {
.aborted = priv->scan.status ? 1 : 0,
};
if (priv->scan.output_power != priv->output_power) if (priv->scan.output_power != priv->output_power)
wsm_set_output_power(priv, priv->output_power * 10); wsm_set_output_power(priv, priv->output_power * 10);
if (priv->join_status == CW1200_JOIN_STATUS_STA && if (priv->join_status == CW1200_JOIN_STATUS_STA &&
...@@ -188,7 +192,7 @@ void cw1200_scan_work(struct work_struct *work) ...@@ -188,7 +192,7 @@ void cw1200_scan_work(struct work_struct *work)
cw1200_scan_restart_delayed(priv); cw1200_scan_restart_delayed(priv);
wsm_unlock_tx(priv); wsm_unlock_tx(priv);
mutex_unlock(&priv->conf_mutex); mutex_unlock(&priv->conf_mutex);
ieee80211_scan_completed(priv->hw, priv->scan.status ? 1 : 0); ieee80211_scan_completed(priv->hw, &info);
up(&priv->scan.lock); up(&priv->scan.lock);
return; return;
} else { } else {
......
...@@ -36,7 +36,11 @@ static int wl1251_event_scan_complete(struct wl1251 *wl, ...@@ -36,7 +36,11 @@ static int wl1251_event_scan_complete(struct wl1251 *wl,
mbox->scheduled_scan_channels); mbox->scheduled_scan_channels);
if (wl->scanning) { if (wl->scanning) {
ieee80211_scan_completed(wl->hw, false); struct cfg80211_scan_info info = {
.aborted = false,
};
ieee80211_scan_completed(wl->hw, &info);
wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed"); wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan completed");
wl->scanning = false; wl->scanning = false;
if (wl->hw->conf.flags & IEEE80211_CONF_IDLE) if (wl->hw->conf.flags & IEEE80211_CONF_IDLE)
......
...@@ -448,7 +448,11 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) ...@@ -448,7 +448,11 @@ static void wl1251_op_stop(struct ieee80211_hw *hw)
WARN_ON(wl->state != WL1251_STATE_ON); WARN_ON(wl->state != WL1251_STATE_ON);
if (wl->scanning) { if (wl->scanning) {
ieee80211_scan_completed(wl->hw, true); struct cfg80211_scan_info info = {
.aborted = true,
};
ieee80211_scan_completed(wl->hw, &info);
wl->scanning = false; wl->scanning = false;
} }
......
...@@ -2615,6 +2615,10 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, ...@@ -2615,6 +2615,10 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
if (wl->scan.state != WL1271_SCAN_STATE_IDLE && if (wl->scan.state != WL1271_SCAN_STATE_IDLE &&
wl->scan_wlvif == wlvif) { wl->scan_wlvif == wlvif) {
struct cfg80211_scan_info info = {
.aborted = true,
};
/* /*
* Rearm the tx watchdog just before idling scan. This * Rearm the tx watchdog just before idling scan. This
* prevents just-finished scans from triggering the watchdog * prevents just-finished scans from triggering the watchdog
...@@ -2625,7 +2629,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, ...@@ -2625,7 +2629,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
wl->scan_wlvif = NULL; wl->scan_wlvif = NULL;
wl->scan.req = NULL; wl->scan.req = NULL;
ieee80211_scan_completed(wl->hw, true); ieee80211_scan_completed(wl->hw, &info);
} }
if (wl->sched_vif == wlvif) if (wl->sched_vif == wlvif)
...@@ -3649,6 +3653,9 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw, ...@@ -3649,6 +3653,9 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
{ {
struct wl1271 *wl = hw->priv; struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
struct cfg80211_scan_info info = {
.aborted = true,
};
int ret; int ret;
wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan"); wl1271_debug(DEBUG_MAC80211, "mac80211 cancel hw scan");
...@@ -3681,7 +3688,7 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw, ...@@ -3681,7 +3688,7 @@ static void wl1271_op_cancel_hw_scan(struct ieee80211_hw *hw,
memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
wl->scan_wlvif = NULL; wl->scan_wlvif = NULL;
wl->scan.req = NULL; wl->scan.req = NULL;
ieee80211_scan_completed(wl->hw, true); ieee80211_scan_completed(wl->hw, &info);
out_sleep: out_sleep:
wl1271_ps_elp_sleep(wl); wl1271_ps_elp_sleep(wl);
......
...@@ -36,6 +36,9 @@ void wl1271_scan_complete_work(struct work_struct *work) ...@@ -36,6 +36,9 @@ void wl1271_scan_complete_work(struct work_struct *work)
struct delayed_work *dwork; struct delayed_work *dwork;
struct wl1271 *wl; struct wl1271 *wl;
struct wl12xx_vif *wlvif; struct wl12xx_vif *wlvif;
struct cfg80211_scan_info info = {
.aborted = false,
};
int ret; int ret;
dwork = to_delayed_work(work); dwork = to_delayed_work(work);
...@@ -82,7 +85,7 @@ void wl1271_scan_complete_work(struct work_struct *work) ...@@ -82,7 +85,7 @@ void wl1271_scan_complete_work(struct work_struct *work)
wlcore_cmd_regdomain_config_locked(wl); wlcore_cmd_regdomain_config_locked(wl);
ieee80211_scan_completed(wl->hw, false); ieee80211_scan_completed(wl->hw, &info);
out: out:
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
......
...@@ -4697,9 +4697,10 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw); ...@@ -4697,9 +4697,10 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw);
* any context, including hardirq context. * any context, including hardirq context.
* *
* @hw: the hardware that finished the scan * @hw: the hardware that finished the scan
* @aborted: set to true if scan was aborted * @info: information about the completed scan
*/ */
void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted); void ieee80211_scan_completed(struct ieee80211_hw *hw,
struct cfg80211_scan_info *info);
/** /**
* ieee80211_sched_scan_results - got results from scheduled scan * ieee80211_sched_scan_results - got results from scheduled scan
......
...@@ -1250,6 +1250,7 @@ struct ieee80211_local { ...@@ -1250,6 +1250,7 @@ struct ieee80211_local {
int scan_channel_idx; int scan_channel_idx;
int scan_ies_len; int scan_ies_len;
int hw_scan_ies_bufsize; int hw_scan_ies_bufsize;
struct cfg80211_scan_info scan_info;
struct work_struct sched_scan_stopped_work; struct work_struct sched_scan_stopped_work;
struct ieee80211_sub_if_data __rcu *sched_scan_sdata; struct ieee80211_sub_if_data __rcu *sched_scan_sdata;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2007, Michael Wu <flamingice@sourmilk.net> * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
* Copyright 2013-2015 Intel Mobile Communications GmbH * Copyright 2013-2015 Intel Mobile Communications GmbH
* Copyright 2016 Intel Deutschland GmbH
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -70,6 +71,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local, ...@@ -70,6 +71,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
.boottime_ns = rx_status->boottime_ns, .boottime_ns = rx_status->boottime_ns,
}; };
bool signal_valid; bool signal_valid;
struct ieee80211_sub_if_data *scan_sdata;
if (ieee80211_hw_check(&local->hw, SIGNAL_DBM)) if (ieee80211_hw_check(&local->hw, SIGNAL_DBM))
bss_meta.signal = rx_status->signal * 100; bss_meta.signal = rx_status->signal * 100;
...@@ -83,6 +85,20 @@ ieee80211_bss_info_update(struct ieee80211_local *local, ...@@ -83,6 +85,20 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_10; bss_meta.scan_width = NL80211_BSS_CHAN_WIDTH_10;
bss_meta.chan = channel; bss_meta.chan = channel;
rcu_read_lock();
scan_sdata = rcu_dereference(local->scan_sdata);
if (scan_sdata && scan_sdata->vif.type == NL80211_IFTYPE_STATION &&
scan_sdata->vif.bss_conf.assoc &&
ieee80211_have_rx_timestamp(rx_status)) {
bss_meta.parent_tsf =
ieee80211_calculate_rx_timestamp(local, rx_status,
len + FCS_LEN, 24);
ether_addr_copy(bss_meta.parent_bssid,
scan_sdata->vif.bss_conf.bssid);
}
rcu_read_unlock();
cbss = cfg80211_inform_bss_frame_data(local->hw.wiphy, &bss_meta, cbss = cfg80211_inform_bss_frame_data(local->hw.wiphy, &bss_meta,
mgmt, len, GFP_ATOMIC); mgmt, len, GFP_ATOMIC);
if (!cbss) if (!cbss)
...@@ -345,6 +361,11 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) ...@@ -345,6 +361,11 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
if (rc == 0) if (rc == 0)
return; return;
/* HW scan failed and is going to be reported as done, so clear
* old scan info.
*/
memset(&local->scan_info, 0, sizeof(local->scan_info));
} }
kfree(local->hw_scan_req); kfree(local->hw_scan_req);
...@@ -354,11 +375,8 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) ...@@ -354,11 +375,8 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
lockdep_is_held(&local->mtx)); lockdep_is_held(&local->mtx));
if (scan_req != local->int_scan_req) { if (scan_req != local->int_scan_req) {
struct cfg80211_scan_info info = { local->scan_info.aborted = aborted;
.aborted = aborted, cfg80211_scan_done(scan_req, &local->scan_info);
};
cfg80211_scan_done(scan_req, &info);
} }
RCU_INIT_POINTER(local->scan_req, NULL); RCU_INIT_POINTER(local->scan_req, NULL);
...@@ -396,15 +414,19 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) ...@@ -396,15 +414,19 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
ieee80211_start_next_roc(local); ieee80211_start_next_roc(local);
} }
void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) void ieee80211_scan_completed(struct ieee80211_hw *hw,
struct cfg80211_scan_info *info)
{ {
struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_local *local = hw_to_local(hw);
trace_api_scan_completed(local, aborted); trace_api_scan_completed(local, info);
set_bit(SCAN_COMPLETED, &local->scanning); set_bit(SCAN_COMPLETED, &local->scanning);
if (aborted) if (info->aborted)
set_bit(SCAN_ABORTED, &local->scanning); set_bit(SCAN_ABORTED, &local->scanning);
memcpy(&local->scan_info, info, sizeof(*info));
ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0); ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0);
} }
EXPORT_SYMBOL(ieee80211_scan_completed); EXPORT_SYMBOL(ieee80211_scan_completed);
...@@ -571,6 +593,9 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, ...@@ -571,6 +593,9 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
local->hw_scan_req->req.ie = ies; local->hw_scan_req->req.ie = ies;
local->hw_scan_req->req.flags = req->flags; local->hw_scan_req->req.flags = req->flags;
eth_broadcast_addr(local->hw_scan_req->req.bssid); eth_broadcast_addr(local->hw_scan_req->req.bssid);
local->hw_scan_req->req.duration = req->duration;
local->hw_scan_req->req.duration_mandatory =
req->duration_mandatory;
local->hw_scan_band = 0; local->hw_scan_band = 0;
...@@ -1078,6 +1103,7 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) ...@@ -1078,6 +1103,7 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
*/ */
cancel_delayed_work(&local->scan_work); cancel_delayed_work(&local->scan_work);
/* and clean up */ /* and clean up */
memset(&local->scan_info, 0, sizeof(local->scan_info));
__ieee80211_scan_completed(&local->hw, true); __ieee80211_scan_completed(&local->hw, true);
out: out:
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment