SmartAudio/lichee/linux-4.9/drivers/net/wireless/xr829/wlan/scan.c

1361 lines
38 KiB
C
Executable File

/*
* Scan implementation for XRadio drivers
*
* Copyright (c) 2013
* Xradio Technology Co., Ltd. <www.xradiotech.com>
*
* 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
* published by the Free Software Foundation.
*/
#include <linux/sched.h>
#include "xradio.h"
#include "scan.h"
#include "sta.h"
#include "pm.h"
static void xradio_scan_restart_delayed(struct xradio_vif *priv);
#ifdef CONFIG_XRADIO_TESTMODE
static int xradio_advance_scan_start(struct xradio_common *hw_priv)
{
int tmo = 0;
scan_printk(XRADIO_DBG_TRC, "%s\n", __func__);
tmo += hw_priv->advanceScanElems.duration;
#ifdef CONFIG_PM
xradio_pm_stay_awake(&hw_priv->pm_state, tmo * HZ / 1000);
#endif
/* Invoke Advance Scan Duration Timeout Handler */
queue_delayed_work(hw_priv->workqueue,
&hw_priv->advance_scan_timeout, tmo * HZ / 1000);
return 0;
}
#endif
static void xradio_remove_wps_p2p_ie(struct wsm_template_frame *frame)
{
u8 *ies;
u32 ies_len;
u32 ie_len;
u32 p2p_ie_len = 0;
u32 wps_ie_len = 0;
scan_printk(XRADIO_DBG_TRC, "%s\n", __func__);
ies = &frame->skb->data[sizeof(struct ieee80211_hdr_3addr)];
ies_len = frame->skb->len - sizeof(struct ieee80211_hdr_3addr);
while (ies_len >= 6) {
ie_len = ies[1] + 2;
ies_len -= ie_len;
if ((ies[0] == WLAN_EID_VENDOR_SPECIFIC) &&
(ies[2] == 0x00 && ies[3] == 0x50 &&
ies[4] == 0xf2 && ies[5] == 0x04)) {
wps_ie_len = ie_len;
memmove(ies, ies + ie_len, ies_len);
} else if ((ies[0] == WLAN_EID_VENDOR_SPECIFIC) &&
(ies[2] == 0x50 && ies[3] == 0x6f &&
ies[4] == 0x9a && ies[5] == 0x09)) {
p2p_ie_len = ie_len;
memmove(ies, ies + ie_len, ies_len);
} else {
ies += ie_len;
}
}
if (p2p_ie_len || wps_ie_len) {
skb_trim(frame->skb, frame->skb->len - (p2p_ie_len + wps_ie_len));
}
}
#ifdef CONFIG_XRADIO_TESTMODE
static int xradio_disable_filtering(struct xradio_vif *priv)
{
int ret = 0;
bool bssid_filtering = 0;
struct wsm_rx_filter rx_filter;
struct wsm_beacon_filter_control bf_control;
struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv);
scan_printk(XRADIO_DBG_TRC, "%s\n", __func__);
/* RX Filter Disable */
rx_filter.promiscuous = 0;
rx_filter.bssid = 0;
rx_filter.fcs = 0;
ret = wsm_set_rx_filter(hw_priv, &rx_filter, priv->if_id);
/* Beacon Filter Disable */
bf_control.enabled = 0;
bf_control.bcn_count = 1;
if (!ret)
ret = wsm_beacon_filter_control(hw_priv, &bf_control, priv->if_id);
/* BSSID Filter Disable */
if (!ret)
ret = wsm_set_bssid_filtering(hw_priv, bssid_filtering, priv->if_id);
return ret;
}
#endif
static int xradio_scan_start(struct xradio_vif *priv, struct wsm_scan *scan)
{
int ret, i;
#ifdef FPGA_SETUP
int tmo = SCAN_DEFAULT_TIMEOUT;
#else
int tmo = SCAN_DEFAULT_TIMEOUT;
#endif
struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv);
scan_printk(XRADIO_DBG_TRC, "%s\n", __func__);
for (i = 0; i < scan->numOfChannels; ++i)
tmo += scan->ch[i].maxChannelTime + 10;
atomic_set(&hw_priv->scan.in_progress, 1);
atomic_set(&hw_priv->recent_scan, 1);
#ifdef CONFIG_PM
xradio_pm_stay_awake(&hw_priv->pm_state, tmo * HZ / 1000);
#endif
schedule_delayed_work(&hw_priv->scan.timeout, tmo * HZ / 1000);
#ifdef SCAN_FAILED_WORKAROUND_OF_FW_EXCEPTION
hw_priv->scan.scan_failed_timestamp = jiffies;
#endif
#ifdef P2P_MULTIVIF
ret = wsm_scan(hw_priv, scan, priv->if_id ? 1 : 0);
#else
ret = wsm_scan(hw_priv, scan, priv->if_id);
#endif
if (unlikely(ret)) {
scan_printk(XRADIO_DBG_WARN, "%s,wsm_scan failed!\n", __func__);
atomic_set(&hw_priv->scan.in_progress, 0);
cancel_delayed_work(&hw_priv->scan.timeout);
xradio_scan_restart_delayed(priv);
}
return ret;
}
#ifdef ROAM_OFFLOAD
static int xradio_sched_scan_start(struct xradio_vif *priv,
struct wsm_scan *scan)
{
int ret;
struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv);
scan_printk(XRADIO_DBG_TRC, "%s\n", __func__);
ret = wsm_scan(hw_priv, scan, priv->if_id);
if (unlikely(ret)) {
atomic_set(&hw_priv->scan.in_progress, 0);
scan_printk(XRADIO_DBG_WARN, "%s,wsm_scan failed!\n", __func__);
}
return ret;
}
#endif /*ROAM_OFFLOAD*/
int xradio_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_scan_request *req)
{
struct xradio_common *hw_priv = hw->priv;
struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif);
struct wsm_template_frame frame = {
.frame_type = WSM_FRAME_TYPE_PROBE_REQUEST,
};
int i;
#ifdef CONFIG_XRADIO_TESTMODE
int ret = 0;
u16 advance_scan_req_channel;
#endif
scan_printk(XRADIO_DBG_TRC, "%s\n", __func__);
/* Scan when P2P_GO corrupt firmware MiniAP mode */
if (priv->join_status == XRADIO_JOIN_STATUS_AP) {
scan_printk(XRADIO_DBG_WARN, "%s, can't scan in AP mode!\n",
__func__);
return -EOPNOTSUPP;
}
#ifdef HW_RESTART
if (hw_priv->hw_restart) {
scan_printk(XRADIO_DBG_NIY, "Ignoring scan in hw reset!\n");
return -EBUSY;
}
#endif
if (hw_priv->bh_error) {
scan_printk(XRADIO_DBG_WARN, "Ignoring scan bh error occur!\n");
return -EBUSY;
}
if (!atomic_read(&priv->enabled)) {
scan_printk(XRADIO_DBG_WARN, "Ignoring scan vif is not enable!\n");
return -EBUSY;
}
if (work_pending(&priv->offchannel_work) ||
(hw_priv->roc_if_id != -1)) {
scan_printk(XRADIO_DBG_WARN, "Offchannel work pending, "
"ignoring scan work %d\n", hw_priv->roc_if_id);
return -EBUSY;
}
if (req->n_ssids == 1 && !req->ssids[0].ssid_len)
req->n_ssids = 0;
scan_printk(XRADIO_DBG_NIY, "vif%d Scan request(%s-%dchs) for %d SSIDs.\n",
priv->if_id, (req->channels[0]->band == NL80211_BAND_2GHZ) ? "2.4G" : "5G",
req->n_channels, req->n_ssids);
if (xradio_is_bt_block(hw_priv)) {
scan_printk(XRADIO_DBG_WARN, "%s:BT is busy, Delay scan!\n", __func__);
return -EBUSY;
}
/*delay multiple ssids scan of vif0 for 3s when connnetting to a node*/
if (hw_priv->scan_delay_status[0] == XRADIO_SCAN_DELAY &&
req->n_ssids == 0 && priv->if_id == 0) {
unsigned long timedelay = hw_priv->scan_delay_time[0] + SCAN_MAX_DELAY;
if (time_before(jiffies, timedelay)) {
scan_printk(XRADIO_DBG_NIY, "vif0 connectting, scan delay %ldms\n",
(long)(timedelay - jiffies)*1000/HZ);
return -EBUSY;
}
hw_priv->scan_delay_status[0] = XRADIO_SCAN_ALLOW;
}
if (req->n_ssids > hw->wiphy->max_scan_ssids) {
scan_printk(XRADIO_DBG_ERROR, "%s: ssids is too much(%d)\n",
__func__, req->n_ssids);
return -EINVAL;
}
frame.skb = mac80211_probereq_get(hw, vif, NULL, 0, req->ie, req->ie_len);
if (!frame.skb) {
scan_printk(XRADIO_DBG_ERROR, "%s: mac80211_probereq_get failed!\n",
__func__);
return -ENOMEM;
}
#ifdef ROAM_OFFLOAD
if (priv->join_status != XRADIO_JOIN_STATUS_STA) {
if (req->channels[0]->band == NL80211_BAND_2GHZ)
hw_priv->num_scanchannels = 0;
else
hw_priv->num_scanchannels = hw_priv->num_2g_channels;
for (i = 0; i < req->n_channels; i++) {
hw_priv->scan_channels[hw_priv->num_scanchannels + i].number = \
req->channels[i]->hw_value;
if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN) {
hw_priv->scan_channels[hw_priv->num_scanchannels \
+ i].minChannelTime = 50;
hw_priv->scan_channels[hw_priv->num_scanchannels \
+ i].maxChannelTime = 110;
} else {
hw_priv->scan_channels[hw_priv->num_scanchannels \
+ i].minChannelTime = 10;
hw_priv->scan_channels[hw_priv->num_scanchannels \
+ i].maxChannelTime = 40;
hw_priv->scan_channels[hw_priv->num_scanchannels \
+ i].number |= \
XRADIO_SCAN_TYPE_ACTIVE;
}
hw_priv->scan_channels[hw_priv->num_scanchannels \
+ i].txPowerLevel = \
req->channels[i]->max_power;
if (req->channels[0]->band == NL80211_BAND_5GHZ)
hw_priv->scan_channels[hw_priv->num_scanchannels \
+ i].number |= XRADIO_SCAN_BAND_5G;
}
if (req->channels[0]->band == NL80211_BAND_2GHZ)
hw_priv->num_2g_channels = req->n_channels;
else
hw_priv->num_5g_channels = req->n_channels;
}
hw_priv->num_scanchannels = hw_priv->num_2g_channels + \
hw_priv->num_5g_channels;
#endif /*ROAM_OFFLOAD*/
/* will be unlocked in xradio_scan_work() */
down(&hw_priv->scan.lock);
down(&hw_priv->conf_lock);
#ifdef CONFIG_XRADIO_TESTMODE
/* Active Scan - Serving Channel Request Handling */
advance_scan_req_channel = req->channels[0]->hw_value;
if (hw_priv->enable_advance_scan &&
(hw_priv->advanceScanElems.scanMode ==
XRADIO_SCAN_MEASUREMENT_ACTIVE) &&
(priv->join_status == XRADIO_JOIN_STATUS_STA) &&
(hw_priv->channel->hw_value == advance_scan_req_channel)) {
SYS_BUG(hw_priv->scan.req);
/* wsm_lock_tx(hw_priv); */
wsm_vif_lock_tx(priv);
hw_priv->scan.if_id = priv->if_id;
/* Disable Power Save */
if (priv->powersave_mode.pmMode & WSM_PSM_PS) {
struct wsm_set_pm pm = priv->powersave_mode;
pm.pmMode = WSM_PSM_ACTIVE;
wsm_set_pm(hw_priv, &pm, priv->if_id);
}
/* Disable Rx Beacon and Bssid filter */
ret = xradio_disable_filtering(priv);
if (ret)
scan_printk(XRADIO_DBG_ERROR,
"%s: Disable BSSID or Beacon filtering "
"failed: %d.\n", __func__, ret);
wsm_unlock_tx(hw_priv);
up(&hw_priv->conf_lock);
/* Transmit Probe Request with Broadcast SSID */
xradio_tx(hw, frame.skb);
/* Start Advance Scan Timer */
xradio_advance_scan_start(hw_priv);
} else {
#endif /* CONFIG_XRADIO_TESTMODE */
if (frame.skb) {
int ret = 0;
if (priv->if_id == 0)
xradio_remove_wps_p2p_ie(&frame);
#ifdef P2P_MULTIVIF
ret = wsm_set_template_frame(hw_priv, &frame, priv->if_id ? 1 : 0);
#else
ret = wsm_set_template_frame(hw_priv, &frame, priv->if_id);
#endif
if (ret) {
up(&hw_priv->conf_lock);
up(&hw_priv->scan.lock);
dev_kfree_skb(frame.skb);
scan_printk(XRADIO_DBG_ERROR,
"%s: wsm_set_template_frame failed: %d.\n",
__func__, ret);
return ret;
}
}
wsm_vif_lock_tx(priv);
SYS_BUG(hw_priv->scan.req);
hw_priv->scan.req = req;
hw_priv->scan.n_ssids = 0;
hw_priv->scan.status = 0;
hw_priv->scan.begin = &req->channels[0];
hw_priv->scan.curr = hw_priv->scan.begin;
hw_priv->scan.end = &req->channels[req->n_channels];
hw_priv->scan.output_power = hw_priv->output_power;
hw_priv->scan.if_id = priv->if_id;
/* TODO:COMBO: Populate BIT4 in scanflags to decide on which MAC
* address the SCAN request will be sent */
for (i = 0; i < req->n_ssids; ++i) {
struct wsm_ssid *dst = &hw_priv->scan.ssids[hw_priv->scan.n_ssids];
SYS_BUG(req->ssids[i].ssid_len > sizeof(dst->ssid));
memcpy(&dst->ssid[0], req->ssids[i].ssid, sizeof(dst->ssid));
dst->length = req->ssids[i].ssid_len;
++hw_priv->scan.n_ssids;
}
up(&hw_priv->conf_lock);
if (frame.skb)
dev_kfree_skb(frame.skb);
queue_work(hw_priv->workqueue, &hw_priv->scan.work);
#ifdef CONFIG_XRADIO_TESTMODE
}
#endif
return 0;
}
#ifdef ROAM_OFFLOAD
int xradio_hw_sched_scan_start(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_sched_scan_request *req,
struct ieee80211_sched_scan_ies *ies)
{
struct xradio_common *hw_priv = hw->priv;
struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif);
struct wsm_template_frame frame = {
.frame_type = WSM_FRAME_TYPE_PROBE_REQUEST,
};
int i;
scan_printk(XRADIO_DBG_TRC, "%s\n", __func__);
scan_printk(XRADIO_DBG_WARN, "Scheduled scan request-->.\n");
if (!priv->vif)
return -EINVAL;
/* Scan when P2P_GO corrupt firmware MiniAP mode */
if (priv->join_status == XRADIO_JOIN_STATUS_AP) {
scan_printk(XRADIO_DBG_WARN, "%s, can't scan in AP mode!\n", __func__);
return -EOPNOTSUPP;
}
#ifdef HW_RESTART
if (hw_priv->hw_restart) {
scan_printk(XRADIO_DBG_NIY, "Ignoring scan in hw reset!\n");
return -EBUSY;
}
#endif
if (hw_priv->bh_error) {
scan_printk(XRADIO_DBG_WARN, "Ignoring scan bh error occur!\n");
return -EBUSY;
}
if (!atomic_read(&priv->enabled)) {
scan_printk(XRADIO_DBG_WARN, "Ignoring scan vif is not enable!\n");
return -EBUSY;
}
scan_printk(XRADIO_DBG_WARN,
"Scheduled scan: n_ssids %d, ssid[0].len = %d\n",
req->n_ssids, req->ssids[0].ssid_len);
if (req->n_ssids == 1 && !req->ssids[0].ssid_len)
req->n_ssids = 0;
scan_printk(XRADIO_DBG_NIY, "[SCAN] Scan request for %d SSIDs.\n",
req->n_ssids);
if (req->n_ssids > hw->wiphy->max_scan_ssids) {
scan_printk(XRADIO_DBG_ERROR, "%s: ssids is too much(%d)\n",
__func__, req->n_ssids);
return -EINVAL;
}
frame.skb = mac80211_probereq_get(hw, priv->vif, NULL, 0,
ies->ie[0], ies->len[0]);
if (!frame.skb) {
scan_printk(XRADIO_DBG_ERROR, "%s: mac80211_probereq_get failed!\n",
__func__);
return -ENOMEM;
}
/* will be unlocked in xradio_scan_work() */
down(&hw_priv->scan.lock);
down(&hw_priv->conf_lock);
if (frame.skb) {
int ret;
if (priv->if_id == 0)
xradio_remove_wps_p2p_ie(&frame);
ret = wsm_set_template_frame(hw_priv, &frame, priv->if_id);
if (0 == ret) {
/* Host want to be the probe responder. */
ret = wsm_set_probe_responder(priv, true);
}
if (ret) {
up(&hw_priv->conf_lock);
up(&hw_priv->scan.lock);
dev_kfree_skb(frame.skb);
scan_printk(XRADIO_DBG_ERROR,
"%s: wsm_set_probe_responder failed: %d.\n",
__func__, ret);
return ret;
}
}
wsm_lock_tx(hw_priv);
SYS_BUG(hw_priv->scan.req);
hw_priv->scan.sched_req = req;
hw_priv->scan.n_ssids = 0;
hw_priv->scan.status = 0;
hw_priv->scan.begin = &req->channels[0];
hw_priv->scan.curr = hw_priv->scan.begin;
hw_priv->scan.end = &req->channels[req->n_channels];
hw_priv->scan.output_power = hw_priv->output_power;
for (i = 0; i < req->n_ssids; ++i) {
u8 j;
struct wsm_ssid *dst = &hw_priv->scan.ssids[hw_priv->scan.n_ssids];
SYS_BUG(req->ssids[i].ssid_len > sizeof(dst->ssid));
memcpy(&dst->ssid[0], req->ssids[i].ssid, sizeof(dst->ssid));
dst->length = req->ssids[i].ssid_len;
++hw_priv->scan.n_ssids;
scan_printk(XRADIO_DBG_NIY, "SSID %d\n", i);
for (j = 0; j < req->ssids[i].ssid_len; j++)
scan_printk(XRADIO_DBG_NIY, "0x%x\n", req->ssids[i].ssid[j]);
}
up(&hw_priv->conf_lock);
if (frame.skb)
dev_kfree_skb(frame.skb);
queue_work(hw_priv->workqueue, &hw_priv->scan.swork);
scan_printk(XRADIO_DBG_NIY, "<-- Scheduled scan request.\n");
return 0;
}
#endif /*ROAM_OFFLOAD*/
void xradio_scan_work(struct work_struct *work)
{
struct xradio_common *hw_priv = container_of(work,
struct xradio_common,
scan.work);
struct xradio_vif *priv;
struct ieee80211_channel **it;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0))
struct cfg80211_scan_info info;
#endif
struct wsm_scan scan = {
#ifndef SUPPORT_HT40
.scanType = WSM_SCAN_TYPE_FOREGROUND,
#endif
.scanFlags = 0, /* TODO:COMBO */
/*.scanFlags = WSM_SCAN_FLAG_SPLIT_METHOD, */
};
bool first_run;
int i;
const u32 ProbeRequestTime = 2;
const u32 ChannelRemainTime = 15;
u32 maxChannelTime;
#ifdef CONFIG_XRADIO_TESTMODE
int ret = 0;
u16 advance_scan_req_channel = hw_priv->scan.begin[0]->hw_value;
#endif
scan_printk(XRADIO_DBG_TRC, "%s\n", __func__);
priv = __xrwl_hwpriv_to_vifpriv(hw_priv, hw_priv->scan.if_id);
/*TODO: COMBO: introduce locking so vif is not removed in meanwhile */
if (!priv) {
scan_printk(XRADIO_DBG_WARN, "interface removed, "
"ignoring scan work\n");
return;
}
#ifdef SUPPORT_HT40
SET_SCAN_TYPE(&scan.scanFlags, WSM_SCAN_TYPE_FOREGROUND);
#endif
#ifdef SUPPORT_HT40
if (priv->if_id)
SET_SCAN_FLAG(&scan.scanFlags, WSM_FLAG_MAC_INSTANCE_1);
else
CLR_SCAN_FLAG(&scan.scanFlags, WSM_FLAG_MAC_INSTANCE_1);
#else
if (priv->if_id)
scan.scanFlags |= WSM_FLAG_MAC_INSTANCE_1;
else
scan.scanFlags &= ~WSM_FLAG_MAC_INSTANCE_1;
#endif
/* No need to set WSM_SCAN_FLAG_FORCE_BACKGROUND in BSS_LOSS work.*/
/*
xradio_for_each_vif(hw_priv, vif, i) {
if (!vif)
continue;
if (vif->bss_loss_status > XRADIO_BSS_LOSS_NONE)
scan.scanFlags |= WSM_SCAN_FLAG_FORCE_BACKGROUND;
} */
first_run = (hw_priv->scan.begin == hw_priv->scan.curr &&
hw_priv->scan.begin != hw_priv->scan.end);
if (first_run) {
/* Firmware gets crazy if scan request is sent
* when STA is joined but not yet associated.
* Force unjoin in this case. */
if (cancel_delayed_work_sync(&priv->join_timeout) > 0)
xradio_join_timeout(&priv->join_timeout.work);
}
down(&hw_priv->conf_lock);
if (first_run) {
#ifdef CONFIG_XRADIO_TESTMODE
/* Passive Scan - Serving Channel Request Handling */
if (hw_priv->enable_advance_scan &&
(hw_priv->advanceScanElems.scanMode ==
XRADIO_SCAN_MEASUREMENT_PASSIVE) &&
(priv->join_status == XRADIO_JOIN_STATUS_STA) &&
(hw_priv->channel->hw_value == advance_scan_req_channel)) {
/* If Advance Scan Request is for Serving Channel Device
* should be Active and Filtering Should be Disable */
if (priv->powersave_mode.pmMode & WSM_PSM_PS) {
struct wsm_set_pm pm = priv->powersave_mode;
pm.pmMode = WSM_PSM_ACTIVE;
wsm_set_pm(hw_priv, &pm, priv->if_id);
}
/* Disable Rx Beacon and Bssid filter */
ret = xradio_disable_filtering(priv);
if (ret)
scan_printk(XRADIO_DBG_ERROR, "%s: Disable BSSID or Beacon"
"filtering failed: %d.\n", __func__, ret);
} else if (hw_priv->enable_advance_scan &&
(hw_priv->advanceScanElems.scanMode ==
XRADIO_SCAN_MEASUREMENT_PASSIVE) &&
(priv->join_status == XRADIO_JOIN_STATUS_STA)) {
if (priv->join_status == XRADIO_JOIN_STATUS_STA &&
!(priv->powersave_mode.pmMode & WSM_PSM_PS)) {
struct wsm_set_pm pm = priv->powersave_mode;
pm.pmMode = WSM_PSM_PS;
xradio_set_pm(priv, &pm);
}
} else {
#endif
#if 0
if (priv->join_status == XRADIO_JOIN_STATUS_STA &&
!(priv->powersave_mode.pmMode & WSM_PSM_PS)) {
struct wsm_set_pm pm = priv->powersave_mode;
pm.pmMode = WSM_PSM_PS;
xradio_set_pm(priv, &pm);
} else
#endif
if (priv->join_status == XRADIO_JOIN_STATUS_MONITOR) {
/* FW bug: driver has to restart p2p-dev mode
* after scan */
xradio_disable_listening(priv);
}
#ifdef CONFIG_XRADIO_TESTMODE
}
#endif
}
if (!hw_priv->scan.req || (hw_priv->scan.curr == hw_priv->scan.end)) {
#ifdef CONFIG_XRADIO_TESTMODE
if (hw_priv->enable_advance_scan &&
(hw_priv->advanceScanElems.scanMode ==
XRADIO_SCAN_MEASUREMENT_PASSIVE) &&
(priv->join_status == XRADIO_JOIN_STATUS_STA) &&
(hw_priv->channel->hw_value == advance_scan_req_channel)) {
/* WSM Lock should be held here for WSM APIs */
wsm_vif_lock_tx(priv);
/* wsm_lock_tx(priv); */
/* Once Duration is Over, enable filtering
* and Revert Back Power Save */
if (priv->powersave_mode.pmMode & WSM_PSM_PS)
wsm_set_pm(hw_priv, &priv->powersave_mode, priv->if_id);
xradio_update_filtering(priv);
} else if (!hw_priv->enable_advance_scan) {
#endif
if (hw_priv->scan.output_power != hw_priv->output_power) {
/* TODO:COMBO: Change when mac80211 implementation
* is available for output power also */
#ifdef P2P_MULTIVIF
WARN_ON(wsm_set_output_power(hw_priv,
hw_priv->output_power * 10,
priv->if_id ? 1 : 0));
#else
WARN_ON(wsm_set_output_power(hw_priv,
hw_priv->output_power * 10,
priv->if_id));
#endif
}
#ifdef CONFIG_XRADIO_TESTMODE
}
#endif
#if 0
if (priv->join_status == XRADIO_JOIN_STATUS_STA &&
!(priv->powersave_mode.pmMode & WSM_PSM_PS))
xradio_set_pm(priv, &priv->powersave_mode);
#endif
if (hw_priv->scan.status < 0)
scan_printk(XRADIO_DBG_ERROR, "Scan failed (%d).\n",
hw_priv->scan.status);
else if (hw_priv->scan.req)
scan_printk(XRADIO_DBG_NIY, "Scan completed.\n");
else
scan_printk(XRADIO_DBG_NIY, "Scan canceled.\n");
hw_priv->scan.req = NULL;
xradio_scan_restart_delayed(priv);
#ifdef CONFIG_XRADIO_TESTMODE
hw_priv->enable_advance_scan = false;
#endif /* CONFIG_XRADIO_TESTMODE */
wsm_unlock_tx(hw_priv);
up(&hw_priv->conf_lock);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0))
memset(&info, 0, sizeof(info));
info.aborted = hw_priv->scan.status ? 1 : 0;
mac80211_scan_completed(hw_priv->hw, &info);
#else
mac80211_scan_completed(hw_priv->hw, hw_priv->scan.status ? 1 : 0);
#endif
up(&hw_priv->scan.lock);
#ifdef SCAN_FAILED_WORKAROUND_OF_FW_EXCEPTION
/*Timeout waiting for scan complete notification all the time,
* then driver restarts.*/
if (hw_priv->scan.scan_failed_cnt >= 5) {
scan_printk(XRADIO_DBG_ERROR, "%s:Too many scan timeout=%d",
__func__, hw_priv->scan.scan_failed_cnt);
hw_priv->bh_error = 1 ;
hw_priv->scan.scan_failed_cnt = 0;
}
#endif
return;
} else {
struct ieee80211_channel *first = *hw_priv->scan.curr;
for (it = hw_priv->scan.curr + 1, i = 1;
it != hw_priv->scan.end && i < WSM_SCAN_MAX_NUM_OF_CHANNELS;
++it, ++i) {
if ((*it)->band != first->band)
break;
if (((*it)->flags ^ first->flags) & IEEE80211_CHAN_PASSIVE_SCAN)
break;
if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
(*it)->max_power != first->max_power)
break;
}
scan.band = first->band;
#ifdef SUPPORT_HT40
if (hw_priv->scan.req->no_cck)
scan.TransmitRateEntry =
((RATE_MODEM_LEGACY << MODEMTYPE_SHIFT)
| (RATE_BANDWIDTH_20M << BANDWIDTH_SHIFT)
| (WSM_TRANSMIT_RATE_6 << 4));
else
scan.TransmitRateEntry =
((RATE_MODEM_LEGACY << MODEMTYPE_SHIFT)
| (RATE_BANDWIDTH_20M << BANDWIDTH_SHIFT)
| (WSM_TRANSMIT_RATE_1 << 4));
#else
if (hw_priv->scan.req->no_cck)
scan.maxTransmitRate = WSM_TRANSMIT_RATE_6;
else
scan.maxTransmitRate = WSM_TRANSMIT_RATE_1;
#endif
#ifdef CONFIG_XRADIO_TESTMODE
if (hw_priv->enable_advance_scan) {
if (hw_priv->advanceScanElems.scanMode ==
XRADIO_SCAN_MEASUREMENT_PASSIVE)
scan.numOfProbeRequests = 0;
else
scan.numOfProbeRequests = 1;
} else {
#endif
/* TODO: Is it optimal? */
scan.numOfProbeRequests =
(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) ? 0 : 4;
#ifdef CONFIG_XRADIO_TESTMODE
}
#endif /* CONFIG_XRADIO_TESTMODE */
scan.numOfSSIDs = hw_priv->scan.n_ssids;
scan.ssids = &hw_priv->scan.ssids[0];
scan.numOfChannels = it - hw_priv->scan.curr;
/* TODO: Is it optimal? */
scan.probeDelay = 200;
scan_printk(XRADIO_DBG_NIY, "Scan split ch(%d).\n", scan.numOfChannels);
/* It is not stated in WSM specification, however
* FW team says that driver may not use FG scan
* when joined. */
if (priv->join_status == XRADIO_JOIN_STATUS_STA) {
#ifdef SUPPORT_HT40
SET_SCAN_TYPE(&scan.scanFlags, WSM_SCAN_TYPE_BACKGROUND);
SET_SCAN_FLAG(&scan.scanFlags, WSM_SCAN_FLAG_FORCE_BACKGROUND);
#else
scan.scanType = WSM_SCAN_TYPE_BACKGROUND;
scan.scanFlags = WSM_SCAN_FLAG_FORCE_BACKGROUND;
#endif
}
scan.ch = xr_kzalloc(sizeof(struct wsm_scan_ch[it - hw_priv->scan.curr]), false);
if (!scan.ch) {
hw_priv->scan.status = -ENOMEM;
scan_printk(XRADIO_DBG_ERROR, "xr_kzalloc wsm_scan_ch failed.\n");
goto fail;
}
maxChannelTime = (scan.numOfSSIDs * scan.numOfProbeRequests *
ProbeRequestTime) + ChannelRemainTime;
maxChannelTime = (maxChannelTime < 100) ? 100 : maxChannelTime;
for (i = 0; i < scan.numOfChannels; ++i) {
scan.ch[i].number = hw_priv->scan.curr[i]->hw_value;
#ifdef CONFIG_XRADIO_TESTMODE
if (hw_priv->enable_advance_scan) {
scan.ch[i].minChannelTime = hw_priv->advanceScanElems.duration;
scan.ch[i].maxChannelTime = hw_priv->advanceScanElems.duration;
} else {
#endif
if (hw_priv->scan.curr[i]->flags &
IEEE80211_CHAN_PASSIVE_SCAN) {
scan.ch[i].minChannelTime = 50;
scan.ch[i].maxChannelTime = 110;
} else {
scan.ch[i].minChannelTime = 50;
scan.ch[i].maxChannelTime = maxChannelTime;
}
#ifdef CONFIG_XRADIO_TESTMODE
}
#endif
}
#ifdef CONFIG_XRADIO_TESTMODE
if (!hw_priv->enable_advance_scan) {
#endif
if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) &&
hw_priv->scan.output_power != first->max_power) {
hw_priv->scan.output_power = first->max_power;
/* TODO:COMBO: Change after mac80211 implementation
* complete */
#ifdef P2P_MULTIVIF
WARN_ON(wsm_set_output_power(hw_priv,
hw_priv->scan.output_power * 10,
priv->if_id ? 1 : 0));
#else
WARN_ON(wsm_set_output_power(hw_priv,
hw_priv->scan.output_power * 10,
priv->if_id));
#endif
}
#ifdef CONFIG_XRADIO_TESTMODE
}
#endif
#ifdef CONFIG_XRADIO_TESTMODE
if (hw_priv->enable_advance_scan &&
(hw_priv->advanceScanElems.scanMode ==
XRADIO_SCAN_MEASUREMENT_PASSIVE) &&
(priv->join_status == XRADIO_JOIN_STATUS_STA) &&
(hw_priv->channel->hw_value == advance_scan_req_channel)) {
/* Start Advance Scan Timer */
hw_priv->scan.status = xradio_advance_scan_start(hw_priv);
wsm_unlock_tx(hw_priv);
} else
#endif
down(&hw_priv->scan.status_lock);
hw_priv->scan.status = xradio_scan_start(priv, &scan);
kfree(scan.ch);
if (WARN_ON(hw_priv->scan.status)) {
scan_printk(XRADIO_DBG_ERROR, "scan failed, status=%d.\n",
hw_priv->scan.status);
up(&hw_priv->scan.status_lock);
goto fail;
}
up(&hw_priv->scan.status_lock);
hw_priv->scan.curr = it;
}
up(&hw_priv->conf_lock);
return;
fail:
hw_priv->scan.curr = hw_priv->scan.end;
up(&hw_priv->conf_lock);
if (queue_work(hw_priv->workqueue, &hw_priv->scan.work) <= 0)
scan_printk(XRADIO_DBG_ERROR, "%s queue scan work failed\n", __func__);
return;
}
#ifdef ROAM_OFFLOAD
void xradio_sched_scan_work(struct work_struct *work)
{
struct xradio_common *hw_priv = container_of(work, struct xradio_common,
scan.swork);
struct wsm_scan scan;
struct wsm_ssid scan_ssid;
int i;
struct xradio_vif *priv = NULL;
scan_printk(XRADIO_DBG_TRC, "%s\n", __func__);
priv = xrwl_hwpriv_to_vifpriv(hw_priv, hw_priv->scan.if_id);
if (unlikely(!priv)) {
WARN_ON(1);
return;
}
spin_unlock(&priv->vif_lock);
/* Firmware gets crazy if scan request is sent
* when STA is joined but not yet associated.
* Force unjoin in this case. */
if (cancel_delayed_work_sync(&priv->join_timeout) > 0) {
xradio_join_timeout(&priv->join_timeout.work);
}
down(&hw_priv->conf_lock);
hw_priv->auto_scanning = 1;
scan.band = 0;
#ifdef SUPPORT_HT40
if (priv->join_status == XRADIO_JOIN_STATUS_STA) /* auto background */
SET_SCAN_TYPE(&scan.scanFlags, WSM_SCAN_TYPE_AUTOBACKGROUND);
else /* auto foreground */
SET_SCAN_TYPE(&scan.scanFlags, WSM_SCAN_TYPE_AUTOFOREGROUND);
/* bit 0 set => forced background scan */
CLR_SCAN_FLAG(&scan.scanFlags, SCANFLAG_MASK);
SET_SCAN_FLAG(&scan.scanFlags, WSM_SCAN_FLAG_FORCE_BACKGROUND);
#else
if (priv->join_status == XRADIO_JOIN_STATUS_STA)
scan.scanType = 3; /* auto background */
else
scan.scanType = 2; /* auto foreground */
scan.scanFlags = 0x01; /* bit 0 set => forced background scan */
#endif
#ifdef SUPPORT_HT40
scan.TransmitRateEntry = ((RATE_MODEM_LEGACY << MODEMTYPE_SHIFT)
| (RATE_BANDWIDTH_20M << BANDWIDTH_SHIFT)
| (AG_RATE_INDEX << 4));
#else
scan.maxTransmitRate = WSM_TRANSMIT_RATE_6;
#endif
scan.autoScanInterval = (0xba << 24)|(30 * 1024); /* 30 seconds, -70 rssi */
scan.numOfProbeRequests = 1;
/*scan.numOfChannels = 11;*/
scan.numOfChannels = hw_priv->num_scanchannels;
scan.numOfSSIDs = 1;
scan.probeDelay = 100;
scan_ssid.length = priv->ssid_length;
memcpy(scan_ssid.ssid, priv->ssid, priv->ssid_length);
scan.ssids = &scan_ssid;
scan.ch = xr_kzalloc(sizeof(struct wsm_scan_ch[scan.numOfChannels]), false);
if (!scan.ch) {
scan_printk(XRADIO_DBG_ERROR, "xr_kzalloc wsm_scan_ch failed.\n");
hw_priv->scan.status = -ENOMEM;
goto fail;
}
for (i = 0; i < scan.numOfChannels; i++) {
scan.ch[i].number = hw_priv->scan_channels[i].number;
scan.ch[i].minChannelTime = hw_priv->scan_channels[i].minChannelTime;
scan.ch[i].maxChannelTime = hw_priv->scan_channels[i].maxChannelTime;
scan.ch[i].txPowerLevel = hw_priv->scan_channels[i].txPowerLevel;
}
#if 0
for (i = 1; i <= scan.numOfChannels; i++) {
scan.ch[i-1].number = i;
scan.ch[i-1].minChannelTime = 10;
scan.ch[i-1].maxChannelTime = 40;
}
#endif
hw_priv->scan.status = xradio_sched_scan_start(priv, &scan);
kfree(scan.ch);
if (hw_priv->scan.status) {
scan_printk(XRADIO_DBG_ERROR, "scan failed, status=%d.\n",
hw_priv->scan.status);
goto fail;
}
up(&hw_priv->conf_lock);
return;
fail:
up(&hw_priv->conf_lock);
queue_work(hw_priv->workqueue, &hw_priv->scan.swork);
return;
}
void xradio_hw_sched_scan_stop(struct xradio_common *hw_priv)
{
struct xradio_vif *priv = NULL;
scan_printk(XRADIO_DBG_TRC, "%s\n", __func__);
priv = xrwl_hwpriv_to_vifpriv(hw_priv, hw_priv->scan.if_id);
if (unlikely(!priv))
return;
spin_unlock(&priv->vif_lock);
wsm_stop_scan(hw_priv, priv->if_id);
return;
}
#endif /*ROAM_OFFLOAD*/
static void xradio_scan_restart_delayed(struct xradio_vif *priv)
{
struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv);
struct xradio_vif *tmp_vif = NULL;
int i = 0;
scan_printk(XRADIO_DBG_TRC, "%s\n", __func__);
if (priv->delayed_link_loss) {
int tmo = hw_priv->scan.direct_probe ? 0 : priv->cqm_beacon_loss_count;
priv->delayed_link_loss = 0;
/* Restart beacon loss timer and requeue
BSS loss work. */
scan_printk(XRADIO_DBG_WARN, "[CQM] Requeue BSS loss in %d "
"beacons.\n", tmo);
cancel_delayed_work_sync(&priv->bss_loss_work);
queue_delayed_work(hw_priv->workqueue, &priv->bss_loss_work,
tmo * HZ / 10);
}
/* FW bug: driver has to restart p2p-dev mode after scan. */
if (priv->join_status == XRADIO_JOIN_STATUS_MONITOR) {
/*xradio_enable_listening(priv);*/
WARN_ON(1);
xradio_update_filtering(priv);
scan_printk(XRADIO_DBG_WARN, "driver has to restart "
"p2p-dev mode after scan");
}
for (i = 0; i < 2; i++) {
tmp_vif = __xrwl_hwpriv_to_vifpriv(hw_priv, i);
if (tmp_vif == NULL)
continue;
if (atomic_xchg(&tmp_vif->delayed_unjoin, 0)) {
if (queue_work(hw_priv->workqueue, &tmp_vif->unjoin_work) <= 0)
wsm_unlock_tx(hw_priv);
}
}
}
static void xradio_scan_complete(struct xradio_common *hw_priv, int if_id)
{
struct xradio_vif *priv;
atomic_xchg(&hw_priv->recent_scan, 0);
scan_printk(XRADIO_DBG_TRC, "%s\n", __func__);
if (hw_priv->scan.direct_probe) {
down(&hw_priv->conf_lock);
priv = __xrwl_hwpriv_to_vifpriv(hw_priv, if_id);
if (priv) {
scan_printk(XRADIO_DBG_NIY, "Direct probe complete.\n");
xradio_scan_restart_delayed(priv);
} else {
scan_printk(XRADIO_DBG_WARN,
"Direct probe complete without interface!\n");
}
up(&hw_priv->conf_lock);
hw_priv->scan.direct_probe = 0;
up(&hw_priv->scan.lock);
wsm_unlock_tx(hw_priv);
} else {
xradio_scan_work(&hw_priv->scan.work);
}
}
void xradio_scan_complete_cb(struct xradio_common *hw_priv,
struct wsm_scan_complete *arg)
{
struct xradio_vif *priv = xrwl_hwpriv_to_vifpriv(hw_priv,
hw_priv->scan.if_id);
scan_printk(XRADIO_DBG_TRC, "%s\n", __func__);
if (unlikely(!priv))
return;
#ifdef ROAM_OFFLOAD
if (hw_priv->auto_scanning)
schedule_delayed_work(&hw_priv->scan.timeout, 0);
#endif /*ROAM_OFFLOAD*/
if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) {
/* STA is stopped. */
spin_unlock(&priv->vif_lock);
scan_printk(XRADIO_DBG_WARN, "%s: priv->mode UNSPECIFIED.\n",
__func__);
return;
}
spin_unlock(&priv->vif_lock);
down(&hw_priv->scan.status_lock);
if (hw_priv->scan.status == -ETIMEDOUT) {
up(&hw_priv->scan.status_lock);
scan_printk(XRADIO_DBG_WARN, "Scan timeout already occured. "
"Don't cancel work");
} else {
hw_priv->scan.status = 1;
up(&hw_priv->scan.status_lock);
if (cancel_delayed_work_sync(&hw_priv->scan.timeout) > 0)
schedule_delayed_work(&hw_priv->scan.timeout, 0);
}
}
void xradio_scan_timeout(struct work_struct *work)
{
struct xradio_common *hw_priv =
container_of(work, struct xradio_common, scan.timeout.work);
scan_printk(XRADIO_DBG_TRC, "%s\n", __func__);
if (likely(atomic_xchg(&hw_priv->scan.in_progress, 0))) {
down(&hw_priv->scan.status_lock);
if (hw_priv->scan.status > 0) {
hw_priv->scan.status = 0;
up(&hw_priv->scan.status_lock);
#ifdef SCAN_FAILED_WORKAROUND_OF_FW_EXCEPTION
hw_priv->scan.scan_failed_cnt = 0;
#endif
} else if (!hw_priv->scan.status) {
scan_printk(XRADIO_DBG_WARN, "Timeout waiting for scan "
"complete notification.\n");
#ifdef SCAN_FAILED_WORKAROUND_OF_FW_EXCEPTION
if (time_after(jiffies, (hw_priv->scan.scan_failed_timestamp +
SCAN_DEFAULT_TIMEOUT*HZ/1000))) {
if (!hw_priv->BT_active)
hw_priv->scan.scan_failed_cnt += 1;
scan_printk(XRADIO_DBG_WARN, "%s:scan timeout cnt=%d",
__func__, hw_priv->scan.scan_failed_cnt);
}
#endif
hw_priv->scan.status = -ETIMEDOUT;
up(&hw_priv->scan.status_lock);
hw_priv->scan.curr = hw_priv->scan.end;
WARN_ON(wsm_stop_scan(hw_priv, hw_priv->scan.if_id ? 1 : 0));
}
xradio_scan_complete(hw_priv, hw_priv->scan.if_id);
#ifdef ROAM_OFFLOAD
} else if (hw_priv->auto_scanning) {
hw_priv->auto_scanning = 0;
mac80211_sched_scan_results(hw_priv->hw);
#endif /*ROAM_OFFLOAD*/
}
}
#ifdef CONFIG_XRADIO_TESTMODE
void xradio_advance_scan_timeout(struct work_struct *work)
{
struct xradio_common *hw_priv =
container_of(work, struct xradio_common, advance_scan_timeout.work);
struct xradio_vif *priv = xrwl_hwpriv_to_vifpriv(hw_priv,
hw_priv->scan.if_id);
scan_printk(XRADIO_DBG_TRC, "%s\n", __func__);
if (WARN_ON(!priv))
return;
spin_unlock(&priv->vif_lock);
hw_priv->scan.status = 0;
if (hw_priv->advanceScanElems.scanMode ==
XRADIO_SCAN_MEASUREMENT_PASSIVE) {
/* Passive Scan on Serving Channel
* Timer Expire */
xradio_scan_complete(hw_priv, hw_priv->scan.if_id);
} else {
/* Active Scan on Serving Channel
* Timer Expire */
down(&hw_priv->conf_lock);
/*wsm_lock_tx(priv);*/
wsm_vif_lock_tx(priv);
/* Once Duration is Over, enable filtering
* and Revert Back Power Save */
if ((priv->powersave_mode.pmMode & WSM_PSM_PS))
wsm_set_pm(hw_priv, &priv->powersave_mode, priv->if_id);
hw_priv->scan.req = NULL;
xradio_update_filtering(priv);
hw_priv->enable_advance_scan = false;
wsm_unlock_tx(hw_priv);
up(&hw_priv->conf_lock);
mac80211_scan_completed(hw_priv->hw,
hw_priv->scan.status ? true : false);
up(&hw_priv->scan.lock);
}
}
#endif
void xradio_probe_work(struct work_struct *work)
{
struct xradio_common *hw_priv =
container_of(work, struct xradio_common, scan.probe_work.work);
struct xradio_vif *priv;
u8 queueId = xradio_queue_get_queue_id(hw_priv->pending_frame_id);
struct xradio_queue *queue = &hw_priv->tx_queue[queueId];
const struct xradio_txpriv *txpriv;
struct wsm_tx *wsm;
struct wsm_template_frame frame = {
.frame_type = WSM_FRAME_TYPE_PROBE_REQUEST,
};
struct wsm_ssid ssids[1] = {{
.length = 0,
} };
struct wsm_scan_ch ch[1] = {{
.minChannelTime = 50,
.maxChannelTime = 80,
} };
struct wsm_scan scan = {
#ifdef SUPPORT_HT40
.scanFlags = 0,
#else
.scanType = WSM_SCAN_TYPE_FOREGROUND,
#endif
.numOfProbeRequests = 1,
.probeDelay = 0,
.numOfChannels = 1,
.ssids = ssids,
.ch = ch,
};
u8 *ies;
size_t ies_len;
int ret = 1;
scan_printk(XRADIO_DBG_NIY, "%s:Direct probe.\n", __func__);
SYS_BUG(queueId >= 4);
SYS_BUG(!hw_priv->channel);
down(&hw_priv->conf_lock);
if (unlikely(down_trylock(&hw_priv->scan.lock))) {
/* Scan is already in progress. Requeue self. */
schedule();
queue_delayed_work(hw_priv->workqueue, &hw_priv->scan.probe_work,
HZ / 10);
up(&hw_priv->conf_lock);
return;
}
if (xradio_queue_get_skb(queue, hw_priv->pending_frame_id,
&frame.skb, &txpriv)) {
up(&hw_priv->scan.lock);
up(&hw_priv->conf_lock);
wsm_unlock_tx(hw_priv);
scan_printk(XRADIO_DBG_ERROR, "%s:xradio_queue_get_skb error!\n",
__func__);
return;
}
priv = __xrwl_hwpriv_to_vifpriv(hw_priv, txpriv->if_id);
if (!priv) {
up(&hw_priv->scan.lock);
up(&hw_priv->conf_lock);
scan_printk(XRADIO_DBG_ERROR, "%s:priv error!\n", __func__);
return;
}
wsm = (struct wsm_tx *)frame.skb->data;
#ifdef SUPPORT_HT40
scan.TransmitRateEntry = wsm->TxRateEntry;
#else
scan.maxTransmitRate = wsm->maxTxRate;
#endif
scan.band = (hw_priv->channel->band == NL80211_BAND_5GHZ) ?
WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G;
#ifdef SUPPORT_HT40
SET_SCAN_TYPE(&scan.scanFlags, WSM_SCAN_TYPE_FOREGROUND);
if (priv->join_status == XRADIO_JOIN_STATUS_STA) {
SET_SCAN_TYPE(&scan.scanFlags, WSM_SCAN_TYPE_BACKGROUND);
SET_SCAN_FLAG(&scan.scanFlags, WSM_SCAN_FLAG_FORCE_BACKGROUND);
if (priv->if_id)
SET_SCAN_FLAG(&scan.scanFlags, WSM_FLAG_MAC_INSTANCE_1);
else
CLR_SCAN_FLAG(&scan.scanFlags, WSM_FLAG_MAC_INSTANCE_1);
}
#else
if (priv->join_status == XRADIO_JOIN_STATUS_STA) {
scan.scanType = WSM_SCAN_TYPE_BACKGROUND;
scan.scanFlags = WSM_SCAN_FLAG_FORCE_BACKGROUND;
if (priv->if_id)
scan.scanFlags |= WSM_FLAG_MAC_INSTANCE_1;
else
scan.scanFlags &= ~WSM_FLAG_MAC_INSTANCE_1;
}
#endif
/* No need to set WSM_SCAN_FLAG_FORCE_BACKGROUND in BSS_LOSS work.*/
/*
xradio_for_each_vif(hw_priv, vif, i) {
if (!vif)
continue;
if (vif->bss_loss_status > XRADIO_BSS_LOSS_NONE)
scan.scanFlags |= WSM_SCAN_FLAG_FORCE_BACKGROUND;
} */
ch[0].number = hw_priv->channel->hw_value;
skb_pull(frame.skb, txpriv->offset);
ies = &frame.skb->data[sizeof(struct ieee80211_hdr_3addr)];
ies_len = frame.skb->len - sizeof(struct ieee80211_hdr_3addr);
if (ies_len) {
u8 *ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ies, ies_len);
if (ssidie && ssidie[1] && ssidie[1] <= sizeof(ssids[0].ssid)) {
u8 *nextie = &ssidie[2 + ssidie[1]];
/* Remove SSID from the IE list. It has to be provided
* as a separate argument in xradio_scan_start call */
/* Store SSID localy */
ssids[0].length = ssidie[1];
memcpy(ssids[0].ssid, &ssidie[2], ssids[0].length);
scan.numOfSSIDs = 1;
/* Remove SSID from IE list */
ssidie[1] = 0;
memmove(&ssidie[2], nextie, &ies[ies_len] - nextie);
skb_trim(frame.skb, frame.skb->len - ssids[0].length);
}
}
if (priv->if_id == 0)
xradio_remove_wps_p2p_ie(&frame);
/* FW bug: driver has to restart p2p-dev mode after scan */
if (priv->join_status == XRADIO_JOIN_STATUS_MONITOR) {
WARN_ON(1);
/*xradio_disable_listening(priv);*/
}
ret = WARN_ON(wsm_set_template_frame(hw_priv, &frame,
priv->if_id));
hw_priv->scan.direct_probe = 1;
hw_priv->scan.if_id = priv->if_id;
if (!ret) {
wsm_flush_tx(hw_priv);
ret = WARN_ON(xradio_scan_start(priv, &scan));
}
up(&hw_priv->conf_lock);
skb_push(frame.skb, txpriv->offset);
if (!ret)
IEEE80211_SKB_CB(frame.skb)->flags |= IEEE80211_TX_STAT_ACK;
#ifdef CONFIG_XRADIO_TESTMODE
SYS_BUG(xradio_queue_remove(hw_priv, queue,
hw_priv->pending_frame_id));
#else
SYS_BUG(xradio_queue_remove(queue, hw_priv->pending_frame_id));
#endif
if (ret) {
hw_priv->scan.direct_probe = 0;
up(&hw_priv->scan.lock);
wsm_unlock_tx(hw_priv);
}
return;
}