luckfox-pico-sdk/sysdrv/drv_ko/wifi/atbm/hal_apollo/scan.c
2023-08-08 20:36:47 +08:00

1627 lines
47 KiB
C

/*
* Scan implementation for altobeam APOLLO mac80211 drivers
*
* Copyright (c) 2016, altobeam
*
* Based on:
* Copyright (c) 2010, ST-Ericsson
* Author: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.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 "apollo.h"
#include "scan.h"
#include "sta.h"
#include "pm.h"
#include "bh.h"
#include "atbm_p2p.h"
#ifdef CONFIG_ATBM_SCAN_SPLIT
#define ATBM_SPLIT_SCAN_MAX_CHANNEL 2
#define ATBM_SPLIT_NEXT_CHANNEL_TIME (500)
#endif
#ifdef ATBM_SUPPORT_SMARTCONFIG
extern int smartconfig_magic_scan_done(struct atbm_common *hw_priv);
#endif
static void atbm_scan_restart_delayed(struct atbm_vif *priv);
//#ifdef CONFIG_WIRELESS_EXT
extern void etf_v2_scan_end(struct atbm_common *hw_priv, struct ieee80211_vif *vif );
extern void etf_v2_scan_rx(struct atbm_common *hw_priv,struct sk_buff *skb,u8 rssi );
//#endif
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
static int atbm_advance_scan_start(struct atbm_common *hw_priv)
{
int tmo = 0;
tmo += hw_priv->advanceScanElems.duration;
#ifdef CONFIG_PM
atbm_pm_stay_awake(&hw_priv->pm_state, tmo * HZ / 1000);
#endif
/* Invoke Advance Scan Duration Timeout Handler */
atbm_hw_priv_queue_delayed_work(hw_priv,
&hw_priv->advance_scan_timeout, tmo * HZ / 1000);
return 0;
}
#endif
#ifdef CONFIG_ATBM_SUPPORT_P2P
static void atbm_remove_wps_p2p_ie(struct wsm_template_frame *frame)
{
u8 *ies;
int ies_len;
int 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] == ATBM_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] == ATBM_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) {
atbm_skb_trim(frame->skb, frame->skb->len - (p2p_ie_len + wps_ie_len));
}
}
#endif
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
static int atbm_disable_filtering(struct atbm_vif *priv)
{
int ret = 0;
bool bssid_filtering = 0;
struct wsm_rx_filter rx_filter;
struct wsm_beacon_filter_control bf_control;
struct atbm_common *hw_priv = ABwifi_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 = 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
#ifdef CONFIG_ATBM_SCAN_SPLIT
void atbm_scan_split_work(struct atbm_work_struct *work)
{
struct atbm_common *hw_priv =
container_of(work, struct atbm_common, scan.scan_spilt.work);
wsm_lock_tx_async(hw_priv);
atbm_scan_work(&hw_priv->scan.work);
}
#endif
static bool atbm_scan_split_running(struct atbm_common *hw_priv)
{
#ifdef CONFIG_ATBM_SCAN_SPLIT
if(hw_priv->scan.curr == hw_priv->scan.end)
return false;
if(hw_priv->scan.split == 0)
return false;
wsm_unlock_tx(hw_priv);
atbm_printk_debug("%s:wait next scan\n",__func__);
atbm_hw_priv_queue_delayed_work(hw_priv, &hw_priv->scan.scan_spilt,msecs_to_jiffies(ATBM_SPLIT_NEXT_CHANNEL_TIME));
return true;
#else
BUG_ON(hw_priv == NULL);
return false;
#endif
}
static int atbm_scan_start(struct atbm_vif *priv, struct wsm_scan *scan)
{
int ret, i;
int tmo = 5000;
struct atbm_common *hw_priv = ABwifi_vifpriv_to_hwpriv(priv);
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);
#ifndef CONFIG_WAKELOCK
#ifdef CONFIG_PM
atbm_pm_stay_awake(&hw_priv->pm_state, tmo * HZ / 1000);
#endif
#endif
atbm_hw_priv_queue_delayed_work(hw_priv, &hw_priv->scan.timeout,
tmo * HZ / 1000);
hw_priv->scan.wait_complete = 1;
#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)) {
hw_priv->scan.wait_complete = 0;
atomic_set(&hw_priv->scan.in_progress, 0);
atbm_hw_cancel_delayed_work(&hw_priv->scan.timeout,true);
// atbm_scan_restart_delayed(priv);
}
return ret;
}
#ifdef CONFIG_ATBM_SUPPORT_SCHED_SCAN
#ifdef ROAM_OFFLOAD
static int atbm_sched_scan_start(struct atbm_vif *priv, struct wsm_scan *scan)
{
int ret;
struct atbm_common *hw_priv = ABwifi_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*/
#endif
int atbm_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_scan_req_wrap *req_wrap)
{
struct atbm_common *hw_priv = hw->priv;
struct atbm_vif *priv = ABwifi_get_vif_from_ieee80211(vif);
struct wsm_template_frame frame = {
.frame_type = WSM_FRAME_TYPE_PROBE_REQUEST,
};
int i;
int ret = 0;
#ifdef CONFIG_ATBM_SUPPORT_P2P
int roc_if_id = 0;
#endif
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
u16 advance_scan_req_channel;
#endif
if(atbm_bh_is_term(hw_priv)){
return -EOPNOTSUPP;
}
if(atomic_read(&priv->enabled) == 0){
atbm_printk_err("%s:disabled\n",__func__);
return -EOPNOTSUPP;
}
/* Scan when P2P_GO corrupt firmware MiniAP mode */
if (priv->join_status == ATBM_APOLLO_JOIN_STATUS_AP)
{
return -EOPNOTSUPP;
}
#ifdef CONFIG_ATBM_SUPPORT_P2P
mutex_lock(&hw_priv->conf_mutex);
roc_if_id = hw_priv->roc_if_id;
mutex_unlock(&hw_priv->conf_mutex);
if (atbm_work_pending(&priv->offchannel_work) ||
(roc_if_id != -1)) {
atbm_printk_err( "[SCAN] Offchannel work pending,ignoring scan work %d\n",hw_priv->roc_if_id);
return -EBUSY;
}
#endif
if (req_wrap->req->n_ssids == 1 && !req_wrap->req->ssids[0].ssid_len)
req_wrap->req->n_ssids = 0;
atbm_printk_debug("[SCAN] Scan request for %d SSIDs.\n",req_wrap->req->n_ssids);
if (req_wrap->req->n_ssids > hw->wiphy->max_scan_ssids)
{
return -EINVAL;
}
frame.skb = ieee80211_probereq_get(hw, vif, NULL, 0,
req_wrap->req->ie, req_wrap->req->ie_len,
req_wrap->flags & IEEE80211_SCAN_REQ_NEED_BSSID ? req_wrap->bssid:NULL);
if (!frame.skb)
return -ENOMEM;
#ifdef CONFIG_ATBM_SUPPORT_P2P
#ifdef ATBM_P2P_CHANGE
atbm_parase_p2p_mgmt_frame(priv,frame.skb,true);
#endif
#endif
#ifdef CONFIG_ATBM_SUPPORT_SCHED_SCAN
#ifdef ROAM_OFFLOAD
if (priv->join_status != ATBM_APOLLO_JOIN_STATUS_STA) {
if (req_wrap->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_wrap->req->n_channels; i++) {
hw_priv->scan_channels[hw_priv->num_scanchannels + i].number = \
channel_hw_value(req_wrap->req->channels[i]);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0))
if (req_wrap->req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN)
#else
if (req_wrap->req->channels[i]->flags &IEEE80211_CHAN_NO_IR)
#endif
{
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 |= \
ATBM_APOLLO_SCAN_TYPE_ACTIVE;
}
hw_priv->scan_channels[hw_priv->num_scanchannels + i].txPowerLevel = \
req_wrap->req->channels[i]->max_power;
if (req_wrap->req->channels[0]->band == NL80211_BAND_5GHZ)
hw_priv->scan_channels[hw_priv->num_scanchannels + i].number |= \
ATBM_APOLLO_SCAN_BAND_5G;
}
if (req_wrap->req->channels[0]->band == NL80211_BAND_2GHZ)
hw_priv->num_2g_channels = req_wrap->req->n_channels;
else
hw_priv->num_5g_channels = req_wrap->req->n_channels;
}
hw_priv->num_scanchannels = hw_priv->num_2g_channels + hw_priv->num_5g_channels;
#endif /*ROAM_OFFLOAD*/
#endif
/*
*supplicant requres scan,we must stay awake.
*/
atbm_hold_suspend(hw_priv);
/* will be unlocked in atbm_scan_work() */
down(&hw_priv->scan.lock);
mutex_lock(&hw_priv->conf_mutex);
atbm_printk_scan("%s:if_id(%d)\n",__func__,priv->if_id);
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
/* Active Scan - Serving Channel Request Handling */
advance_scan_req_channel = channel_hw_value(req_wrap->req->channels[0]);
if (hw_priv->enable_advance_scan &&
(hw_priv->advanceScanElems.scanMode ==
ATBM_APOLLO_SCAN_MEASUREMENT_ACTIVE) &&
(priv->join_status == ATBM_APOLLO_JOIN_STATUS_STA) &&
(channel_hw_value(hw_priv->channel) == advance_scan_req_channel)) {
BUG_ON(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 = atbm_disable_filtering(priv);
if (ret)
atbm_printk_warn("%s: Disable BSSID or Beacon filtering failed: %d.\n",
__func__, ret);
wsm_unlock_tx(hw_priv);
mutex_unlock(&hw_priv->conf_mutex);
/* Transmit Probe Request with Broadcast SSID */
atbm_tx(hw, frame.skb);
/* Start Advance Scan Timer */
atbm_advance_scan_start(hw_priv);
} else {
#endif
if (frame.skb) {
#ifdef CONFIG_ATBM_SUPPORT_P2P
if (priv->if_id == 0)
atbm_remove_wps_p2p_ie(&frame);
#endif
#ifdef P2P_MULTIVIF
#ifdef ATBM_SUPPORT_WIDTH_40M
//#ifdef P2P_MULTIVIF
#ifdef CONFIG_ATBM_SUPPORT_P2P
if(priv->if_id&&(priv->vif->p2p==true))
{
struct atbm_ieee80211_mgmt *mgmt = (struct atbm_ieee80211_mgmt *)frame.skb->data;
atbm_printk_debug( "%s:atbm_clear_wpas_p2p_40M_ie,if_id(%d)\n",__func__,priv->if_id);
atbm_clear_wpas_p2p_40M_ie(mgmt,frame.skb->len);
}
#endif
//#endif
#endif
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) {
mutex_unlock(&hw_priv->conf_mutex);
up(&hw_priv->scan.lock);
atbm_dev_kfree_skb(frame.skb);
atbm_release_suspend(hw_priv);
return ret;
}
priv->tmpframe_probereq_set = 1;
}
// wsm_vif_lock_tx(priv);
/*
*must make sure that there are no pkgs in the lmc.
*/
wsm_lock_tx_async(hw_priv);
wsm_flush_tx(hw_priv);
BUG_ON(hw_priv->scan.req);
hw_priv->scan.req = req_wrap->req;
hw_priv->scan.req_wrap = req_wrap;
hw_priv->scan.n_ssids = 0;
hw_priv->scan.status = 0;
hw_priv->scan.begin = &req_wrap->req->channels[0];
hw_priv->scan.curr = hw_priv->scan.begin;
hw_priv->scan.end = &req_wrap->req->channels[req_wrap->req->n_channels];
hw_priv->scan.output_power = hw_priv->output_power;
hw_priv->scan.if_id = priv->if_id;
hw_priv->scan.passive = !!(req_wrap->flags & IEEE80211_SCAN_REQ_PASSIVE_SCAN);
hw_priv->scan.cca = !!(req_wrap->flags & IEEE80211_SCAN_REQ_CCA);
#ifdef CONFIG_ATBM_SCAN_SPLIT
hw_priv->scan.split = !!(req_wrap->flags & IEEE80211_SCAN_REQ_SPILT);
#endif
#ifdef CONFIG_ATBM_SUPPORT_P2P
#ifdef ATBM_P2P_CHANGE
/*
*when p2p scan for p2p go , must make sure that we have
*receive the p2p go beacon or probe resp.
*/
if((priv->if_id==1)&&(atomic_read(&hw_priv->go_bssid_set))){
hw_priv->p2p_scan_start_time = jiffies;
atomic_set(&hw_priv->receive_go_resp,0);
}
#endif
#endif
/* TODO:COMBO: Populate BIT4 in scanflags to decide on which MAC
* address the SCAN request will be sent */
for (i = 0; i < req_wrap->req->n_ssids; ++i) {
struct wsm_ssid *dst =
&hw_priv->scan.ssids[hw_priv->scan.n_ssids];
BUG_ON(req_wrap->req->ssids[i].ssid_len > sizeof(dst->ssid));
memcpy(&dst->ssid[0], req_wrap->req->ssids[i].ssid,
sizeof(dst->ssid));
dst->length = req_wrap->req->ssids[i].ssid_len;
++hw_priv->scan.n_ssids;
}
mutex_unlock(&hw_priv->conf_mutex);
if (frame.skb)
atbm_dev_kfree_skb(frame.skb);
atbm_printk_scan("%s:scan, delay suspend\n",__func__);
atbm_hw_priv_queue_work(hw_priv, &hw_priv->scan.work);
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
}
#endif
return 0;
}
#ifdef CONFIG_ATBM_SUPPORT_SCHED_SCAN
#ifdef ROAM_OFFLOAD
int atbm_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 atbm_common *hw_priv = hw->priv;
struct atbm_vif *priv = ABwifi_get_vif_from_ieee80211(vif);
struct wsm_template_frame frame = {
.frame_type = WSM_FRAME_TYPE_PROBE_REQUEST,
};
int i;
atbm_printk_warn("[SCAN] Scheduled scan request-->.\n");
if (!priv->vif)
return -EINVAL;
/* Scan when P2P_GO corrupt firmware MiniAP mode */
if (priv->join_status == ATBM_APOLLO_JOIN_STATUS_AP)
return -EOPNOTSUPP;
atbm_printk_warn("[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;
atbm_printk_debug("[SCAN] Scan request for %d SSIDs.\n",req->n_ssids);
if (req->n_ssids > hw->wiphy->max_scan_ssids)
return -EINVAL;
frame.skb = ieee80211_probereq_get(hw, priv->vif, NULL, 0,
ies->ie[0], ies->len[0],NULL);
if (!frame.skb)
return -ENOMEM;
/* will be unlocked in atbm_scan_work() */
down(&hw_priv->scan.lock);
mutex_lock(&hw_priv->conf_mutex);
if (frame.skb) {
int ret;
#ifdef CONFIG_ATBM_SUPPORT_P2P
if (priv->if_id == 0)
atbm_remove_wps_p2p_ie(&frame);
#endif
ret = wsm_set_template_frame(hw_priv, &frame, priv->if_id);
if (0 == ret) {
priv->tmpframe_probereq_set = 1;
/* Host want to be the probe responder. */
ret = wsm_set_probe_responder(priv, true);
}
if (ret) {
mutex_unlock(&hw_priv->conf_mutex);
up(&hw_priv->scan.lock);
atbm_dev_kfree_skb(frame.skb);
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;
atbm_printk_warn("[SCAN] SSID %d\n",i);
for(j=0; j<req->ssids[i].ssid_len; j++)
atbm_printk_warn("[SCAN] 0x%x\n", req->ssids[i].ssid[j]);
}
}
mutex_unlock(&hw_priv->conf_mutex);
if (frame.skb)
atbm_dev_kfree_skb(frame.skb);
atbm_hw_priv_queue_work(hw_priv, &hw_priv->scan.swork);
atbm_printk_warn("<--[SCAN] Scheduled scan request.\n");
return 0;
}
#endif /*ROAM_OFFLOAD*/
#endif
void atbm_scan_work(struct atbm_work_struct *work)
{
struct atbm_common *hw_priv = container_of(work,
struct atbm_common,
scan.work);
struct atbm_vif *priv;
#ifndef CONFIG_TX_NO_CONFIRM
struct atbm_vif *vif;
#endif
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;
u32 ProbeRequestTime = 10;
u32 ChannelRemainTime = 20;
u32 maxChannelTime;
int scan_status = 0;
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
int ret = 0;
u16 advance_scan_req_channel = channel_hw_value(hw_priv->scan.begin[0]);
#endif
priv = __ABwifi_hwpriv_to_vifpriv(hw_priv, hw_priv->scan.if_id);
/*TODO: COMBO: introduce locking so vif is not removed in meanwhile */
if (!priv) {
goto vif_err;
}
if (priv->if_id)
scan.scanFlags |= WSM_FLAG_MAC_INSTANCE_1;
else
scan.scanFlags &= ~WSM_FLAG_MAC_INSTANCE_1;
#ifndef CONFIG_TX_NO_CONFIRM
atbm_for_each_vif(hw_priv, vif, i) {
if (!vif)
continue;
if (vif->bss_loss_status > ATBM_APOLLO_BSS_LOSS_NONE)
scan.scanFlags |= WSM_SCAN_FLAG_FORCE_BACKGROUND;
}
#endif
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 (atbm_hw_cancel_delayed_work(&priv->join_timeout,true) > 0)
atbm_join_timeout(&priv->join_timeout.work);
}
mutex_lock(&hw_priv->conf_mutex);
if (first_run) {
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
/* Passive Scan - Serving Channel Request Handling */
if (hw_priv->enable_advance_scan &&
(hw_priv->advanceScanElems.scanMode ==
ATBM_APOLLO_SCAN_MEASUREMENT_PASSIVE) &&
(priv->join_status == ATBM_APOLLO_JOIN_STATUS_STA) &&
(channel_hw_value(hw_priv->channel) ==
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 = atbm_disable_filtering(priv);
if (ret)
atbm_printk_warn("%s: Disable BSSID or Beacon filtering failed: %d.\n",
__func__, ret);
} else if (hw_priv->enable_advance_scan &&
(hw_priv->advanceScanElems.scanMode ==
ATBM_APOLLO_SCAN_MEASUREMENT_PASSIVE) &&
(priv->join_status == ATBM_APOLLO_JOIN_STATUS_STA)) {
if (priv->join_status == ATBM_APOLLO_JOIN_STATUS_STA &&
!(priv->powersave_mode.pmMode & WSM_PSM_PS)) {
struct wsm_set_pm pm = priv->powersave_mode;
pm.pmMode = WSM_PSM_PS;
atbm_set_pm(priv, &pm);
}
} else {
#endif
if (priv->join_status == ATBM_APOLLO_JOIN_STATUS_MONITOR) {
/* FW bug: driver has to restart p2p-dev mode
* after scan */
#if defined(CONFIG_ATBM_STA_LISTEN) || defined(CONFIG_ATBM_SUPPORT_P2P)
atbm_disable_listening(priv);
#endif
}
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
}
#endif
}
if (!hw_priv->scan.req || (hw_priv->scan.curr == hw_priv->scan.end)) {
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
if (hw_priv->enable_advance_scan &&
(hw_priv->advanceScanElems.scanMode ==
ATBM_APOLLO_SCAN_MEASUREMENT_PASSIVE) &&
(priv->join_status == ATBM_APOLLO_JOIN_STATUS_STA) &&
(channel_hw_value(hw_priv->channel) ==
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);
atbm_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_ATBM_APOLLO_TESTMODE
}
}
#endif
#ifdef CONFIG_ATBM_SUPPORT_P2P
#ifndef ATBM_P2P_CHANGE
while(priv->scan_again)
{
int status;
priv->scan_again = 0;
scan.ch = atbm_kzalloc(
sizeof(struct wsm_scan_ch[3]),
GFP_KERNEL);
if (!scan.ch) {
break;
}
scan.numOfSSIDs = hw_priv->scan.n_ssids;
scan.numOfProbeRequests = 3;
maxChannelTime = (scan.numOfSSIDs * scan.numOfProbeRequests *
15) + 10;
maxChannelTime = (maxChannelTime < 35) ? 35 : maxChannelTime;
scan.ch[0].number = 1;
scan.ch[0].maxChannelTime = maxChannelTime;
scan.ch[0].minChannelTime = 35;
scan.ch[1].number = 6;
scan.ch[1].maxChannelTime = maxChannelTime;
scan.ch[1].minChannelTime = 35;
scan.ch[2].number = 11;
scan.ch[2].maxChannelTime = maxChannelTime;
scan.ch[2].minChannelTime = 35;
scan.ssids = &hw_priv->scan.ssids[0];
scan.probeDelay = 15;
scan.numOfChannels = 3;
scan.band = IEEE80211_BAND_2GHZ;
status = atbm_scan_start(priv, &scan);
atbm_kfree(scan.ch);
if(status)
break;
mutex_unlock(&hw_priv->conf_mutex);
return;
}
#else
while((hw_priv->scan.if_id == 1)&&(atomic_read(&hw_priv->go_bssid_set) == 1)&&
(atomic_read(&hw_priv->receive_go_resp) == 0))
{
int status;
atbm_printk_scan("%s:p2p scan again,channel(%d)\n",__func__,atomic_read(&hw_priv->p2p_oper_channel));
if(atomic_read(&hw_priv->p2p_oper_channel) == 0){
break;
}
if(!time_is_after_jiffies(hw_priv->p2p_scan_start_time+2*HZ)){
atomic_set(&hw_priv->go_bssid_set,0);
atomic_set(&hw_priv->p2p_oper_channel,0);
break;
}
scan.ch = atbm_kzalloc(
sizeof(struct wsm_scan_ch[5]),
GFP_KERNEL);
if (!scan.ch) {
break;
}
scan.numOfSSIDs = hw_priv->scan.n_ssids;
scan.numOfProbeRequests = 3;
#if 0
maxChannelTime = (scan.numOfSSIDs * scan.numOfProbeRequests *
15) + 10;
maxChannelTime = (maxChannelTime < 35) ? 35 : maxChannelTime;
#else
maxChannelTime = 110;
#endif
scan.ch[0].number = atomic_read(&hw_priv->p2p_oper_channel);
scan.ch[0].maxChannelTime = maxChannelTime;
scan.ch[0].minChannelTime = 35;
scan.ch[1].number = 1;//atomic_read(&hw_priv->p2p_oper_channel);
scan.ch[1].maxChannelTime = maxChannelTime;
scan.ch[1].minChannelTime = 35;
scan.ch[2].number = 6;//atomic_read(&hw_priv->p2p_oper_channel);
scan.ch[2].maxChannelTime = maxChannelTime;
scan.ch[2].minChannelTime = 35;
scan.ch[3].number = 11;//atomic_read(&hw_priv->p2p_oper_channel);
scan.ch[3].maxChannelTime = maxChannelTime;
scan.ch[3].minChannelTime = 35;
scan.maxTransmitRate = WSM_TRANSMIT_RATE_6;
scan.ch[4].number = atomic_read(&hw_priv->p2p_oper_channel);
scan.ch[4].maxChannelTime = maxChannelTime;
scan.ch[4].minChannelTime = 35;
scan.ssids = &hw_priv->scan.ssids[0];
scan.probeDelay = 15;
scan.numOfChannels = 5;
scan.band = IEEE80211_BAND_2GHZ;
status = atbm_scan_start(priv, &scan);
atbm_kfree(scan.ch);
if(status)
break;
mutex_unlock(&hw_priv->conf_mutex);
return;
}
#endif
#endif
if (hw_priv->scan.status < 0)
atbm_printk_debug("[SCAN] Scan failed (%d).\n",hw_priv->scan.status);
else if (hw_priv->scan.req)
atbm_printk_debug("[SCAN] Scan completed.\n");
else
atbm_printk_debug("[SCAN] Scan canceled.\n");
hw_priv->scan.req = NULL;
hw_priv->scan.cca = 0;
hw_priv->scan.req_wrap = NULL;
atbm_printk_scan("%s:end(%d)\n",__func__,hw_priv->scan.if_id);
atbm_scan_restart_delayed(priv);
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
hw_priv->enable_advance_scan = false;
#endif /* CONFIG_ATBM_APOLLO_TESTMODE */
wsm_unlock_tx(hw_priv);
mutex_unlock(&hw_priv->conf_mutex);
ieee80211_scan_completed(hw_priv->hw,
hw_priv->scan.status ? 1 : 0);
up(&hw_priv->scan.lock);
atbm_release_suspend(hw_priv);
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;
#ifdef CONFIG_ATBM_SCAN_SPLIT
if((hw_priv->scan.split == 1) && (i >= ATBM_SPLIT_SCAN_MAX_CHANNEL))
break;
#endif
#ifdef WIFI_ALLIANCE_CERTIF
if (((*it)->flags ^ first->flags) &
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0))
IEEE80211_CHAN_PASSIVE_SCAN
#else
IEEE80211_CHAN_NO_IR
#endif
)
break;
if (!(first->flags &
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0))
IEEE80211_CHAN_PASSIVE_SCAN
#else
IEEE80211_CHAN_NO_IR
#endif
) &&
(*it)->max_power != first->max_power)
break;
#endif //WIFI_ALLIANCE_CERTIF
}
scan.band = first->band;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
if (hw_priv->scan.req->no_cck)
scan.maxTransmitRate = WSM_TRANSMIT_RATE_6;
else
#endif
scan.maxTransmitRate = WSM_TRANSMIT_RATE_1;
if (priv->if_id&&priv->vif->p2p){
scan.maxTransmitRate = WSM_TRANSMIT_RATE_6;
}
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
if (hw_priv->enable_advance_scan) {
if (hw_priv->advanceScanElems.scanMode ==
ATBM_APOLLO_SCAN_MEASUREMENT_PASSIVE)
scan.numOfProbeRequests = 0;
else
scan.numOfProbeRequests = 1;
} else {
#endif
/* TODO: Is it optimal? */
#ifndef CONFIG_ATBM_5G_PRETEND_2G
scan.numOfProbeRequests =
(first->flags &
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0))
IEEE80211_CHAN_PASSIVE_SCAN
#else
IEEE80211_CHAN_NO_IR
#endif
)
? 0 : 3;
#else
scan.numOfProbeRequests = 3;
#endif
if(hw_priv->scan.cca == 1)
scan.numOfProbeRequests = 1;
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
}
#endif /* CONFIG_ATBM_APOLLO_TESTMODE */
/*
*passive scan
*/
if(hw_priv->scan.passive)
scan.numOfProbeRequests = 0;
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? */
if(scan.numOfChannels == 3)
{
ProbeRequestTime = 10;
ChannelRemainTime = 10;
}
scan.probeDelay = ProbeRequestTime;
/* It is not stated in WSM specification, however
* FW team says that driver may not use FG scan
* when joined. */
if (priv->join_status == ATBM_APOLLO_JOIN_STATUS_STA) {
scan.scanType = WSM_SCAN_TYPE_BACKGROUND;
scan.scanFlags = WSM_SCAN_FLAG_FORCE_BACKGROUND;
}
if(hw_priv->scan.cca == 1){
scan.scanFlags |= WSM_FLAG_BEST_CHANNEL_START;
}
scan.ch = atbm_kzalloc(
sizeof(struct wsm_scan_ch[it - hw_priv->scan.curr]),
GFP_KERNEL);
if (!scan.ch) {
hw_priv->scan.status = -ENOMEM;
goto fail;
}
maxChannelTime = (scan.numOfSSIDs * scan.numOfProbeRequests *
ProbeRequestTime) + ChannelRemainTime;
maxChannelTime = (maxChannelTime < 35) ? 35 : maxChannelTime;
for (i = 0; i < scan.numOfChannels; ++i) {
scan.ch[i].number = channel_hw_value(hw_priv->scan.curr[i]);
#ifdef CONFIG_ATBM_APOLLO_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 (LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0))
if (hw_priv->scan.curr[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN)
#else
if (hw_priv->scan.curr[i]->flags & IEEE80211_CHAN_NO_IR)
#endif
{
scan.ch[i].minChannelTime = 50;
scan.ch[i].maxChannelTime = 110;
}
else {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
if (hw_priv->scan.req->no_cck)
scan.ch[i].minChannelTime = 35;
else
#endif //#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
scan.ch[i].minChannelTime = 15;
scan.ch[i].maxChannelTime = maxChannelTime;
}
if(hw_priv->scan.cca == 1){
scan.ch[i].maxChannelTime = 500;
}
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
}
#endif
}
/*
if((priv->if_id == 1)&&(priv->join_status<=ATBM_APOLLO_JOIN_STATUS_MONITOR))
if(i>=14)
{
scan.ch[i-1].number = scan.ch[0].number;
scan.ch[i-1].maxChannelTime = scan.ch[0].maxChannelTime;
scan.ch[i-1].minChannelTime = scan.ch[0].minChannelTime;
}
*/
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
if (!hw_priv->enable_advance_scan) {
#endif
if (
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0))
!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN)
#else
!(first->flags & IEEE80211_CHAN_NO_IR)
#endif
&&
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_ATBM_APOLLO_TESTMODE
}
#endif
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
if (hw_priv->enable_advance_scan &&
(hw_priv->advanceScanElems.scanMode ==
ATBM_APOLLO_SCAN_MEASUREMENT_PASSIVE) &&
(priv->join_status == ATBM_APOLLO_JOIN_STATUS_STA) &&
(channel_hw_value(hw_priv->channel)== advance_scan_req_channel)) {
/* Start Advance Scan Timer */
hw_priv->scan.status = atbm_advance_scan_start(hw_priv);
wsm_unlock_tx(hw_priv);
} else
#endif
/*
*sometimes,t920 take a long time to scan,and
*the usb recive process run too slowly.if that
*happens,can triger some errors.
*/
//hw_priv->scan.status = atbm_scan_start(priv, &scan);
atbm_printk_scan("scan start band(%d),(%d)\n",scan.band,scan.numOfChannels);
scan_status = atbm_scan_start(priv, &scan);
atbm_kfree(scan.ch);
if (WARN_ON(scan_status)){
hw_priv->scan.status = scan_status;
goto fail;
}
#ifdef CONFIG_ATBM_SUPPORT_P2P
#ifndef ATBM_P2P_CHANGE
if((priv->if_id == 1)&&(priv->join_status<=ATBM_APOLLO_JOIN_STATUS_MONITOR)&&(priv->scan_again == 0))
{
priv->scan_again = 1;
}
else
{
priv->scan_again = 0;
}
#endif
#endif
hw_priv->scan.curr = it;
}
mutex_unlock(&hw_priv->conf_mutex);
return;
fail:
hw_priv->scan.curr = hw_priv->scan.end;
mutex_unlock(&hw_priv->conf_mutex);
atbm_hw_priv_queue_work(hw_priv, &hw_priv->scan.work);
return;
vif_err:
hw_priv->scan.req = NULL;
hw_priv->scan.cca = 0;
hw_priv->scan.req_wrap = NULL;
up(&hw_priv->scan.lock);
wsm_unlock_tx(hw_priv);
atbm_printk_err("[SCAN] interface removed\n");
ieee80211_scan_completed(hw_priv->hw,
hw_priv->scan.status ? 1 : 0);
atbm_release_suspend(hw_priv);
return;
}
#ifdef CONFIG_ATBM_SUPPORT_SCHED_SCAN
#ifdef ROAM_OFFLOAD
void atbm_sched_scan_work(struct atbm_work_struct *work)
{
struct atbm_common *hw_priv = container_of(work, struct atbm_common,
scan.swork);
struct wsm_scan scan;
struct wsm_ssid scan_ssid;
int i;
struct atbm_vif *priv = ABwifi_hwpriv_to_vifpriv(hw_priv,
hw_priv->scan.if_id);
if (unlikely(!priv)) {
WARN_ON(1);
return;
}
atbm_priv_vif_list_read_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 (atbm_hw_cancel_delayed_work(&priv->join_timeout,true) > 0) {
atbm_join_timeout(&priv->join_timeout.work);
}
mutex_lock(&hw_priv->conf_mutex);
hw_priv->auto_scanning = 1;
scan.band = 0;
if (priv->join_status == ATBM_APOLLO_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 = 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 = atbm_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 = atbm_sched_scan_start(priv, &scan);
atbm_kfree(scan.ch);
if (hw_priv->scan.status)
goto fail;
mutex_unlock(&hw_priv->conf_mutex);
return;
fail:
mutex_unlock(&hw_priv->conf_mutex);
atbm_hw_priv_queue_work(hw_priv, &hw_priv->scan.swork);
return;
}
void atbm_hw_sched_scan_stop(struct atbm_common *hw_priv)
{
struct atbm_vif *priv = ABwifi_hwpriv_to_vifpriv(hw_priv,
hw_priv->scan.if_id);
if (unlikely(!priv))
return;
atbm_priv_vif_list_read_unlock(&priv->vif_lock);
wsm_stop_scan(hw_priv, priv->if_id);
return;
}
#endif /*ROAM_OFFLOAD*/
#endif
static void atbm_scan_restart_delayed(struct atbm_vif *priv)
{
struct atbm_common *hw_priv = ABwifi_vifpriv_to_hwpriv(priv);
struct atbm_vif *priv_delay = NULL;
u8 i = 0;
atbm_for_each_vif(hw_priv, priv_delay, i) {
if (priv_delay == NULL)
continue;
if(!(
#ifndef CONFIG_TX_NO_CONFIRM
(priv_delay->delayed_link_loss) ||
#endif
(priv_delay->delayed_unjoin) ||
(priv_delay->join_status == ATBM_APOLLO_JOIN_STATUS_MONITOR)
)
)
continue;
atbm_printk_scan("%s:if_id(%d),scan_id(%d),join_status(%d),delayed_unjoin(%d)\n",
__func__,priv_delay->if_id,hw_priv->scan.if_id,priv_delay->join_status,priv_delay->delayed_unjoin);
#ifndef CONFIG_TX_NO_CONFIRM
if (priv_delay->delayed_link_loss) {
int tmo = priv_delay->cqm_beacon_loss_count;
if (hw_priv->scan.direct_probe)
tmo = 0;
priv_delay->delayed_link_loss = 0;
/* Restart beacon loss timer and requeue
BSS loss work. */
atbm_printk_debug("[CQM] Requeue BSS loss in %d ""beacons.\n", tmo);
spin_lock_bh(&priv_delay->bss_loss_lock);
priv_delay->bss_loss_status = ATBM_APOLLO_BSS_LOSS_NONE;
spin_unlock_bh(&priv_delay->bss_loss_lock);
atbm_hw_cancel_delayed_work(&priv_delay->bss_loss_work,false);
atbm_hw_priv_queue_delayed_work(hw_priv,
&priv_delay->bss_loss_work,
tmo * HZ / 10);
}
#endif
/* FW bug: driver has to restart p2p-dev mode after scan. */
if (priv_delay->join_status == ATBM_APOLLO_JOIN_STATUS_MONITOR) {
/*atbm_enable_listening(priv);*/
// WARN_ON(1);
atbm_update_filtering(priv_delay);
}
if (priv_delay->delayed_unjoin) {
priv_delay->delayed_unjoin = false;
atbm_printk_scan("%s:restart delayed_unjoin\n",__func__);
#if 1
wsm_lock_tx_async(hw_priv);
#endif
if (atbm_hw_priv_queue_work(hw_priv, &priv_delay->unjoin_work) <= 0)
wsm_unlock_tx(hw_priv);
}
}
}
#ifdef CONFIG_ATBM_SUPPORT_P2P
void atbm_scan_listenning_restart_delayed(struct atbm_vif *priv)
{
atbm_scan_restart_delayed(priv);
}
#endif
static void atbm_scan_complete(struct atbm_common *hw_priv, int if_id)
{
struct atbm_vif *priv;
atomic_xchg(&hw_priv->recent_scan, 0);
if (hw_priv->scan.direct_probe) {
mutex_lock(&hw_priv->conf_mutex);
priv = __ABwifi_hwpriv_to_vifpriv(hw_priv, if_id);
if (priv) {
atbm_printk_debug("[SCAN] Direct probe complete.\n");
atbm_scan_restart_delayed(priv);
} else {
atbm_printk_debug("[SCAN] Direct probe complete without interface!\n");
}
mutex_unlock(&hw_priv->conf_mutex);
hw_priv->scan.direct_probe = 0;
up(&hw_priv->scan.lock);
wsm_unlock_tx(hw_priv);
} else if(atbm_scan_split_running(hw_priv) == false){
atbm_scan_work(&hw_priv->scan.work);
}else {
#ifndef CONFIG_ATBM_SCAN_SPLIT
BUG_ON(1);
#endif
}
}
void atbm_scan_complete_cb(struct atbm_common *hw_priv,
struct wsm_scan_complete *arg)
{
struct atbm_vif *priv = ABwifi_hwpriv_to_vifpriv(hw_priv,
hw_priv->scan.if_id);
if (unlikely(!priv))
{
return;
}
#ifdef CONFIG_ATBM_SUPPORT_SCHED_SCAN
#ifdef ROAM_OFFLOAD
if (hw_priv->auto_scanning)
atbm_hw_priv_queue_delayed_work(hw_priv,
&hw_priv->scan.timeout, 0);
#endif /*ROAM_OFFLOAD*/
#endif
if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) {
/* STA is stopped. */
atbm_priv_vif_list_read_unlock(&priv->vif_lock);
atbm_printk_err("[SCAN] mode err\n");
return;
}
atbm_priv_vif_list_read_unlock(&priv->vif_lock);
//printk("hw_priv->bStartTx %d\n",hw_priv->bStartTx);
if(hw_priv->bStartTx)
{
atbm_hw_priv_queue_delayed_work(hw_priv,&hw_priv->scan.timeout, HZ/10);
return;
}
#ifdef ATBM_SUPPORT_SMARTCONFIG
priv->scan_no_connect=priv->scan_no_connect_back;
if (hw_priv->scan.scan_smartconfig){
//printk("**%s %d**\n", __FUNCTION__, hw_priv->scan.scan_smartconfig);
smartconfig_magic_scan_done(hw_priv);
return ;
}
#endif
atbm_printk_scan("hw_priv->scan.status %d\n",hw_priv->scan.status);
if(hw_priv->scan.status == -ETIMEDOUT)
atbm_printk_warn("Scan timeout already occured. Don't cancel work");
if ((hw_priv->scan.status != -ETIMEDOUT) &&
(atbm_hw_cancel_delayed_work(&hw_priv->scan.timeout,false/*can't set to true,because this function is call in bh, must not wait in bh */) > 0)) {
hw_priv->scan.status = 1;
if(hw_priv->scan.cca){
struct ieee80211_internal_scan_notity notify;
notify.cca.val = arg->busy_ratio;
notify.cca.val_len = sizeof(arg->busy_ratio);
notify.success = true;
ieee80211_scan_cca_notify(hw_priv->hw,&notify);
}
#ifdef SIGMSTAR_SCAN_FEATURE
else {
int i;
struct ieee80211_local *local = hw_to_local(hw_priv->hw);
for(i=0;(i<CHANNEL_NUM)&&(i<14);i++){
local->noise_floor[i] = arg->busy_ratio[i];
}
}
#endif //#ifdef SIGMSTAR_SCAN_FEATURE
atbm_hw_priv_queue_delayed_work(hw_priv,
&hw_priv->scan.timeout, 0);
}
}
//#ifdef CONFIG_WIRELESS_EXT
extern int wsm_start_scan_etf(struct atbm_common *hw_priv, struct ieee80211_vif *vif );
void etf_scan_end_work(struct atbm_work_struct *work)
{
struct atbm_common *hw_priv =
container_of(work, struct atbm_common, etf_tx_end_work);
struct atbm_vif *priv = __ABwifi_hwpriv_to_vifpriv(hw_priv,
hw_priv->scan.if_id);
etf_v2_scan_end(hw_priv,priv->vif);
}
//#endif //CONFIG_WIRELESS_EXT
void atbm_scan_timeout(struct atbm_work_struct *work)
{
struct atbm_common *hw_priv =
container_of(work, struct atbm_common, scan.timeout.work);
//#ifdef CONFIG_WIRELESS_EXT
if(hw_priv->bStartTx)
{
struct atbm_vif *priv = __ABwifi_hwpriv_to_vifpriv(hw_priv,
hw_priv->scan.if_id);
if(hw_priv->bStartTxWantCancel==0){
wsm_start_scan_etf(hw_priv,priv->vif);
}
else {
hw_priv->bStartTx = 0;
hw_priv->bStartTxWantCancel = 0;
if(hw_priv->etf_test_v2){
atbm_hw_priv_queue_work(hw_priv, &hw_priv->etf_tx_end_work);
}
//stop etf test
//up(&hw_priv->scan.lock);
//printk("atbm_scan_timeout bStartTx %d\n",hw_priv->bStartTx);
}
return;
}
//#endif //CONFIG_WIRELESS_EXT
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) {
atbm_printk_warn("Timeout waiting for scan "
"complete notification.\n");
hw_priv->scan.status = -ETIMEDOUT;
hw_priv->scan.curr = hw_priv->scan.end;
if(WARN_ON(wsm_stop_scan(hw_priv,
hw_priv->scan.if_id ? 1 : 0)))
{
hw_priv->scan.wait_complete= 0;
//#ifndef OPER_CLOCK_USE_SEM
//mutex_unlock(&hw_priv->wsm_oper_lock);
//#else
//up(&hw_priv->wsm_oper_lock);
//#endif
wsm_oper_unlock(hw_priv);
}
}
atbm_scan_complete(hw_priv, hw_priv->scan.if_id);
#ifdef CONFIG_ATBM_SUPPORT_SCHED_SCAN
#ifdef ROAM_OFFLOAD
} else if (hw_priv->auto_scanning) {
hw_priv->auto_scanning = 0;
ieee80211_sched_scan_results(hw_priv->hw);
#endif /*ROAM_OFFLOAD*/
#endif
}
}
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
void atbm_advance_scan_timeout(struct atbm_work_struct *work)
{
struct atbm_common *hw_priv =
container_of(work, struct atbm_common, advance_scan_timeout.work);
struct atbm_vif *priv = ABwifi_hwpriv_to_vifpriv(hw_priv,
hw_priv->scan.if_id);
if (WARN_ON(!priv))
return;
atbm_priv_vif_list_read_unlock(&priv->vif_lock);
hw_priv->scan.status = 0;
if (hw_priv->advanceScanElems.scanMode ==
ATBM_APOLLO_SCAN_MEASUREMENT_PASSIVE) {
/* Passive Scan on Serving Channel
* Timer Expire */
atbm_scan_complete(hw_priv, hw_priv->scan.if_id);
} else {
/* Active Scan on Serving Channel
* Timer Expire */
mutex_lock(&hw_priv->conf_mutex);
//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;
atbm_update_filtering(priv);
hw_priv->enable_advance_scan = false;
wsm_unlock_tx(hw_priv);
mutex_unlock(&hw_priv->conf_mutex);
ieee80211_scan_completed(hw_priv->hw,
hw_priv->scan.status ? true : false);
up(&hw_priv->scan.lock);
}
}
#endif
void atbm_probe_work(struct atbm_work_struct *work)
{
struct atbm_common *hw_priv =
container_of(work, struct atbm_common, scan.probe_work.work);
struct atbm_vif *priv;
#ifndef CONFIG_TX_NO_CONFIRM
struct atbm_vif *vif;
#endif
u8 queueId = atbm_queue_get_queue_id(hw_priv->pending_frame_id);
struct atbm_queue *queue = &hw_priv->tx_queue[queueId];
const struct atbm_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 = 1,
.probeDelay = 0,
.numOfChannels = 1,
.ssids = ssids,
.ch = ch,
};
u8 *ies;
size_t ies_len;
int ret = 1;
#ifndef CONFIG_TX_NO_CONFIRM
int i;
#endif
atbm_printk_scan("[SCAN] Direct probe work.\n");
BUG_ON(queueId >= 4);
BUG_ON(!hw_priv->channel);
if(atbm_bh_is_term(hw_priv))
{
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
BUG_ON(atbm_queue_remove(hw_priv, queue,
hw_priv->pending_frame_id));
#else
BUG_ON(atbm_queue_remove(queue, hw_priv->pending_frame_id));
#endif
wsm_unlock_tx(hw_priv);
return;
}
mutex_lock(&hw_priv->conf_mutex);
if (unlikely(down_trylock(&hw_priv->scan.lock))) {
/* Scan is already in progress. Requeue self. */
if (unlikely(atomic_read(&hw_priv->scan.in_progress))){
schedule();
atbm_hw_priv_queue_delayed_work(hw_priv,
&hw_priv->scan.probe_work, HZ / 10);
mutex_unlock(&hw_priv->conf_mutex);
atbm_printk_scan("%s:scanning so delay work\n",__func__);
}
else{
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
BUG_ON(atbm_queue_remove(hw_priv, queue,
hw_priv->pending_frame_id));
#else
BUG_ON(atbm_queue_remove(queue, hw_priv->pending_frame_id));
#endif
wsm_unlock_tx(hw_priv);
mutex_unlock(&hw_priv->conf_mutex);
atbm_printk_scan("%s:listenning or other delete pendding frame\n",__func__);
}
return;
}
if (atbm_queue_get_skb(queue, hw_priv->pending_frame_id,
&frame.skb, &txpriv)) {
up(&hw_priv->scan.lock);
mutex_unlock(&hw_priv->conf_mutex);
wsm_unlock_tx(hw_priv);
atbm_printk_err("[SCAN] Direct probe work. return\n");
return;
}
priv = __ABwifi_hwpriv_to_vifpriv(hw_priv, txpriv->if_id);
if (!priv) {
up(&hw_priv->scan.lock);
mutex_unlock(&hw_priv->conf_mutex);
atbm_printk_err("[SCAN] Direct probe work. !priv\n");
return;
}
wsm = (struct wsm_tx *)frame.skb->data;
scan.maxTransmitRate = wsm->maxTxRate;
scan.band = (hw_priv->channel->band == IEEE80211_BAND_5GHZ) ?
WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G;
if (priv->join_status == ATBM_APOLLO_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;
}
#ifndef CONFIG_TX_NO_CONFIRM
atbm_for_each_vif(hw_priv, vif, i) {
if (!vif)
continue;
if (vif->bss_loss_status > ATBM_APOLLO_BSS_LOSS_NONE)
scan.scanFlags |= WSM_SCAN_FLAG_FORCE_BACKGROUND;
}
#endif
ch[0].number = channel_hw_value(hw_priv->channel);
atbm_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(ATBM_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 atbm_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);
atbm_skb_trim(frame.skb, frame.skb->len - ssids[0].length);
}
}
#ifdef CONFIG_ATBM_SUPPORT_P2P
if (priv->if_id == 0)
atbm_remove_wps_p2p_ie(&frame);
#endif
/* FW bug: driver has to restart p2p-dev mode after scan */
if (priv->join_status == ATBM_APOLLO_JOIN_STATUS_MONITOR) {
WARN_ON(1);
/*atbm_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;
hw_priv->scan.status = 0;
priv->tmpframe_probereq_set = 1;
if (!ret) {
wsm_flush_tx(hw_priv);
ret = WARN_ON(atbm_scan_start(priv, &scan));
}
mutex_unlock(&hw_priv->conf_mutex);
atbm_skb_push(frame.skb, txpriv->offset);
if (!ret)
IEEE80211_SKB_CB(frame.skb)->flags |= IEEE80211_TX_STAT_ACK;
#ifdef CONFIG_ATBM_APOLLO_TESTMODE
(atbm_queue_remove(hw_priv, queue,hw_priv->pending_frame_id));
#else
(atbm_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;
}
void atbm_wait_scan_complete_sync(struct atbm_common *hw_priv)
{
down(&hw_priv->scan.lock);
mutex_lock(&hw_priv->conf_mutex);
/*
*here wait scan completed
*/
mutex_unlock(&hw_priv->conf_mutex);
up(&hw_priv->scan.lock);
atbm_printk_scan( "%s\n",__func__);
}
void atbm_cancel_hw_scan(struct ieee80211_hw *hw,struct ieee80211_vif *vif)
{
struct atbm_common *hw_priv = hw->priv;
struct atbm_vif *priv = ABwifi_get_vif_from_ieee80211(vif);
atbm_printk_scan( "%s:[%d]\n",__func__,priv->if_id);
atbm_wait_scan_complete_sync(hw_priv);
}