a02f8b7629
The bes2600 driver is a fork of the upstream cw1200 driver
(drivers/net/wireless/st/cw1200/, ST-Ericsson, Dmitry Tarnyagin
2010-2011). The fork's file headers have three GPL-compliance issues:
1. NO SPDX-License-Identifier on any of 48 source files (cw1200
mainline has them on all 25). kernel.org-mandated since 2017.
2. Original "Copyright (c) 2010, ST-Ericsson" lines stripped from
all files inherited from cw1200, replaced with
"Copyright (c) 2010, Bestechnic" — factually impossible
(Bestechnic did not author the 2010 work) and a GPL-2.0 §1
attribution-preservation violation.
3. The "GPL version 2 as published by the Free Software Foundation"
boilerplate paragraph is redundant alongside SPDX and is the
legacy form modern kernel sources have replaced.
This patch corrects all three for the 48 .c/.h files in bes2600/:
- Adds `// SPDX-License-Identifier: GPL-2.0-only` (or `/* ... */`
for headers) as line 1 of every file.
- Restores `Copyright (c) 2010, ST-Ericsson` + `Author: Dmitry
Tarnyagin <dmitry.tarnyagin@lockless.no>` as the FIRST copyright
chain entry on all 22 files derived from cw1200 (bh.{c,h},
debug.{c,h}, fwio.{c,h}, hwio.{c,h}, main.c, pm.{c,h},
queue.{c,h}, scan.{c,h}, sta.{c,h}, txrx.{c,h}, wsm.{c,h}).
- Keeps `Copyright (c) 2022, Bestechnic (Beijing) Co., Ltd.` as
the SECOND chain entry where Bestechnic genuinely contributed.
- Notes "Derived from cw1200_sdio.c" + ST-Ericsson copyright on
bes2600_sdio.c (heavy derivation, not a literal rename).
- Notes "Replaces hwbus.h from cw1200/" + ST-Ericsson copyright
on sbus.h.
- Preserves the prism54/islsm authorship chain on main.c and
bes2600.h (Michael Wu 2006 + Jean-Baptiste Note 2004-2006).
- Drops the GPL-2.0 boilerplate paragraph in favour of SPDX.
No code changes — only file-header comment blocks. Module build is
unaffected (verified by header-only diff scope).
This is a prerequisite for any kernel.org submission attempt. The
existing MODULE_LICENSE("GPL") + MODULE_AUTHOR(Tarnyagin@stericsson.com)
declarations were already present and are unchanged here; the
mismatch between MODULE_AUTHOR and the (since-corrected) per-file
copyrights is now resolved.
1232 lines
35 KiB
C
1232 lines
35 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Scan implementation for BES2600 mac80211 driver
|
|
*
|
|
* Copyright (c) 2010, ST-Ericsson
|
|
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
|
|
*
|
|
* Copyright (c) 2022, Bestechnic (Beijing) Co., Ltd.
|
|
*
|
|
*/
|
|
|
|
#include <linux/sched.h>
|
|
#include "bes2600.h"
|
|
#include "scan.h"
|
|
#include "sta.h"
|
|
#include "pm.h"
|
|
#include "epta_coex.h"
|
|
#include "epta_request.h"
|
|
#include "bes_pwr.h"
|
|
|
|
/*
|
|
* After this many consecutive WSM scan rejections from firmware, stop
|
|
* issuing new scans for BES2600_SCAN_BACKOFF_JIFFIES and let the state
|
|
* that's rejecting them (coex window, firmware-internal busy) clear.
|
|
*
|
|
* The backoff has to be at least as long as the natural mac80211 scan-
|
|
* retry cadence, otherwise the next attempt lands outside the window
|
|
* and bypasses the defer guard. Observed in the wild on PineTab2:
|
|
* roam-evaluation bursts at ~12 s cadence, idle background scans at
|
|
* ~5 min cadence. 30 s catches the burst and leaves the slow case
|
|
* alone (the firmware-policy state has had minutes to clear by then
|
|
* anyway).
|
|
*/
|
|
#define BES2600_SCAN_REJECT_THRESHOLD 3
|
|
#define BES2600_SCAN_BACKOFF_JIFFIES (30 * HZ)
|
|
|
|
static void bes2600_scan_restart_delayed(struct bes2600_vif *priv);
|
|
|
|
/*
|
|
* Decide whether to skip sending the next WSM scan command without
|
|
* bothering the firmware. Two triggers:
|
|
*
|
|
* 1. BT A2DP is streaming in non-FDD coex mode. The firmware is
|
|
* known to reject scan requests during that window; short-
|
|
* circuiting here saves a WSM round-trip and avoids the
|
|
* wsm_generic_confirm / scan_work warning cascade that follows.
|
|
*
|
|
* 2. We already saw >= BES2600_SCAN_REJECT_THRESHOLD consecutive
|
|
* rejections on recent scan attempts and the backoff window has
|
|
* not yet elapsed. Whatever was rejecting them is likely still
|
|
* rejecting them; give it time. If the backoff has elapsed without
|
|
* a fresh reject refreshing it, the burst is over and we reset the
|
|
* count so an isolated reject doesn't immediately re-trip.
|
|
*
|
|
* Returns true if the caller should abandon the scan iteration.
|
|
*/
|
|
static bool bes2600_scan_should_defer(struct bes2600_common *hw_priv)
|
|
{
|
|
#ifdef WIFI_BT_COEXIST_EPTA_ENABLE
|
|
if (!coex_is_fdd_mode() && coex_is_bt_a2dp())
|
|
return true;
|
|
#endif
|
|
|
|
if (time_after(jiffies, hw_priv->scan.backoff_until))
|
|
hw_priv->scan.reject_count = 0;
|
|
|
|
if (hw_priv->scan.reject_count >= BES2600_SCAN_REJECT_THRESHOLD &&
|
|
time_before(jiffies, hw_priv->scan.backoff_until))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
#ifdef CONFIG_BES2600_TESTMODE
|
|
static int bes2600_advance_scan_start(struct bes2600_common *hw_priv)
|
|
{
|
|
int tmo = 0;
|
|
tmo += hw_priv->advanceScanElems.duration;
|
|
bes2600_pwr_set_busy_event_with_timeout(hw_priv, BES_PWR_LOCK_ON_ADV_SCAN, tmo);
|
|
/* 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 bes2600_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;
|
|
|
|
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;
|
|
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);
|
|
ies_len -= ie_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);
|
|
ies_len -= ie_len;
|
|
} else {
|
|
ies += ie_len;
|
|
ies_len -= ie_len;
|
|
}
|
|
}
|
|
|
|
if (p2p_ie_len || wps_ie_len) {
|
|
skb_trim(frame->skb, frame->skb->len - (p2p_ie_len + wps_ie_len));
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_BES2600_TESTMODE
|
|
static int bes2600_disable_filtering(struct bes2600_vif *priv)
|
|
{
|
|
int ret = 0;
|
|
bool bssid_filtering = 0;
|
|
struct wsm_rx_filter rx_filter;
|
|
struct wsm_beacon_filter_control bf_control;
|
|
struct bes2600_common *hw_priv = cw12xx_vifpriv_to_hwpriv(priv);
|
|
|
|
/* RX Filter Disable */
|
|
rx_filter.promiscuous = 0;
|
|
rx_filter.bssid = 0;
|
|
rx_filter.fcs = 0;
|
|
rx_filter.probeResponder = 0;
|
|
rx_filter.keepalive = 0;
|
|
ret = wsm_set_rx_filter(hw_priv, &rx_filter,
|
|
priv->if_id);
|
|
|
|
/* Beacon Filter Disable */
|
|
bf_control.enabled = __cpu_to_le32(0);
|
|
bf_control.bcn_count = __cpu_to_le32(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 bes2600_scan_get_first_active_if(struct bes2600_common *hw_priv)
|
|
{
|
|
int i = 0;
|
|
struct bes2600_vif *vif;
|
|
|
|
bes2600_for_each_vif(hw_priv, vif, i) {
|
|
if (vif->join_status > BES2600_JOIN_STATUS_PASSIVE)
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int bes2600_scan_start(struct bes2600_vif *priv, struct wsm_scan *scan)
|
|
{
|
|
int ret, i;
|
|
#ifdef FPGA_SETUP
|
|
int tmo = 5000;
|
|
#else
|
|
int tmo = 5000;
|
|
#endif
|
|
struct bes2600_common *hw_priv = cw12xx_vifpriv_to_hwpriv(priv);
|
|
|
|
|
|
if (hw_priv->scan_switch_if_id == -1 &&
|
|
hw_priv->ht_info.channel_type > NL80211_CHAN_HT20 &&
|
|
priv->if_id >= 0) {
|
|
hw_priv->scan_switch_if_id = bes2600_scan_get_first_active_if(hw_priv);
|
|
if(hw_priv->scan_switch_if_id >= 0) {
|
|
struct wsm_switch_channel channel;
|
|
channel.channelMode = 0 << 4;
|
|
channel.channelSwitchCount = 0;
|
|
channel.newChannelNumber = hw_priv->channel->hw_value;
|
|
wsm_switch_channel(hw_priv, &channel, hw_priv->scan_switch_if_id);
|
|
bes_devel("scan start channel type %d num %d\n", hw_priv->ht_info.channel_type, channel.newChannelNumber);
|
|
}
|
|
}
|
|
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);
|
|
queue_delayed_work(hw_priv->workqueue, &hw_priv->scan.timeout,
|
|
tmo * HZ / 1000);
|
|
#ifdef P2P_MULTIVIF
|
|
ret = wsm_scan(hw_priv, scan, 0);
|
|
#else
|
|
ret = wsm_scan(hw_priv, scan, priv->if_id);
|
|
#endif
|
|
if (unlikely(ret)) {
|
|
atomic_set(&hw_priv->scan.in_progress, 0);
|
|
cancel_delayed_work_sync(&hw_priv->scan.timeout);
|
|
bes2600_scan_restart_delayed(priv);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#ifdef ROAM_OFFLOAD
|
|
static int bes2600_sched_scan_start(struct bes2600_vif *priv, struct wsm_scan *scan)
|
|
{
|
|
int ret;
|
|
struct bes2600_common *hw_priv = cw12xx_vifpriv_to_hwpriv(priv);
|
|
|
|
ret = wsm_scan(hw_priv, scan, priv->if_id);
|
|
if (unlikely(ret)) {
|
|
atomic_set(&hw_priv->scan.in_progress, 0);
|
|
}
|
|
return ret;
|
|
}
|
|
#endif /*ROAM_OFFLOAD*/
|
|
|
|
int bes2600_hw_scan(struct ieee80211_hw *hw,
|
|
struct ieee80211_vif *vif,
|
|
struct ieee80211_scan_request *hw_req)
|
|
{
|
|
struct bes2600_common *hw_priv = hw->priv;
|
|
struct bes2600_vif *priv = cw12xx_get_vif_from_ieee80211(vif);
|
|
struct cfg80211_scan_request *req = &hw_req->req;
|
|
struct wsm_template_frame frame = {
|
|
.frame_type = WSM_FRAME_TYPE_PROBE_REQUEST,
|
|
};
|
|
int i;
|
|
/* Scan when P2P_GO corrupt firmware MiniAP mode */
|
|
if (priv->join_status == BES2600_JOIN_STATUS_AP)
|
|
return -EOPNOTSUPP;
|
|
#if 0
|
|
if (work_pending(&priv->offchannel_work) ||
|
|
(hw_priv->roc_if_id != -1)) {
|
|
wiphy_dbg(hw_priv->hw->wiphy, "[SCAN] Offchannel work pending, "
|
|
"ignoring scan work %d\n", hw_priv->roc_if_id);
|
|
return -EBUSY;
|
|
}
|
|
#endif
|
|
if (req->n_ssids == 1 && !req->ssids[0].ssid_len)
|
|
req->n_ssids = 0;
|
|
|
|
wiphy_dbg(hw->wiphy, "[SCAN] Scan request for %d SSIDs.\n",
|
|
req->n_ssids);
|
|
|
|
if (req->n_ssids > hw->wiphy->max_scan_ssids)
|
|
return -EINVAL;
|
|
|
|
bes2600_pwr_set_busy_event(hw_priv, BES_PWR_LOCK_ON_SCAN);
|
|
|
|
/* will be unlocked in bes2600_scan_work() */
|
|
down(&hw_priv->scan.lock);
|
|
down(&hw_priv->conf_lock);
|
|
|
|
frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0,
|
|
req->ie_len);
|
|
if (!frame.skb) {
|
|
up(&hw_priv->conf_lock);
|
|
up(&hw_priv->scan.lock);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
if (req->ie_len)
|
|
skb_put_data(frame.skb, req->ie, req->ie_len);
|
|
|
|
if (frame.skb) {
|
|
int ret;
|
|
//if (priv->if_id == 0)
|
|
// bes2600_remove_wps_p2p_ie(&frame);
|
|
#ifdef P2P_MULTIVIF
|
|
ret = wsm_set_template_frame(hw_priv, &frame, 0);
|
|
#else
|
|
ret = wsm_set_template_frame(hw_priv, &frame,
|
|
priv->if_id);
|
|
#endif
|
|
#if 0
|
|
if (!ret) {
|
|
/* Host want to be the probe responder. */
|
|
ret = wsm_set_probe_responder(priv, true);
|
|
}
|
|
#endif
|
|
if (ret) {
|
|
dev_kfree_skb(frame.skb);
|
|
up(&hw_priv->conf_lock);
|
|
up(&hw_priv->scan.lock);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
wsm_vif_lock_tx(priv);
|
|
|
|
BUG_ON(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 */
|
|
bes_devel("%s %d if_id:%d,num_channel:%d.\n", __func__, __LINE__, priv->if_id, req->n_channels);
|
|
|
|
for (i = 0; i < req->n_ssids; ++i) {
|
|
struct wsm_ssid *dst =
|
|
&hw_priv->scan.ssids[hw_priv->scan.n_ssids];
|
|
BUG_ON(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;
|
|
}
|
|
|
|
if (frame.skb)
|
|
dev_kfree_skb(frame.skb);
|
|
|
|
up(&hw_priv->conf_lock);
|
|
#ifdef WIFI_BT_COEXIST_EPTA_ENABLE
|
|
bwifi_change_current_status(hw_priv, BWIFI_STATUS_SCANNING);
|
|
#endif
|
|
queue_work(hw_priv->workqueue, &hw_priv->scan.work);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef ROAM_OFFLOAD
|
|
int bes2600_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 bes2600_common *hw_priv = hw->priv;
|
|
struct bes2600_vif *priv = cw12xx_get_vif_from_ieee80211(vif);
|
|
struct wsm_template_frame frame = {
|
|
.frame_type = WSM_FRAME_TYPE_PROBE_REQUEST,
|
|
};
|
|
int i;
|
|
|
|
wiphy_warn(hw->wiphy, "[SCAN] Scheduled scan request-->.\n");
|
|
|
|
if (!priv->vif)
|
|
return -EINVAL;
|
|
|
|
/* Scan when P2P_GO corrupt firmware MiniAP mode */
|
|
if (priv->join_status == BES2600_JOIN_STATUS_AP)
|
|
return -EOPNOTSUPP;
|
|
|
|
wiphy_warn(hw->wiphy, "[SCAN] 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;
|
|
|
|
wiphy_dbg(hw->wiphy, "[SCAN] Scan request for %d SSIDs.\n",
|
|
req->n_ssids);
|
|
|
|
if (req->n_ssids > hw->wiphy->max_scan_ssids)
|
|
return -EINVAL;
|
|
|
|
/* will be unlocked in bes2600_scan_work() */
|
|
down(&hw_priv->scan.lock);
|
|
down(&hw_priv->conf_lock);
|
|
|
|
frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0,
|
|
req->ie_len);
|
|
if (!frame.skb) {
|
|
up(&hw_priv->conf_lock);
|
|
up(&hw_priv->scan.lock);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
if (frame.skb) {
|
|
int ret;
|
|
if (priv->if_id == 0)
|
|
bes2600_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) {
|
|
dev_kfree_skb(frame.skb);
|
|
up(&hw_priv->conf_lock);
|
|
up(&hw_priv->scan.lock);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
wsm_lock_tx(hw_priv);
|
|
|
|
BUG_ON(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) {
|
|
struct wsm_ssid *dst =
|
|
&hw_priv->scan.ssids[hw_priv->scan.n_ssids];
|
|
BUG_ON(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;
|
|
{
|
|
u8 j;
|
|
wiphy_warn(hw->wiphy, "[SCAN] SSID %d\n",i);
|
|
for(j=0; j<req->ssids[i].ssid_len; j++)
|
|
wiphy_warn(priv->hw->wiphy, "[SCAN] 0x%x\n", req->ssids[i].ssid[j]);
|
|
}
|
|
}
|
|
|
|
if (frame.skb)
|
|
dev_kfree_skb(frame.skb);
|
|
|
|
up(&hw_priv->conf_lock);
|
|
queue_work(hw_priv->workqueue, &hw_priv->scan.swork);
|
|
wiphy_warn(hw->wiphy, "<--[SCAN] Scheduled scan request.\n");
|
|
return 0;
|
|
}
|
|
#endif /*ROAM_OFFLOAD*/
|
|
void bes2600_scan_work(struct work_struct *work)
|
|
{
|
|
struct bes2600_common *hw_priv = container_of(work,
|
|
struct bes2600_common,
|
|
scan.work);
|
|
struct bes2600_vif *priv, *vif;
|
|
struct ieee80211_channel **it;
|
|
struct wsm_scan scan = {
|
|
.scanType = WSM_SCAN_TYPE_FOREGROUND,
|
|
.scanFlags = 0, /* TODO:COMBO */
|
|
//.scanFlags = WSM_SCAN_FLAG_SPLIT_METHOD, /* TODO:COMBO */
|
|
};
|
|
bool first_run;
|
|
int i;
|
|
const u32 ProbeRequestTime = 2;
|
|
const u32 ChannelRemainTime = 15;
|
|
#ifdef WIFI_BT_COEXIST_EPTA_ENABLE
|
|
u32 minChannelTime;
|
|
#endif
|
|
u32 maxChannelTime;
|
|
#ifdef CONFIG_BES2600_TESTMODE
|
|
int ret = 0;
|
|
u16 advance_scan_req_channel = hw_priv->scan.begin[0]->hw_value;
|
|
#endif
|
|
priv = __cw12xx_hwpriv_to_vifpriv(hw_priv, hw_priv->scan.if_id);
|
|
|
|
/*TODO: COMBO: introduce locking so vif is not removed in meanwhile */
|
|
if (!priv) {
|
|
wiphy_warn(hw_priv->hw->wiphy, "[SCAN] interface removed, "
|
|
"ignoring scan work\n");
|
|
return;
|
|
}
|
|
|
|
if (priv->if_id)
|
|
scan.scanFlags |= WSM_FLAG_MAC_INSTANCE_1;
|
|
else
|
|
scan.scanFlags &= ~WSM_FLAG_MAC_INSTANCE_1;
|
|
|
|
bes2600_for_each_vif(hw_priv, vif, i) {
|
|
#ifdef P2P_MULTIVIF
|
|
if ((i == (CW12XX_MAX_VIFS - 1)) || !vif)
|
|
#else
|
|
if (!vif)
|
|
#endif
|
|
continue;
|
|
if (vif->bss_loss_status > BES2600_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) {
|
|
bes2600_join_timeout(&priv->join_timeout.work);
|
|
}
|
|
}
|
|
down(&hw_priv->conf_lock);
|
|
if (first_run) {
|
|
#ifdef CONFIG_BES2600_TESTMODE
|
|
/* Passive Scan - Serving Channel Request Handling */
|
|
if (hw_priv->enable_advance_scan &&
|
|
(hw_priv->advanceScanElems.scanMode ==
|
|
BES2600_SCAN_MEASUREMENT_PASSIVE) &&
|
|
(priv->join_status == BES2600_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 = bes2600_disable_filtering(priv);
|
|
if (ret)
|
|
wiphy_err(hw_priv->hw->wiphy,
|
|
"%s: Disable BSSID or Beacon filtering failed: %d.\n",
|
|
__func__, ret);
|
|
} else if (hw_priv->enable_advance_scan &&
|
|
(hw_priv->advanceScanElems.scanMode ==
|
|
BES2600_SCAN_MEASUREMENT_PASSIVE) &&
|
|
(priv->join_status == BES2600_JOIN_STATUS_STA)) {
|
|
if (priv->join_status == BES2600_JOIN_STATUS_STA &&
|
|
!(priv->powersave_mode.pmMode & WSM_PSM_PS)) {
|
|
struct wsm_set_pm pm = priv->powersave_mode;
|
|
pm.pmMode = WSM_PSM_PS;
|
|
bes2600_set_pm(priv, &pm);
|
|
}
|
|
} else {
|
|
#endif
|
|
#if 0
|
|
if (priv->join_status == BES2600_JOIN_STATUS_STA &&
|
|
!(priv->powersave_mode.pmMode & WSM_PSM_PS)) {
|
|
struct wsm_set_pm pm = priv->powersave_mode;
|
|
pm.pmMode = WSM_PSM_PS;
|
|
bes2600_set_pm(priv, &pm);
|
|
} else
|
|
#endif
|
|
if (priv->join_status == BES2600_JOIN_STATUS_MONITOR) {
|
|
/* FW bug: driver has to restart p2p-dev mode
|
|
* after scan */
|
|
bes2600_disable_listening(priv);
|
|
}
|
|
#ifdef CONFIG_BES2600_TESTMODE
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (!hw_priv->scan.req || (hw_priv->scan.curr == hw_priv->scan.end)) {
|
|
struct cfg80211_scan_info info = {
|
|
.aborted = hw_priv->scan.status ? 1 : 0,
|
|
};
|
|
|
|
#ifdef CONFIG_BES2600_TESTMODE
|
|
if (hw_priv->enable_advance_scan &&
|
|
(hw_priv->advanceScanElems.scanMode ==
|
|
BES2600_SCAN_MEASUREMENT_PASSIVE) &&
|
|
(priv->join_status == BES2600_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);
|
|
bes2600_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 ? 0 : 0));
|
|
#else
|
|
WARN_ON(wsm_set_output_power(hw_priv,
|
|
hw_priv->output_power * 10,
|
|
priv->if_id));
|
|
#endif
|
|
#ifdef CONFIG_BES2600_TESTMODE
|
|
}
|
|
}
|
|
#endif
|
|
#if 0
|
|
if (priv->join_status == BES2600_JOIN_STATUS_STA &&
|
|
!(priv->powersave_mode.pmMode & WSM_PSM_PS))
|
|
bes2600_set_pm(priv, &priv->powersave_mode);
|
|
#endif
|
|
if (hw_priv->scan.status < 0)
|
|
wiphy_info(priv->hw->wiphy,
|
|
"[SCAN] Scan failed (%d).\n",
|
|
hw_priv->scan.status);
|
|
else if (hw_priv->scan.req)
|
|
wiphy_dbg(priv->hw->wiphy,
|
|
"[SCAN] Scan completed.\n");
|
|
else
|
|
wiphy_dbg(priv->hw->wiphy,
|
|
"[SCAN] Scan canceled.\n");
|
|
|
|
#ifdef WIFI_BT_COEXIST_EPTA_ENABLE
|
|
if (priv->join_status == BES2600_JOIN_STATUS_STA) {
|
|
if (hw_priv->channel->band != NL80211_BAND_2GHZ)
|
|
bwifi_change_current_status(hw_priv, BWIFI_STATUS_GOT_IP_5G);
|
|
else
|
|
bwifi_change_current_status(hw_priv, BWIFI_STATUS_GOT_IP);
|
|
} else {
|
|
bwifi_change_current_status(hw_priv, BWIFI_STATUS_IDLE);
|
|
}
|
|
#endif
|
|
bes_devel("%s %d %d.", __func__, __LINE__, hw_priv->ht_info.channel_type);
|
|
/* switch to previous channel and bw mode after scan done */
|
|
if (hw_priv->scan_switch_if_id >= 0) {
|
|
struct wsm_switch_channel channel;
|
|
channel.channelMode = hw_priv->ht_info.channel_type << 4;
|
|
channel.channelSwitchCount = 0;
|
|
channel.newChannelNumber = hw_priv->channel->hw_value;
|
|
wsm_switch_channel(hw_priv, &channel, hw_priv->scan_switch_if_id);
|
|
hw_priv->scan_switch_if_id = -1;
|
|
bes_devel("scan done channel type %d num %d\n", hw_priv->ht_info.channel_type, channel.newChannelNumber);
|
|
}
|
|
|
|
hw_priv->scan.req = NULL;
|
|
bes2600_scan_restart_delayed(priv);
|
|
#ifdef CONFIG_BES2600_TESTMODE
|
|
hw_priv->enable_advance_scan = false;
|
|
#endif /* CONFIG_BES2600_TESTMODE */
|
|
wsm_unlock_tx(hw_priv);
|
|
up(&hw_priv->conf_lock);
|
|
bes2600_pwr_clear_busy_event(hw_priv, BES_PWR_LOCK_ON_SCAN);
|
|
ieee80211_scan_completed(hw_priv->hw, &info);
|
|
up(&hw_priv->scan.lock);
|
|
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;
|
|
// Doen't split scan req in case of EPTA error after scan req
|
|
// if (((*it)->flags ^ first->flags) &
|
|
// IEEE80211_CHAN_NO_IR)
|
|
// break;
|
|
// if (!(first->flags & IEEE80211_CHAN_NO_IR) &&
|
|
// (*it)->max_power != first->max_power)
|
|
// break;
|
|
}
|
|
scan.band = first->band;
|
|
|
|
if (hw_priv->scan.req->no_cck)
|
|
scan.maxTransmitRate = WSM_TRANSMIT_RATE_6;
|
|
else
|
|
scan.maxTransmitRate = WSM_TRANSMIT_RATE_1;
|
|
#ifdef CONFIG_BES2600_TESTMODE
|
|
if (hw_priv->enable_advance_scan) {
|
|
if (hw_priv->advanceScanElems.scanMode ==
|
|
BES2600_SCAN_MEASUREMENT_PASSIVE)
|
|
scan.numOfProbeRequests = 0;
|
|
else
|
|
scan.numOfProbeRequests = 2;
|
|
} else {
|
|
#endif
|
|
/* TODO: Is it optimal? */
|
|
scan.numOfProbeRequests =
|
|
(first->flags & IEEE80211_CHAN_NO_IR) ? 0 : 2;
|
|
#ifdef CONFIG_BES2600_TESTMODE
|
|
}
|
|
#endif /* CONFIG_BES2600_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 = 100;
|
|
/* It is not stated in WSM specification, however
|
|
* FW team says that driver may not use FG scan
|
|
* when joined. */
|
|
if (priv->join_status == BES2600_JOIN_STATUS_STA) {
|
|
scan.scanType = WSM_SCAN_TYPE_BACKGROUND;
|
|
scan.scanFlags = WSM_SCAN_FLAG_FORCE_BACKGROUND;
|
|
}
|
|
scan.ch = kcalloc((it - hw_priv->scan.curr),
|
|
sizeof(struct wsm_scan_ch),
|
|
GFP_KERNEL);
|
|
if (!scan.ch) {
|
|
hw_priv->scan.status = -ENOMEM;
|
|
goto fail;
|
|
}
|
|
maxChannelTime = (scan.numOfSSIDs * scan.numOfProbeRequests *
|
|
ProbeRequestTime) + ChannelRemainTime;
|
|
maxChannelTime = (maxChannelTime < 35) ? 35 : maxChannelTime;
|
|
|
|
#ifdef WIFI_BT_COEXIST_EPTA_ENABLE
|
|
if (scan.band == NL80211_BAND_2GHZ) {
|
|
coex_calc_wifi_scan_time(&minChannelTime, &maxChannelTime);
|
|
} else {
|
|
minChannelTime = 100;
|
|
maxChannelTime = 100;
|
|
}
|
|
#endif
|
|
|
|
for (i = 0; i < scan.numOfChannels; ++i) {
|
|
scan.ch[i].number = hw_priv->scan.curr[i]->hw_value;
|
|
#ifdef CONFIG_BES2600_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
|
|
|
|
#ifndef WIFI_BT_COEXIST_EPTA_ENABLE
|
|
if (hw_priv->scan.curr[i]->flags & IEEE80211_CHAN_NO_IR) {
|
|
scan.ch[i].minChannelTime = 40;
|
|
scan.ch[i].maxChannelTime = 100;
|
|
}
|
|
else {
|
|
//TODO: modify maxChannelTime
|
|
scan.ch[i].minChannelTime = 15;
|
|
scan.ch[i].maxChannelTime = maxChannelTime;
|
|
}
|
|
#else
|
|
scan.ch[i].minChannelTime = minChannelTime;
|
|
scan.ch[i].maxChannelTime = maxChannelTime;
|
|
#endif
|
|
|
|
#ifdef CONFIG_BES2600_TESTMODE
|
|
}
|
|
#endif
|
|
}
|
|
#ifdef CONFIG_BES2600_TESTMODE
|
|
if (!hw_priv->enable_advance_scan) {
|
|
#endif
|
|
if (!(first->flags & IEEE80211_CHAN_NO_IR) &&
|
|
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 ? 0 : 0));
|
|
#else
|
|
WARN_ON(wsm_set_output_power(hw_priv,
|
|
hw_priv->scan.output_power * 10,
|
|
priv->if_id));
|
|
#endif
|
|
}
|
|
#ifdef CONFIG_BES2600_TESTMODE
|
|
}
|
|
#endif
|
|
#ifdef CONFIG_BES2600_TESTMODE
|
|
if (hw_priv->enable_advance_scan &&
|
|
(hw_priv->advanceScanElems.scanMode ==
|
|
BES2600_SCAN_MEASUREMENT_PASSIVE) &&
|
|
(priv->join_status == BES2600_JOIN_STATUS_STA) &&
|
|
(hw_priv->channel->hw_value == advance_scan_req_channel)) {
|
|
/* Start Advance Scan Timer */
|
|
hw_priv->scan.status = bes2600_advance_scan_start(hw_priv);
|
|
wsm_unlock_tx(hw_priv);
|
|
} else
|
|
#endif
|
|
{
|
|
if (bes2600_scan_should_defer(hw_priv)) {
|
|
hw_priv->scan.status = -EBUSY;
|
|
hw_priv->scan.reject_count++;
|
|
hw_priv->scan.backoff_until =
|
|
jiffies + BES2600_SCAN_BACKOFF_JIFFIES;
|
|
wiphy_dbg(priv->hw->wiphy,
|
|
"[SCAN] deferred (coex/backoff, reject_count=%u)\n",
|
|
hw_priv->scan.reject_count);
|
|
kfree(scan.ch);
|
|
goto fail;
|
|
}
|
|
hw_priv->scan.status = bes2600_scan_start(priv, &scan);
|
|
}
|
|
kfree(scan.ch);
|
|
if (hw_priv->scan.status) {
|
|
hw_priv->scan.reject_count++;
|
|
hw_priv->scan.backoff_until =
|
|
jiffies + BES2600_SCAN_BACKOFF_JIFFIES;
|
|
/* Lower callers already logged the reason at wiphy_warn. */
|
|
goto fail;
|
|
}
|
|
hw_priv->scan.reject_count = 0;
|
|
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);
|
|
queue_work(hw_priv->workqueue, &hw_priv->scan.work);
|
|
return;
|
|
}
|
|
|
|
#ifdef ROAM_OFFLOAD
|
|
void bes2600_sched_scan_work(struct work_struct *work)
|
|
{
|
|
struct bes2600_common *hw_priv = container_of(work, struct bes2600_common,
|
|
scan.swork);
|
|
struct wsm_scan scan;
|
|
struct wsm_ssid scan_ssid;
|
|
int i;
|
|
struct bes2600_vif *priv = cw12xx_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) {
|
|
bes2600_join_timeout(&priv->join_timeout.work);
|
|
}
|
|
down(&hw_priv->conf_lock);
|
|
hw_priv->auto_scanning = 1;
|
|
|
|
scan.band = 0;
|
|
|
|
if (priv->join_status == BES2600_JOIN_STATUS_STA)
|
|
scan.scanType = 3; /* auto background */
|
|
else
|
|
scan.scanType = 2; /* auto foreground */
|
|
|
|
scan.scanFlags = 0x01; /* bit 0 set => forced background scan */
|
|
scan.maxTransmitRate = WSM_TRANSMIT_RATE_6;
|
|
scan.autoScanInterval = (0xba << 24)|(30 * 1024); /* 30 seconds, -70 rssi */
|
|
scan.numOfProbeRequests = 2;
|
|
//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 = kzalloc(
|
|
sizeof(struct wsm_scan_ch[scan.numOfChannels]),
|
|
GFP_KERNEL);
|
|
if (!scan.ch) {
|
|
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 = bes2600_sched_scan_start(priv, &scan);
|
|
kfree(scan.ch);
|
|
if (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 bes2600_hw_sched_scan_stop(struct bes2600_common *hw_priv)
|
|
{
|
|
struct bes2600_vif *priv = cw12xx_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 bes2600_scan_restart_delayed(struct bes2600_vif *priv)
|
|
{
|
|
struct bes2600_common *hw_priv = cw12xx_vifpriv_to_hwpriv(priv);
|
|
|
|
if (priv->delayed_link_loss) {
|
|
int tmo = priv->cqm_beacon_loss_count;
|
|
|
|
if (hw_priv->scan.direct_probe)
|
|
tmo = 0;
|
|
|
|
priv->delayed_link_loss = 0;
|
|
/* Restart beacon loss timer and requeue
|
|
BSS loss work. */
|
|
wiphy_dbg(priv->hw->wiphy,
|
|
"[CQM] Requeue BSS loss in %d "
|
|
"beacons.\n", tmo);
|
|
spin_lock(&priv->bss_loss_lock);
|
|
priv->bss_loss_status = BES2600_BSS_LOSS_NONE;
|
|
spin_unlock(&priv->bss_loss_lock);
|
|
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 == BES2600_JOIN_STATUS_MONITOR) {
|
|
/*bes2600_enable_listening(priv);*/
|
|
// WARN_ON(1);
|
|
bes_devel("scan complete join_status is monitor");
|
|
bes2600_update_filtering(priv);
|
|
}
|
|
|
|
if (priv->delayed_unjoin) {
|
|
priv->delayed_unjoin = false;
|
|
if (queue_work(hw_priv->workqueue, &priv->unjoin_work) <= 0)
|
|
wsm_unlock_tx(hw_priv);
|
|
}
|
|
}
|
|
|
|
static void bes2600_scan_complete(struct bes2600_common *hw_priv, int if_id)
|
|
{
|
|
struct bes2600_vif *priv;
|
|
atomic_xchg(&hw_priv->recent_scan, 0);
|
|
|
|
if (hw_priv->scan.direct_probe) {
|
|
down(&hw_priv->conf_lock);
|
|
priv = __cw12xx_hwpriv_to_vifpriv(hw_priv, if_id);
|
|
if (priv) {
|
|
wiphy_dbg(priv->hw->wiphy, "[SCAN] Direct probe "
|
|
"complete.\n");
|
|
bes2600_scan_restart_delayed(priv);
|
|
} else {
|
|
wiphy_dbg(priv->hw->wiphy, "[SCAN] 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 {
|
|
bes2600_scan_work(&hw_priv->scan.work);
|
|
}
|
|
}
|
|
|
|
void bes2600_scan_complete_cb(struct bes2600_common *hw_priv,
|
|
struct wsm_scan_complete *arg)
|
|
{
|
|
struct bes2600_vif *priv = cw12xx_hwpriv_to_vifpriv(hw_priv,
|
|
hw_priv->scan.if_id);
|
|
|
|
if (unlikely(!priv))
|
|
return;
|
|
|
|
#ifdef ROAM_OFFLOAD
|
|
if (hw_priv->auto_scanning)
|
|
queue_delayed_work(hw_priv->workqueue,
|
|
&hw_priv->scan.timeout, 0);
|
|
#endif /*ROAM_OFFLOAD*/
|
|
|
|
if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) {
|
|
/* STA is stopped. */
|
|
spin_unlock(&priv->vif_lock);
|
|
return;
|
|
}
|
|
spin_unlock(&priv->vif_lock);
|
|
|
|
#ifdef WIFI_BT_COEXIST_EPTA_ENABLE
|
|
// recover EPTA timer after scan wsm msg complete, in case of epta state error
|
|
// bwifi_change_current_status(hw_priv, BWIFI_STATUS_SCANNING_COMP);
|
|
#endif
|
|
wiphy_dbg(hw_priv->hw->wiphy, "bes2600_scan_complete_cb status: %u", arg->status);
|
|
|
|
if(hw_priv->scan.status == -ETIMEDOUT)
|
|
wiphy_warn(hw_priv->hw->wiphy,
|
|
"Scan timeout already occured. Don't cancel work");
|
|
if ((hw_priv->scan.status != -ETIMEDOUT) &&
|
|
(cancel_delayed_work_sync(&hw_priv->scan.timeout) > 0)) {
|
|
hw_priv->scan.status = 1;
|
|
queue_delayed_work(hw_priv->workqueue,
|
|
&hw_priv->scan.timeout, 0);
|
|
}
|
|
}
|
|
|
|
void bes2600_scan_timeout(struct work_struct *work)
|
|
{
|
|
struct bes2600_common *hw_priv =
|
|
container_of(work, struct bes2600_common, scan.timeout.work);
|
|
|
|
if (likely(atomic_xchg(&hw_priv->scan.in_progress, 0))) {
|
|
if (hw_priv->scan.status > 0)
|
|
hw_priv->scan.status = 0;
|
|
else if (!hw_priv->scan.status) {
|
|
wiphy_warn(hw_priv->hw->wiphy,
|
|
"Timeout waiting for scan "
|
|
"complete notification.\n");
|
|
hw_priv->scan.status = -ETIMEDOUT;
|
|
hw_priv->scan.curr = hw_priv->scan.end;
|
|
WARN_ON(wsm_stop_scan(hw_priv,
|
|
hw_priv->scan.if_id ? 1 : 0));
|
|
}
|
|
bes2600_scan_complete(hw_priv, hw_priv->scan.if_id);
|
|
#ifdef ROAM_OFFLOAD
|
|
} else if (hw_priv->auto_scanning) {
|
|
hw_priv->auto_scanning = 0;
|
|
ieee80211_sched_scan_results(hw_priv->hw);
|
|
#endif /*ROAM_OFFLOAD*/
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_BES2600_TESTMODE
|
|
void bes2600_advance_scan_timeout(struct work_struct *work)
|
|
{
|
|
struct bes2600_common *hw_priv =
|
|
container_of(work, struct bes2600_common, advance_scan_timeout.work);
|
|
|
|
struct bes2600_vif *priv = cw12xx_hwpriv_to_vifpriv(hw_priv,
|
|
hw_priv->scan.if_id);
|
|
if (WARN_ON(!priv))
|
|
return;
|
|
spin_unlock(&priv->vif_lock);
|
|
|
|
hw_priv->scan.status = 0;
|
|
if (hw_priv->advanceScanElems.scanMode ==
|
|
BES2600_SCAN_MEASUREMENT_PASSIVE) {
|
|
/* Passive Scan on Serving Channel
|
|
* Timer Expire */
|
|
bes2600_scan_complete(hw_priv, hw_priv->scan.if_id);
|
|
} else {
|
|
struct cfg80211_scan_info info = {
|
|
.aborted = hw_priv->scan.status ? 1 : 0,
|
|
};
|
|
/* 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;
|
|
bes2600_update_filtering(priv);
|
|
hw_priv->enable_advance_scan = false;
|
|
wsm_unlock_tx(hw_priv);
|
|
up(&hw_priv->conf_lock);
|
|
ieee80211_scan_completed(hw_priv->hw, &info);
|
|
up(&hw_priv->scan.lock);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void bes2600_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
|
{
|
|
struct bes2600_vif *priv = cw12xx_get_vif_from_ieee80211(vif);
|
|
struct bes2600_common *hw_priv = cw12xx_vifpriv_to_hwpriv(priv);
|
|
|
|
if(hw_priv->scan.if_id == priv->if_id) {
|
|
bes_devel("cancel hw_scan on intf:%d\n", priv->if_id);
|
|
|
|
down(&hw_priv->conf_lock);
|
|
hw_priv->scan.req = NULL;
|
|
up(&hw_priv->conf_lock);
|
|
|
|
/* cancel scan operation */
|
|
wsm_stop_scan(hw_priv, priv->if_id);
|
|
|
|
/* wait scan operation end */
|
|
down(&hw_priv->scan.lock);
|
|
up(&hw_priv->scan.lock);
|
|
}
|
|
}
|
|
|
|
void bes2600_probe_work(struct work_struct *work)
|
|
{
|
|
struct bes2600_common *hw_priv =
|
|
container_of(work, struct bes2600_common, scan.probe_work.work);
|
|
struct bes2600_vif *priv, *vif;
|
|
u8 queueId = bes2600_queue_get_queue_id(hw_priv->pending_frame_id);
|
|
struct bes2600_queue *queue = &hw_priv->tx_queue[queueId];
|
|
const struct bes2600_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 = 0,
|
|
.maxChannelTime = 10,
|
|
} };
|
|
struct wsm_scan scan = {
|
|
.scanType = WSM_SCAN_TYPE_FOREGROUND,
|
|
.numOfProbeRequests = 2,
|
|
.probeDelay = 0,
|
|
.numOfChannels = 1,
|
|
.ssids = ssids,
|
|
.ch = ch,
|
|
};
|
|
u8 *ies;
|
|
size_t ies_len;
|
|
int ret = 1;
|
|
int i;
|
|
wiphy_info(hw_priv->hw->wiphy, "[SCAN] Direct probe work.\n");
|
|
|
|
BUG_ON(queueId >= 4);
|
|
BUG_ON(!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 (bes2600_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);
|
|
return;
|
|
}
|
|
priv = __cw12xx_hwpriv_to_vifpriv(hw_priv, txpriv->if_id);
|
|
if (!priv) {
|
|
up(&hw_priv->scan.lock);
|
|
up(&hw_priv->conf_lock);
|
|
return;
|
|
}
|
|
wsm = (struct wsm_tx *)frame.skb->data;
|
|
scan.maxTransmitRate = wsm->maxTxRate;
|
|
scan.band = (hw_priv->channel->band == NL80211_BAND_5GHZ) ?
|
|
WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G;
|
|
if (priv->join_status == BES2600_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;
|
|
}
|
|
bes2600_for_each_vif(hw_priv, vif, i) {
|
|
if (!vif)
|
|
continue;
|
|
if (vif->bss_loss_status > BES2600_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 bes2600_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)
|
|
bes2600_remove_wps_p2p_ie(&frame);
|
|
|
|
/* FW bug: driver has to restart p2p-dev mode after scan */
|
|
if (priv->join_status == BES2600_JOIN_STATUS_MONITOR) {
|
|
WARN_ON(1);
|
|
/*bes2600_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(bes2600_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_BES2600_TESTMODE
|
|
BUG_ON(bes2600_queue_remove(hw_priv, queue,
|
|
hw_priv->pending_frame_id));
|
|
#else
|
|
BUG_ON(bes2600_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;
|
|
}
|
|
|