Commit 1d76250b authored by Avraham Stern's avatar Avraham Stern Committed by Johannes Berg

nl80211: support beacon report scanning

Beacon report radio measurement requires reporting observed BSSs
on the channels specified in the beacon request. If the measurement
mode is set to passive or active, it requires actually performing a
scan (passive or active, accordingly), and reporting the time that
the scan was started and the time each beacon/probe was received
(both in terms of TSF of the BSS of the requesting AP). If the
request mode is table, this information is optional.
In addition, the radio measurement request specifies the channel
dwell time for the measurement.

In order to use scan for beacon report when the mode is active or
passive, add a parameter to scan request that specifies the
channel dwell time, and add scan start time and beacon received time
to scan results information.

Supporting beacon report is required for Multi Band Operation (MBO).
Signed-off-by: default avatarAssaf Krauss <assaf.krauss@intel.com>
Signed-off-by: default avatarDavid Spinadel <david.spinadel@intel.com>
Signed-off-by: default avatarAvraham Stern <avraham.stern@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent f1724b02
......@@ -859,7 +859,11 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
struct ath6kl *ar = vif->ar;
if (vif->scan_req) {
cfg80211_scan_done(vif->scan_req, true);
struct cfg80211_scan_info info = {
.aborted = true,
};
cfg80211_scan_done(vif->scan_req, &info);
vif->scan_req = NULL;
}
......@@ -1069,6 +1073,9 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy,
void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted)
{
struct ath6kl *ar = vif->ar;
struct cfg80211_scan_info info = {
.aborted = aborted,
};
int i;
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status%s\n", __func__,
......@@ -1089,7 +1096,7 @@ void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted)
}
out:
cfg80211_scan_done(vif->scan_req, aborted);
cfg80211_scan_done(vif->scan_req, &info);
vif->scan_req = NULL;
}
......@@ -3614,7 +3621,11 @@ void ath6kl_cfg80211_vif_stop(struct ath6kl_vif *vif, bool wmi_ready)
}
if (vif->scan_req) {
cfg80211_scan_done(vif->scan_req, true);
struct cfg80211_scan_info info = {
.aborted = true,
};
cfg80211_scan_done(vif->scan_req, &info);
vif->scan_req = NULL;
}
......
......@@ -1369,7 +1369,11 @@ static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy,
mutex_lock(&wil->mutex);
started = wil_p2p_stop_discovery(wil);
if (started && wil->scan_request) {
cfg80211_scan_done(wil->scan_request, 1);
struct cfg80211_scan_info info = {
.aborted = true,
};
cfg80211_scan_done(wil->scan_request, &info);
wil->scan_request = NULL;
wil->radio_wdev = wil->wdev;
}
......
......@@ -850,10 +850,14 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
mutex_unlock(&wil->wmi_mutex);
if (wil->scan_request) {
struct cfg80211_scan_info info = {
.aborted = true,
};
wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
wil->scan_request);
del_timer_sync(&wil->scan_timer);
cfg80211_scan_done(wil->scan_request, true);
cfg80211_scan_done(wil->scan_request, &info);
wil->scan_request = NULL;
}
......@@ -1049,10 +1053,14 @@ int __wil_down(struct wil6210_priv *wil)
(void)wil_p2p_stop_discovery(wil);
if (wil->scan_request) {
struct cfg80211_scan_info info = {
.aborted = true,
};
wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
wil->scan_request);
del_timer_sync(&wil->scan_timer);
cfg80211_scan_done(wil->scan_request, true);
cfg80211_scan_done(wil->scan_request, &info);
wil->scan_request = NULL;
}
......
......@@ -252,8 +252,12 @@ void wil_p2p_search_expired(struct work_struct *work)
mutex_unlock(&wil->mutex);
if (started) {
struct cfg80211_scan_info info = {
.aborted = false,
};
mutex_lock(&wil->p2p_wdev_mutex);
cfg80211_scan_done(wil->scan_request, 0);
cfg80211_scan_done(wil->scan_request, &info);
wil->scan_request = NULL;
wil->radio_wdev = wil->wdev;
mutex_unlock(&wil->p2p_wdev_mutex);
......
......@@ -426,15 +426,17 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,
{
if (wil->scan_request) {
struct wmi_scan_complete_event *data = d;
bool aborted = (data->status != WMI_SCAN_SUCCESS);
struct cfg80211_scan_info info = {
.aborted = (data->status != WMI_SCAN_SUCCESS),
};
wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", data->status);
wil_dbg_misc(wil, "Complete scan_request 0x%p aborted %d\n",
wil->scan_request, aborted);
wil->scan_request, info.aborted);
del_timer_sync(&wil->scan_timer);
mutex_lock(&wil->p2p_wdev_mutex);
cfg80211_scan_done(wil->scan_request, aborted);
cfg80211_scan_done(wil->scan_request, &info);
wil->radio_wdev = wil->wdev;
mutex_unlock(&wil->p2p_wdev_mutex);
wil->scan_request = NULL;
......
......@@ -775,9 +775,13 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
if (!aborted)
cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
} else if (scan_request) {
struct cfg80211_scan_info info = {
.aborted = aborted,
};
brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
aborted ? "Aborted" : "Done");
cfg80211_scan_done(scan_request, aborted);
cfg80211_scan_done(scan_request, &info);
}
if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
......
......@@ -237,7 +237,11 @@ void orinoco_add_hostscan_results(struct orinoco_private *priv,
scan_abort:
if (priv->scan_request) {
cfg80211_scan_done(priv->scan_request, abort);
struct cfg80211_scan_info info = {
.aborted = abort,
};
cfg80211_scan_done(priv->scan_request, &info);
priv->scan_request = NULL;
}
}
......@@ -245,7 +249,11 @@ void orinoco_add_hostscan_results(struct orinoco_private *priv,
void orinoco_scan_done(struct orinoco_private *priv, bool abort)
{
if (priv->scan_request) {
cfg80211_scan_done(priv->scan_request, abort);
struct cfg80211_scan_info info = {
.aborted = abort,
};
cfg80211_scan_done(priv->scan_request, &info);
priv->scan_request = NULL;
}
}
......@@ -796,10 +796,15 @@ void lbs_scan_done(struct lbs_private *priv)
{
WARN_ON(!priv->scan_req);
if (priv->internal_scan)
if (priv->internal_scan) {
kfree(priv->scan_req);
else
cfg80211_scan_done(priv->scan_req, false);
} else {
struct cfg80211_scan_info info = {
.aborted = false,
};
cfg80211_scan_done(priv->scan_req, &info);
}
priv->scan_req = NULL;
}
......
......@@ -1057,8 +1057,12 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
if (!priv)
continue;
if (priv->scan_request) {
struct cfg80211_scan_info info = {
.aborted = true,
};
mwifiex_dbg(adapter, WARN, "info: aborting scan\n");
cfg80211_scan_done(priv->scan_request, 1);
cfg80211_scan_done(priv->scan_request, &info);
priv->scan_request = NULL;
}
}
......@@ -1112,8 +1116,12 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
if (!priv)
continue;
if (priv->scan_request) {
struct cfg80211_scan_info info = {
.aborted = true,
};
mwifiex_dbg(adapter, WARN, "info: aborting scan\n");
cfg80211_scan_done(priv->scan_request, 1);
cfg80211_scan_done(priv->scan_request, &info);
priv->scan_request = NULL;
}
}
......
......@@ -697,9 +697,13 @@ mwifiex_close(struct net_device *dev)
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
if (priv->scan_request) {
struct cfg80211_scan_info info = {
.aborted = true,
};
mwifiex_dbg(priv->adapter, INFO,
"aborting scan on ndo_stop\n");
cfg80211_scan_done(priv->scan_request, 1);
cfg80211_scan_done(priv->scan_request, &info);
priv->scan_request = NULL;
priv->scan_aborting = true;
}
......
......@@ -1956,9 +1956,13 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
mwifiex_complete_scan(priv);
if (priv->scan_request) {
struct cfg80211_scan_info info = {
.aborted = false,
};
mwifiex_dbg(adapter, INFO,
"info: notifying scan done\n");
cfg80211_scan_done(priv->scan_request, 0);
cfg80211_scan_done(priv->scan_request, &info);
priv->scan_request = NULL;
} else {
priv->scan_aborting = false;
......@@ -1977,9 +1981,13 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
if (!adapter->active_scan_triggered) {
if (priv->scan_request) {
struct cfg80211_scan_info info = {
.aborted = true,
};
mwifiex_dbg(adapter, INFO,
"info: aborting scan\n");
cfg80211_scan_done(priv->scan_request, 1);
cfg80211_scan_done(priv->scan_request, &info);
priv->scan_request = NULL;
} else {
priv->scan_aborting = false;
......
......@@ -2134,6 +2134,7 @@ static void rndis_get_scan_results(struct work_struct *work)
struct rndis_wlan_private *priv =
container_of(work, struct rndis_wlan_private, scan_work.work);
struct usbnet *usbdev = priv->usbdev;
struct cfg80211_scan_info info = {};
int ret;
netdev_dbg(usbdev->net, "get_scan_results\n");
......@@ -2143,7 +2144,8 @@ static void rndis_get_scan_results(struct work_struct *work)
ret = rndis_check_bssid_list(usbdev, NULL, NULL);
cfg80211_scan_done(priv->scan_request, ret < 0);
info.aborted = ret < 0;
cfg80211_scan_done(priv->scan_request, &info);
priv->scan_request = NULL;
}
......@@ -3574,7 +3576,11 @@ static int rndis_wlan_stop(struct usbnet *usbdev)
flush_workqueue(priv->workqueue);
if (priv->scan_request) {
cfg80211_scan_done(priv->scan_request, true);
struct cfg80211_scan_info info = {
.aborted = true,
};
cfg80211_scan_done(priv->scan_request, &info);
priv->scan_request = NULL;
}
......
......@@ -1256,10 +1256,15 @@ void rtw_cfg80211_indicate_scan_done(struct rtw_wdev_priv *pwdev_priv,
DBG_8723A("%s with scan req\n", __func__);
if (pwdev_priv->scan_request->wiphy !=
pwdev_priv->rtw_wdev->wiphy)
pwdev_priv->rtw_wdev->wiphy) {
DBG_8723A("error wiphy compare\n");
else
cfg80211_scan_done(pwdev_priv->scan_request, aborted);
} else {
struct cfg80211_scan_info info = {
.aborted = aborted,
};
cfg80211_scan_done(pwdev_priv->scan_request, &info);
}
pwdev_priv->scan_request = NULL;
} else {
......
......@@ -454,7 +454,11 @@ static void CfgScanResult(enum scan_event scan_event,
mutex_lock(&priv->scan_req_lock);
if (priv->pstrScanReq) {
cfg80211_scan_done(priv->pstrScanReq, false);
struct cfg80211_scan_info info = {
.aborted = false,
};
cfg80211_scan_done(priv->pstrScanReq, &info);
priv->u32RcvdChCount = 0;
priv->bCfgScanning = false;
priv->pstrScanReq = NULL;
......@@ -464,10 +468,14 @@ static void CfgScanResult(enum scan_event scan_event,
mutex_lock(&priv->scan_req_lock);
if (priv->pstrScanReq) {
struct cfg80211_scan_info info = {
.aborted = false,
};
update_scan_time();
refresh_scan(priv, 1, false);
cfg80211_scan_done(priv->pstrScanReq, false);
cfg80211_scan_done(priv->pstrScanReq, &info);
priv->bCfgScanning = false;
priv->pstrScanReq = NULL;
}
......
......@@ -338,6 +338,8 @@ static int prism2_scan(struct wiphy *wiphy,
struct p80211msg_dot11req_scan msg1;
struct p80211msg_dot11req_scan_results msg2;
struct cfg80211_bss *bss;
struct cfg80211_scan_info info = {};
int result;
int err = 0;
int numbss = 0;
......@@ -440,7 +442,8 @@ static int prism2_scan(struct wiphy *wiphy,
err = prism2_result2err(msg2.resultcode.data);
exit:
cfg80211_scan_done(request, err ? 1 : 0);
info.aborted = !!(err);
cfg80211_scan_done(request, &info);
priv->scan_request = NULL;
return err;
}
......
......@@ -1423,6 +1423,21 @@ struct cfg80211_ssid {
u8 ssid_len;
};
/**
* struct cfg80211_scan_info - information about completed scan
* @scan_start_tsf: scan start time in terms of the TSF of the BSS that the
* wireless device that requested the scan is connected to. If this
* information is not available, this field is left zero.
* @tsf_bssid: the BSSID according to which %scan_start_tsf is set.
* @aborted: set to true if the scan was aborted for any reason,
* userspace will be notified of that
*/
struct cfg80211_scan_info {
u64 scan_start_tsf;
u8 tsf_bssid[ETH_ALEN] __aligned(2);
bool aborted;
};
/**
* struct cfg80211_scan_request - scan request description
*
......@@ -1433,12 +1448,17 @@ struct cfg80211_ssid {
* @scan_width: channel width for scanning
* @ie: optional information element(s) to add into Probe Request or %NULL
* @ie_len: length of ie in octets
* @duration: how long to listen on each channel, in TUs. If
* %duration_mandatory is not set, this is the maximum dwell time and
* the actual dwell time may be shorter.
* @duration_mandatory: if set, the scan duration must be as specified by the
* %duration field.
* @flags: bit field of flags controlling operation
* @rates: bitmap of rates to advertise for each band
* @wiphy: the wiphy this was for
* @scan_start: time (in jiffies) when the scan started
* @wdev: the wireless device to scan for
* @aborted: (internal) scan request was notified as aborted
* @info: (internal) information about completed scan
* @notified: (internal) scan request was notified as done or aborted
* @no_cck: used to send probe requests at non CCK rate in 2GHz band
* @mac_addr: MAC address used with randomisation
......@@ -1454,6 +1474,8 @@ struct cfg80211_scan_request {
enum nl80211_bss_scan_width scan_width;
const u8 *ie;
size_t ie_len;
u16 duration;
bool duration_mandatory;
u32 flags;
u32 rates[NUM_NL80211_BANDS];
......@@ -1467,7 +1489,8 @@ struct cfg80211_scan_request {
/* internal */
struct wiphy *wiphy;
unsigned long scan_start;
bool aborted, notified;
struct cfg80211_scan_info info;
bool notified;
bool no_cck;
/* keep last */
......@@ -1600,12 +1623,19 @@ enum cfg80211_signal_type {
* buffered on the device) and be accurate to about 10ms.
* If the frame isn't buffered, just passing the return value of
* ktime_get_boot_ns() is likely appropriate.
* @parent_tsf: the time at the start of reception of the first octet of the
* timestamp field of the frame. The time is the TSF of the BSS specified
* by %parent_bssid.
* @parent_bssid: the BSS according to which %parent_tsf is set. This is set to
* the BSS that requested the scan in which the beacon/probe was received.
*/
struct cfg80211_inform_bss {
struct ieee80211_channel *chan;
enum nl80211_bss_scan_width scan_width;
s32 signal;
u64 boottime_ns;
u64 parent_tsf;
u8 parent_bssid[ETH_ALEN] __aligned(2);
};
/**
......@@ -4067,10 +4097,10 @@ const char *reg_initiator_name(enum nl80211_reg_initiator initiator);
* cfg80211_scan_done - notify that scan finished
*
* @request: the corresponding scan request
* @aborted: set to true if the scan was aborted for any reason,
* userspace will be notified of that
* @info: information about the completed scan
*/
void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted);
void cfg80211_scan_done(struct cfg80211_scan_request *request,
struct cfg80211_scan_info *info);
/**
* cfg80211_sched_scan_results - notify that new scan results are available
......
......@@ -1848,6 +1848,22 @@ enum nl80211_commands {
* to turn that feature off set an invalid mac address
* (e.g. FF:FF:FF:FF:FF:FF)
*
* @NL80211_ATTR_SCAN_START_TIME_TSF: The time at which the scan was actually
* started (u64). The time is the TSF of the BSS the interface that
* requested the scan is connected to (if available, otherwise this
* attribute must not be included).
* @NL80211_ATTR_SCAN_START_TIME_TSF_BSSID: The BSS according to which
* %NL80211_ATTR_SCAN_START_TIME_TSF is set.
* @NL80211_ATTR_MEASUREMENT_DURATION: measurement duration in TUs (u16). If
* %NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY is not set, this is the
* maximum measurement duration allowed. This attribute is used with
* measurement requests. It can also be used with %NL80211_CMD_TRIGGER_SCAN
* if the scan is used for beacon report radio measurement.
* @NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY: flag attribute that indicates
* that the duration specified with %NL80211_ATTR_MEASUREMENT_DURATION is
* mandatory. If this flag is not set, the duration is the maximum duration
* and the actual measurement duration may be shorter.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
......@@ -2235,6 +2251,11 @@ enum nl80211_attrs {
NL80211_ATTR_MU_MIMO_GROUP_DATA,
NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR,
NL80211_ATTR_SCAN_START_TIME_TSF,
NL80211_ATTR_SCAN_START_TIME_TSF_BSSID,
NL80211_ATTR_MEASUREMENT_DURATION,
NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
......@@ -3496,6 +3517,12 @@ enum nl80211_bss_scan_width {
* was last updated by a received frame. The value is expected to be
* accurate to about 10ms. (u64, nanoseconds)
* @NL80211_BSS_PAD: attribute used for padding for 64-bit alignment
* @NL80211_BSS_PARENT_TSF: the time at the start of reception of the first
* octet of the timestamp field of the last beacon/probe received for
* this BSS. The time is the TSF of the BSS specified by
* @NL80211_BSS_PARENT_BSSID. (u64).
* @NL80211_BSS_PARENT_BSSID: the BSS according to which @NL80211_BSS_PARENT_TSF
* is set.
* @__NL80211_BSS_AFTER_LAST: internal
* @NL80211_BSS_MAX: highest BSS attribute
*/
......@@ -3517,6 +3544,8 @@ enum nl80211_bss {
NL80211_BSS_PRESP_DATA,
NL80211_BSS_LAST_SEEN_BOOTTIME,
NL80211_BSS_PAD,
NL80211_BSS_PARENT_TSF,
NL80211_BSS_PARENT_BSSID,
/* keep last */
__NL80211_BSS_AFTER_LAST,
......@@ -4507,6 +4536,16 @@ enum nl80211_feature_flags {
* %NL80211_ATTR_MU_MIMO_GROUP_DATA attribute,
* or can be configured to follow a station by configuring the
* %NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR attribute.
* @NL80211_EXT_FEATURE_SCAN_START_TIME: This driver includes the actual
* time the scan started in scan results event. The time is the TSF of
* the BSS that the interface that requested the scan is connected to
* (if available).
* @NL80211_EXT_FEATURE_BSS_PARENT_TSF: Per BSS, this driver reports the
* time the last beacon/probe was received. The time is the TSF of the
* BSS that the interface that requested the scan is connected to
* (if available).
* @NL80211_EXT_FEATURE_SET_SCAN_DWELL: This driver supports configuration of
* channel dwell time.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
......@@ -4515,6 +4554,9 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_VHT_IBSS,
NL80211_EXT_FEATURE_RRM,
NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER,
NL80211_EXT_FEATURE_SCAN_START_TIME,
NL80211_EXT_FEATURE_BSS_PARENT_TSF,
NL80211_EXT_FEATURE_SET_SCAN_DWELL,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
......
......@@ -353,8 +353,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
scan_req = rcu_dereference_protected(local->scan_req,
lockdep_is_held(&local->mtx));
if (scan_req != local->int_scan_req)
cfg80211_scan_done(scan_req, aborted);
if (scan_req != local->int_scan_req) {
struct cfg80211_scan_info info = {
.aborted = aborted,
};
cfg80211_scan_done(scan_req, &info);
}
RCU_INIT_POINTER(local->scan_req, NULL);
scan_sdata = rcu_dereference_protected(local->scan_sdata,
......
......@@ -220,7 +220,7 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
if (WARN_ON(!rdev->scan_req->notified))
rdev->scan_req->aborted = true;
rdev->scan_req->info.aborted = true;
___cfg80211_scan_done(rdev, false);
}
}
......@@ -1087,7 +1087,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
cfg80211_update_iface_num(rdev, wdev->iftype, -1);
if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
if (WARN_ON(!rdev->scan_req->notified))
rdev->scan_req->aborted = true;
rdev->scan_req->info.aborted = true;
___cfg80211_scan_done(rdev, false);
}
......
......@@ -141,6 +141,18 @@ struct cfg80211_internal_bss {
unsigned long refcount;
atomic_t hold;
/* time at the start of the reception of the first octet of the
* timestamp field of the last beacon/probe received for this BSS.
* The time is the TSF of the BSS specified by %parent_bssid.
*/
u64 parent_tsf;
/* the BSS according to which %parent_tsf is set. This is set to
* the BSS that the interface that requested the scan was connected to
* when the beacon/probe was received.
*/
u8 parent_bssid[ETH_ALEN] __aligned(2);
/* must be last because of priv member */
struct cfg80211_bss pub;
};
......
......@@ -6223,6 +6223,19 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
}
}
if (info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]) {
if (!wiphy_ext_feature_isset(wiphy,
NL80211_EXT_FEATURE_SET_SCAN_DWELL)) {
err = -EOPNOTSUPP;
goto out_free;
}
request->duration =
nla_get_u16(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION]);
request->duration_mandatory =
nla_get_flag(info->attrs[NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY]);
}
if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
request->flags = nla_get_u32(
info->attrs[NL80211_ATTR_SCAN_FLAGS]);
......@@ -7056,6 +7069,13 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
jiffies_to_msecs(jiffies - intbss->ts)))
goto nla_put_failure;
if (intbss->parent_tsf &&
(nla_put_u64_64bit(msg, NL80211_BSS_PARENT_TSF,
intbss->parent_tsf, NL80211_BSS_PAD) ||
nla_put(msg, NL80211_BSS_PARENT_BSSID, ETH_ALEN,
intbss->parent_bssid)))
goto nla_put_failure;
if (intbss->ts_boottime &&
nla_put_u64_64bit(msg, NL80211_BSS_LAST_SEEN_BOOTTIME,
intbss->ts_boottime, NL80211_BSS_PAD))
......@@ -11829,6 +11849,13 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, req->flags))
goto nla_put_failure;
if (req->info.scan_start_tsf &&
(nla_put_u64_64bit(msg, NL80211_ATTR_SCAN_START_TIME_TSF,
req->info.scan_start_tsf, NL80211_BSS_PAD) ||
nla_put(msg, NL80211_ATTR_SCAN_START_TIME_TSF_BSSID, ETH_ALEN,
req->info.tsf_bssid)))
goto nla_put_failure;
return 0;
nla_put_failure:
return -ENOBUFS;
......