提交 0c9b7f22 编写于 作者: X Xinming Hu 提交者: Kalle Valo

mwifiex: add schedule scan support

This patch add sched scan support for mwifiex, include cfg80211
sched_scan_start/sched_scan_stop handler, corresponding bgscan
command path and event handler.
Signed-off-by: NXinming Hu <huxm@marvell.com>
Signed-off-by: Nchunfan chen <jeffc@marvell.com>
Signed-off-by: NCathy Luo <cluo@marvell.com>
Signed-off-by: NAmitkumar Karwar <akarwar@marvell.com>
Signed-off-by: NKalle Valo <kvalo@codeaurora.org>
上级 dc896b15
...@@ -1962,6 +1962,9 @@ mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, ...@@ -1962,6 +1962,9 @@ mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
{ {
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
if (!mwifiex_stop_bg_scan(priv))
cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy);
if (mwifiex_deauthenticate(priv, NULL)) if (mwifiex_deauthenticate(priv, NULL))
return -EFAULT; return -EFAULT;
...@@ -2217,6 +2220,9 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ...@@ -2217,6 +2220,9 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
"info: Trying to associate to %s and bssid %pM\n", "info: Trying to associate to %s and bssid %pM\n",
(char *)sme->ssid, sme->bssid); (char *)sme->ssid, sme->bssid);
if (!mwifiex_stop_bg_scan(priv))
cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy);
ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid, ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid,
priv->bss_mode, sme->channel, sme, 0); priv->bss_mode, sme->channel, sme, 0);
if (!ret) { if (!ret) {
...@@ -2420,6 +2426,9 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, ...@@ -2420,6 +2426,9 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
return -EBUSY; return -EBUSY;
} }
if (!mwifiex_stop_bg_scan(priv))
cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy);
user_scan_cfg = kzalloc(sizeof(*user_scan_cfg), GFP_KERNEL); user_scan_cfg = kzalloc(sizeof(*user_scan_cfg), GFP_KERNEL);
if (!user_scan_cfg) if (!user_scan_cfg)
return -ENOMEM; return -ENOMEM;
...@@ -2487,6 +2496,121 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, ...@@ -2487,6 +2496,121 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
return 0; return 0;
} }
/* CFG802.11 operation handler for sched_scan_start.
*
* This function issues a bgscan config request to the firmware based upon
* the user specified sched_scan configuration. On successful completion,
* firmware will generate BGSCAN_REPORT event, driver should issue bgscan
* query command to get sched_scan results from firmware.
*/
static int
mwifiex_cfg80211_sched_scan_start(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_sched_scan_request *request)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
int i, offset;
struct ieee80211_channel *chan;
struct mwifiex_bg_scan_cfg *bgscan_cfg;
struct ieee_types_header *ie;
if (!request || (!request->n_ssids && !request->n_match_sets)) {
wiphy_err(wiphy, "%s : Invalid Sched_scan parameters",
__func__);
return -EINVAL;
}
wiphy_info(wiphy, "sched_scan start : n_ssids=%d n_match_sets=%d ",
request->n_ssids, request->n_match_sets);
wiphy_info(wiphy, "n_channels=%d interval=%d ie_len=%d\n",
request->n_channels, request->scan_plans->interval,
(int)request->ie_len);
bgscan_cfg = kzalloc(sizeof(*bgscan_cfg), GFP_KERNEL);
if (!bgscan_cfg)
return -ENOMEM;
if (priv->scan_request || priv->scan_aborting)
bgscan_cfg->start_later = true;
bgscan_cfg->num_ssids = request->n_match_sets;
bgscan_cfg->ssid_list = request->match_sets;
if (request->ie && request->ie_len) {
offset = 0;
for (i = 0; i < MWIFIEX_MAX_VSIE_NUM; i++) {
if (priv->vs_ie[i].mask != MWIFIEX_VSIE_MASK_CLEAR)
continue;
priv->vs_ie[i].mask = MWIFIEX_VSIE_MASK_BGSCAN;
ie = (struct ieee_types_header *)(request->ie + offset);
memcpy(&priv->vs_ie[i].ie, ie, sizeof(*ie) + ie->len);
offset += sizeof(*ie) + ie->len;
if (offset >= request->ie_len)
break;
}
}
for (i = 0; i < min_t(u32, request->n_channels,
MWIFIEX_BG_SCAN_CHAN_MAX); i++) {
chan = request->channels[i];
bgscan_cfg->chan_list[i].chan_number = chan->hw_value;
bgscan_cfg->chan_list[i].radio_type = chan->band;
if ((chan->flags & IEEE80211_CHAN_NO_IR) || !request->n_ssids)
bgscan_cfg->chan_list[i].scan_type =
MWIFIEX_SCAN_TYPE_PASSIVE;
else
bgscan_cfg->chan_list[i].scan_type =
MWIFIEX_SCAN_TYPE_ACTIVE;
bgscan_cfg->chan_list[i].scan_time = 0;
}
bgscan_cfg->chan_per_scan = min_t(u32, request->n_channels,
MWIFIEX_BG_SCAN_CHAN_MAX);
/* Use at least 15 second for per scan cycle */
bgscan_cfg->scan_interval = (request->scan_plans->interval >
MWIFIEX_BGSCAN_INTERVAL) ?
request->scan_plans->interval :
MWIFIEX_BGSCAN_INTERVAL;
bgscan_cfg->repeat_count = MWIFIEX_BGSCAN_REPEAT_COUNT;
bgscan_cfg->report_condition = MWIFIEX_BGSCAN_SSID_MATCH |
MWIFIEX_BGSCAN_WAIT_ALL_CHAN_DONE;
bgscan_cfg->bss_type = MWIFIEX_BSS_MODE_INFRA;
bgscan_cfg->action = MWIFIEX_BGSCAN_ACT_SET;
bgscan_cfg->enable = true;
if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_BG_SCAN_CONFIG,
HostCmd_ACT_GEN_SET, 0, bgscan_cfg, true)) {
kfree(bgscan_cfg);
return -EFAULT;
}
priv->sched_scanning = true;
kfree(bgscan_cfg);
return 0;
}
/* CFG802.11 operation handler for sched_scan_stop.
*
* This function issues a bgscan config command to disable
* previous bgscan configuration in the firmware
*/
static int mwifiex_cfg80211_sched_scan_stop(struct wiphy *wiphy,
struct net_device *dev)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
wiphy_info(wiphy, "sched scan stop!");
mwifiex_stop_bg_scan(priv);
return 0;
}
static void mwifiex_setup_vht_caps(struct ieee80211_sta_vht_cap *vht_info, static void mwifiex_setup_vht_caps(struct ieee80211_sta_vht_cap *vht_info,
struct mwifiex_private *priv) struct mwifiex_private *priv)
{ {
...@@ -2848,6 +2972,9 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) ...@@ -2848,6 +2972,9 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
mwifiex_dev_debugfs_remove(priv); mwifiex_dev_debugfs_remove(priv);
#endif #endif
if (priv->sched_scanning)
priv->sched_scanning = false;
mwifiex_stop_net_dev_queue(priv->netdev, adapter); mwifiex_stop_net_dev_queue(priv->netdev, adapter);
skb_queue_walk_safe(&priv->bypass_txq, skb, tmp) skb_queue_walk_safe(&priv->bypass_txq, skb, tmp)
...@@ -3701,6 +3828,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { ...@@ -3701,6 +3828,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
.set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config, .set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config,
.set_antenna = mwifiex_cfg80211_set_antenna, .set_antenna = mwifiex_cfg80211_set_antenna,
.del_station = mwifiex_cfg80211_del_station, .del_station = mwifiex_cfg80211_del_station,
.sched_scan_start = mwifiex_cfg80211_sched_scan_start,
.sched_scan_stop = mwifiex_cfg80211_sched_scan_stop,
#ifdef CONFIG_PM #ifdef CONFIG_PM
.suspend = mwifiex_cfg80211_suspend, .suspend = mwifiex_cfg80211_suspend,
.resume = mwifiex_cfg80211_resume, .resume = mwifiex_cfg80211_resume,
...@@ -3829,6 +3958,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) ...@@ -3829,6 +3958,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_AP_UAPSD |
WIPHY_FLAG_SUPPORTS_SCHED_SCAN |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
WIPHY_FLAG_HAS_CHANNEL_SWITCH | WIPHY_FLAG_HAS_CHANNEL_SWITCH |
WIPHY_FLAG_PS_ON_BY_DEFAULT; WIPHY_FLAG_PS_ON_BY_DEFAULT;
...@@ -3847,6 +3977,10 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) ...@@ -3847,6 +3977,10 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
wiphy->max_sched_scan_ssids = MWIFIEX_MAX_SSID_LIST_LENGTH;
wiphy->max_sched_scan_ie_len = MWIFIEX_MAX_VSIE_LEN;
wiphy->max_match_sets = MWIFIEX_MAX_SSID_LIST_LENGTH;
wiphy->available_antennas_tx = BIT(adapter->number_of_antenna) - 1; wiphy->available_antennas_tx = BIT(adapter->number_of_antenna) - 1;
wiphy->available_antennas_rx = BIT(adapter->number_of_antenna) - 1; wiphy->available_antennas_rx = BIT(adapter->number_of_antenna) - 1;
......
...@@ -144,6 +144,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { ...@@ -144,6 +144,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18) #define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18)
#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) #define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19)
#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22) #define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22)
#define TLV_TYPE_BGSCAN_START_LATER (PROPRIETARY_TLV_BASE_ID + 30)
#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31) #define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31)
#define TLV_TYPE_STA_MAC_ADDR (PROPRIETARY_TLV_BASE_ID + 32) #define TLV_TYPE_STA_MAC_ADDR (PROPRIETARY_TLV_BASE_ID + 32)
#define TLV_TYPE_BSSID (PROPRIETARY_TLV_BASE_ID + 35) #define TLV_TYPE_BSSID (PROPRIETARY_TLV_BASE_ID + 35)
...@@ -177,6 +178,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { ...@@ -177,6 +178,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_TX_PAUSE (PROPRIETARY_TLV_BASE_ID + 148) #define TLV_TYPE_TX_PAUSE (PROPRIETARY_TLV_BASE_ID + 148)
#define TLV_TYPE_COALESCE_RULE (PROPRIETARY_TLV_BASE_ID + 154) #define TLV_TYPE_COALESCE_RULE (PROPRIETARY_TLV_BASE_ID + 154)
#define TLV_TYPE_KEY_PARAM_V2 (PROPRIETARY_TLV_BASE_ID + 156) #define TLV_TYPE_KEY_PARAM_V2 (PROPRIETARY_TLV_BASE_ID + 156)
#define TLV_TYPE_REPEAT_COUNT (PROPRIETARY_TLV_BASE_ID + 176)
#define TLV_TYPE_MULTI_CHAN_INFO (PROPRIETARY_TLV_BASE_ID + 183) #define TLV_TYPE_MULTI_CHAN_INFO (PROPRIETARY_TLV_BASE_ID + 183)
#define TLV_TYPE_MC_GROUP_INFO (PROPRIETARY_TLV_BASE_ID + 184) #define TLV_TYPE_MC_GROUP_INFO (PROPRIETARY_TLV_BASE_ID + 184)
#define TLV_TYPE_TDLS_IDLE_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 194) #define TLV_TYPE_TDLS_IDLE_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 194)
...@@ -331,6 +333,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { ...@@ -331,6 +333,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_802_11_MAC_ADDRESS 0x004D #define HostCmd_CMD_802_11_MAC_ADDRESS 0x004D
#define HostCmd_CMD_802_11D_DOMAIN_INFO 0x005b #define HostCmd_CMD_802_11D_DOMAIN_INFO 0x005b
#define HostCmd_CMD_802_11_KEY_MATERIAL 0x005e #define HostCmd_CMD_802_11_KEY_MATERIAL 0x005e
#define HostCmd_CMD_802_11_BG_SCAN_CONFIG 0x006b
#define HostCmd_CMD_802_11_BG_SCAN_QUERY 0x006c #define HostCmd_CMD_802_11_BG_SCAN_QUERY 0x006c
#define HostCmd_CMD_WMM_GET_STATUS 0x0071 #define HostCmd_CMD_WMM_GET_STATUS 0x0071
#define HostCmd_CMD_802_11_SUBSCRIBE_EVENT 0x0075 #define HostCmd_CMD_802_11_SUBSCRIBE_EVENT 0x0075
...@@ -523,6 +526,7 @@ enum P2P_MODES { ...@@ -523,6 +526,7 @@ enum P2P_MODES {
#define EVENT_CHANNEL_REPORT_RDY 0x00000054 #define EVENT_CHANNEL_REPORT_RDY 0x00000054
#define EVENT_TX_DATA_PAUSE 0x00000055 #define EVENT_TX_DATA_PAUSE 0x00000055
#define EVENT_EXT_SCAN_REPORT 0x00000058 #define EVENT_EXT_SCAN_REPORT 0x00000058
#define EVENT_BG_SCAN_STOPPED 0x00000065
#define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f #define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f
#define EVENT_MULTI_CHAN_INFO 0x0000006a #define EVENT_MULTI_CHAN_INFO 0x0000006a
#define EVENT_TX_STATUS_REPORT 0x00000074 #define EVENT_TX_STATUS_REPORT 0x00000074
...@@ -733,6 +737,16 @@ struct mwifiex_ie_types_num_probes { ...@@ -733,6 +737,16 @@ struct mwifiex_ie_types_num_probes {
__le16 num_probes; __le16 num_probes;
} __packed; } __packed;
struct mwifiex_ie_types_repeat_count {
struct mwifiex_ie_types_header header;
__le16 repeat_count;
} __packed;
struct mwifiex_ie_types_bgscan_start_later {
struct mwifiex_ie_types_header header;
__le16 start_later;
} __packed;
struct mwifiex_ie_types_scan_chan_gap { struct mwifiex_ie_types_scan_chan_gap {
struct mwifiex_ie_types_header header; struct mwifiex_ie_types_header header;
/* time gap in TUs to be used between two consecutive channels scan */ /* time gap in TUs to be used between two consecutive channels scan */
...@@ -1425,6 +1439,36 @@ struct mwifiex_user_scan_cfg { ...@@ -1425,6 +1439,36 @@ struct mwifiex_user_scan_cfg {
u16 scan_chan_gap; u16 scan_chan_gap;
} __packed; } __packed;
#define MWIFIEX_BG_SCAN_CHAN_MAX 38
#define MWIFIEX_BSS_MODE_INFRA 1
#define MWIFIEX_BGSCAN_ACT_GET 0x0000
#define MWIFIEX_BGSCAN_ACT_SET 0x0001
#define MWIFIEX_BGSCAN_ACT_SET_ALL 0xff01
/** ssid match */
#define MWIFIEX_BGSCAN_SSID_MATCH 0x0001
/** ssid match and RSSI exceeded */
#define MWIFIEX_BGSCAN_SSID_RSSI_MATCH 0x0004
/**wait for all channel scan to complete to report scan result*/
#define MWIFIEX_BGSCAN_WAIT_ALL_CHAN_DONE 0x80000000
struct mwifiex_bg_scan_cfg {
u16 action;
u8 enable;
u8 bss_type;
u8 chan_per_scan;
u32 scan_interval;
u32 report_condition;
u8 num_probes;
u8 rssi_threshold;
u8 snr_threshold;
u16 repeat_count;
u16 start_later;
struct cfg80211_match_set *ssid_list;
u8 num_ssids;
struct mwifiex_user_scan_chan chan_list[MWIFIEX_BG_SCAN_CHAN_MAX];
u16 scan_chan_gap;
} __packed;
struct ie_body { struct ie_body {
u8 grp_key_oui[4]; u8 grp_key_oui[4];
u8 ptk_cnt[2]; u8 ptk_cnt[2];
...@@ -1470,6 +1514,20 @@ struct mwifiex_ie_types_bss_scan_info { ...@@ -1470,6 +1514,20 @@ struct mwifiex_ie_types_bss_scan_info {
__le64 tsf; __le64 tsf;
} __packed; } __packed;
struct host_cmd_ds_802_11_bg_scan_config {
__le16 action;
u8 enable;
u8 bss_type;
u8 chan_per_scan;
u8 reserved;
__le16 reserved1;
__le32 scan_interval;
__le32 reserved2;
__le32 report_condition;
__le16 reserved3;
u8 tlv[0];
} __packed;
struct host_cmd_ds_802_11_bg_scan_query { struct host_cmd_ds_802_11_bg_scan_query {
u8 flush; u8 flush;
} __packed; } __packed;
...@@ -2124,6 +2182,7 @@ struct host_cmd_ds_command { ...@@ -2124,6 +2182,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_802_11_scan scan; struct host_cmd_ds_802_11_scan scan;
struct host_cmd_ds_802_11_scan_ext ext_scan; struct host_cmd_ds_802_11_scan_ext ext_scan;
struct host_cmd_ds_802_11_scan_rsp scan_resp; struct host_cmd_ds_802_11_scan_rsp scan_resp;
struct host_cmd_ds_802_11_bg_scan_config bg_scan_config;
struct host_cmd_ds_802_11_bg_scan_query bg_scan_query; struct host_cmd_ds_802_11_bg_scan_query bg_scan_query;
struct host_cmd_ds_802_11_bg_scan_query_rsp bg_scan_query_resp; struct host_cmd_ds_802_11_bg_scan_query_rsp bg_scan_query_resp;
struct host_cmd_ds_802_11_associate associate; struct host_cmd_ds_802_11_associate associate;
......
...@@ -414,6 +414,7 @@ struct mwifiex_ds_mef_cfg { ...@@ -414,6 +414,7 @@ struct mwifiex_ds_mef_cfg {
#define MWIFIEX_VSIE_MASK_SCAN 0x01 #define MWIFIEX_VSIE_MASK_SCAN 0x01
#define MWIFIEX_VSIE_MASK_ASSOC 0x02 #define MWIFIEX_VSIE_MASK_ASSOC 0x02
#define MWIFIEX_VSIE_MASK_ADHOC 0x04 #define MWIFIEX_VSIE_MASK_ADHOC 0x04
#define MWIFIEX_VSIE_MASK_BGSCAN 0x08
enum { enum {
MWIFIEX_FUNC_INIT = 1, MWIFIEX_FUNC_INIT = 1,
......
...@@ -746,6 +746,13 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb) ...@@ -746,6 +746,13 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb)
mwifiex_queue_main_work(priv->adapter); mwifiex_queue_main_work(priv->adapter);
if (priv->sched_scanning) {
mwifiex_dbg(priv->adapter, INFO,
"aborting bgscan on ndo_stop\n");
mwifiex_stop_bg_scan(priv);
cfg80211_sched_scan_stopped(priv->wdev.wiphy);
}
return 0; return 0;
} }
......
...@@ -198,6 +198,11 @@ do { \ ...@@ -198,6 +198,11 @@ do { \
buf, len, false); \ buf, len, false); \
} while (0) } while (0)
/** Min BGSCAN interval 15 second */
#define MWIFIEX_BGSCAN_INTERVAL 15000
/** default repeat count */
#define MWIFIEX_BGSCAN_REPEAT_COUNT 6
struct mwifiex_dbg { struct mwifiex_dbg {
u32 num_cmd_host_to_card_failure; u32 num_cmd_host_to_card_failure;
u32 num_cmd_sleep_cfm_host_to_card_failure; u32 num_cmd_sleep_cfm_host_to_card_failure;
...@@ -641,6 +646,7 @@ struct mwifiex_private { ...@@ -641,6 +646,7 @@ struct mwifiex_private {
u32 mgmt_frame_mask; u32 mgmt_frame_mask;
struct mwifiex_roc_cfg roc_cfg; struct mwifiex_roc_cfg roc_cfg;
bool scan_aborting; bool scan_aborting;
u8 sched_scanning;
u8 csa_chan; u8 csa_chan;
unsigned long csa_expire_time; unsigned long csa_expire_time;
u8 del_list_idx; u8 del_list_idx;
...@@ -1198,6 +1204,10 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv, ...@@ -1198,6 +1204,10 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
struct host_cmd_ds_command *resp); struct host_cmd_ds_command *resp);
int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv, int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv,
void *buf); void *buf);
int mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd,
void *data_buf);
int mwifiex_stop_bg_scan(struct mwifiex_private *priv);
/* /*
* This function checks if the queuing is RA based or not. * This function checks if the queuing is RA based or not.
......
...@@ -547,6 +547,61 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv, ...@@ -547,6 +547,61 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
return chan_idx; return chan_idx;
} }
/* This function creates a channel list tlv for bgscan config, based
* on region/band information.
*/
static int
mwifiex_bgscan_create_channel_list(struct mwifiex_private *priv,
const struct mwifiex_bg_scan_cfg
*bgscan_cfg_in,
struct mwifiex_chan_scan_param_set
*scan_chan_list)
{
enum ieee80211_band band;
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
struct mwifiex_adapter *adapter = priv->adapter;
int chan_idx = 0, i;
for (band = 0; (band < IEEE80211_NUM_BANDS); band++) {
if (!priv->wdev.wiphy->bands[band])
continue;
sband = priv->wdev.wiphy->bands[band];
for (i = 0; (i < sband->n_channels) ; i++) {
ch = &sband->channels[i];
if (ch->flags & IEEE80211_CHAN_DISABLED)
continue;
scan_chan_list[chan_idx].radio_type = band;
if (bgscan_cfg_in->chan_list[0].scan_time)
scan_chan_list[chan_idx].max_scan_time =
cpu_to_le16((u16)bgscan_cfg_in->
chan_list[0].scan_time);
else if (ch->flags & IEEE80211_CHAN_NO_IR)
scan_chan_list[chan_idx].max_scan_time =
cpu_to_le16(adapter->passive_scan_time);
else
scan_chan_list[chan_idx].max_scan_time =
cpu_to_le16(adapter->
specific_scan_time);
if (ch->flags & IEEE80211_CHAN_NO_IR)
scan_chan_list[chan_idx].chan_scan_mode_bitmap
|= MWIFIEX_PASSIVE_SCAN;
else
scan_chan_list[chan_idx].chan_scan_mode_bitmap
&= ~MWIFIEX_PASSIVE_SCAN;
scan_chan_list[chan_idx].chan_number =
(u32)ch->hw_value;
chan_idx++;
}
}
return chan_idx;
}
/* This function appends rate TLV to scan config command. */ /* This function appends rate TLV to scan config command. */
static int static int
mwifiex_append_rate_tlv(struct mwifiex_private *priv, mwifiex_append_rate_tlv(struct mwifiex_private *priv,
...@@ -2155,6 +2210,212 @@ int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv, ...@@ -2155,6 +2210,212 @@ int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv,
return 0; return 0;
} }
/* This function prepares an background scan config command to be sent
* to the firmware
*/
int mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv,
struct host_cmd_ds_command *cmd,
void *data_buf)
{
struct host_cmd_ds_802_11_bg_scan_config *bgscan_config =
&cmd->params.bg_scan_config;
struct mwifiex_bg_scan_cfg *bgscan_cfg_in = data_buf;
u8 *tlv_pos = bgscan_config->tlv;
u8 num_probes;
u32 ssid_len, chan_idx, scan_type, scan_dur, chan_num;
int i;
struct mwifiex_ie_types_num_probes *num_probes_tlv;
struct mwifiex_ie_types_repeat_count *repeat_count_tlv;
struct mwifiex_ie_types_bgscan_start_later *start_later_tlv;
struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv;
struct mwifiex_ie_types_chan_list_param_set *chan_list_tlv;
struct mwifiex_chan_scan_param_set *temp_chan;
cmd->command = cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_CONFIG);
cmd->size = cpu_to_le16(sizeof(*bgscan_config) + S_DS_GEN);
bgscan_config->action = cpu_to_le16(bgscan_cfg_in->action);
bgscan_config->enable = bgscan_cfg_in->enable;
bgscan_config->bss_type = bgscan_cfg_in->bss_type;
bgscan_config->scan_interval =
cpu_to_le32(bgscan_cfg_in->scan_interval);
bgscan_config->report_condition =
cpu_to_le32(bgscan_cfg_in->report_condition);
/* stop sched scan */
if (!bgscan_config->enable)
return 0;
bgscan_config->chan_per_scan = bgscan_cfg_in->chan_per_scan;
num_probes = (bgscan_cfg_in->num_probes ? bgscan_cfg_in->
num_probes : priv->adapter->scan_probes);
if (num_probes) {
num_probes_tlv = (struct mwifiex_ie_types_num_probes *)tlv_pos;
num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES);
num_probes_tlv->header.len =
cpu_to_le16(sizeof(num_probes_tlv->num_probes));
num_probes_tlv->num_probes = cpu_to_le16((u16)num_probes);
tlv_pos += sizeof(num_probes_tlv->header) +
le16_to_cpu(num_probes_tlv->header.len);
}
if (bgscan_cfg_in->repeat_count) {
repeat_count_tlv =
(struct mwifiex_ie_types_repeat_count *)tlv_pos;
repeat_count_tlv->header.type =
cpu_to_le16(TLV_TYPE_REPEAT_COUNT);
repeat_count_tlv->header.len =
cpu_to_le16(sizeof(repeat_count_tlv->repeat_count));
repeat_count_tlv->repeat_count =
cpu_to_le16(bgscan_cfg_in->repeat_count);
tlv_pos += sizeof(repeat_count_tlv->header) +
le16_to_cpu(repeat_count_tlv->header.len);
}
for (i = 0; i < bgscan_cfg_in->num_ssids; i++) {
ssid_len = bgscan_cfg_in->ssid_list[i].ssid.ssid_len;
wildcard_ssid_tlv =
(struct mwifiex_ie_types_wildcard_ssid_params *)tlv_pos;
wildcard_ssid_tlv->header.type =
cpu_to_le16(TLV_TYPE_WILDCARDSSID);
wildcard_ssid_tlv->header.len = cpu_to_le16(
(u16)(ssid_len + sizeof(wildcard_ssid_tlv->
max_ssid_length)));
/* max_ssid_length = 0 tells firmware to perform
* specific scan for the SSID filled, whereas
* max_ssid_length = IEEE80211_MAX_SSID_LEN is for
* wildcard scan.
*/
if (ssid_len)
wildcard_ssid_tlv->max_ssid_length = 0;
else
wildcard_ssid_tlv->max_ssid_length =
IEEE80211_MAX_SSID_LEN;
memcpy(wildcard_ssid_tlv->ssid,
bgscan_cfg_in->ssid_list[i].ssid.ssid, ssid_len);
tlv_pos += (sizeof(wildcard_ssid_tlv->header)
+ le16_to_cpu(wildcard_ssid_tlv->header.len));
}
chan_list_tlv = (struct mwifiex_ie_types_chan_list_param_set *)tlv_pos;
if (bgscan_cfg_in->chan_list[0].chan_number) {
dev_dbg(priv->adapter->dev, "info: bgscan: Using supplied channel list\n");
chan_list_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
for (chan_idx = 0;
chan_idx < MWIFIEX_BG_SCAN_CHAN_MAX &&
bgscan_cfg_in->chan_list[chan_idx].chan_number;
chan_idx++) {
temp_chan = chan_list_tlv->chan_scan_param + chan_idx;
/* Increment the TLV header length by size appended */
le16_add_cpu(&chan_list_tlv->header.len,
sizeof(chan_list_tlv->chan_scan_param));
temp_chan->chan_number =
bgscan_cfg_in->chan_list[chan_idx].chan_number;
temp_chan->radio_type =
bgscan_cfg_in->chan_list[chan_idx].radio_type;
scan_type =
bgscan_cfg_in->chan_list[chan_idx].scan_type;
if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
temp_chan->chan_scan_mode_bitmap
|= MWIFIEX_PASSIVE_SCAN;
else
temp_chan->chan_scan_mode_bitmap
&= ~MWIFIEX_PASSIVE_SCAN;
if (bgscan_cfg_in->chan_list[chan_idx].scan_time) {
scan_dur = (u16)bgscan_cfg_in->
chan_list[chan_idx].scan_time;
} else {
scan_dur = (scan_type ==
MWIFIEX_SCAN_TYPE_PASSIVE) ?
priv->adapter->passive_scan_time :
priv->adapter->specific_scan_time;
}
temp_chan->min_scan_time = cpu_to_le16(scan_dur);
temp_chan->max_scan_time = cpu_to_le16(scan_dur);
}
} else {
dev_dbg(priv->adapter->dev,
"info: bgscan: Creating full region channel list\n");
chan_num =
mwifiex_bgscan_create_channel_list(priv, bgscan_cfg_in,
chan_list_tlv->
chan_scan_param);
le16_add_cpu(&chan_list_tlv->header.len,
chan_num *
sizeof(chan_list_tlv->chan_scan_param[0]));
}
tlv_pos += (sizeof(chan_list_tlv->header)
+ le16_to_cpu(chan_list_tlv->header.len));
if (bgscan_cfg_in->start_later) {
start_later_tlv =
(struct mwifiex_ie_types_bgscan_start_later *)tlv_pos;
start_later_tlv->header.type =
cpu_to_le16(TLV_TYPE_BGSCAN_START_LATER);
start_later_tlv->header.len =
cpu_to_le16(sizeof(start_later_tlv->start_later));
start_later_tlv->start_later =
cpu_to_le16(bgscan_cfg_in->start_later);
tlv_pos += sizeof(start_later_tlv->header) +
le16_to_cpu(start_later_tlv->header.len);
}
/* Append vendor specific IE TLV */
mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_BGSCAN, &tlv_pos);
le16_add_cpu(&cmd->size, tlv_pos - bgscan_config->tlv);
return 0;
}
int mwifiex_stop_bg_scan(struct mwifiex_private *priv)
{
struct mwifiex_bg_scan_cfg *bgscan_cfg;
if (!priv->sched_scanning) {
dev_dbg(priv->adapter->dev, "bgscan already stopped!\n");
return 0;
}
bgscan_cfg = kzalloc(sizeof(*bgscan_cfg), GFP_KERNEL);
if (!bgscan_cfg)
return -ENOMEM;
bgscan_cfg->bss_type = MWIFIEX_BSS_MODE_INFRA;
bgscan_cfg->action = MWIFIEX_BGSCAN_ACT_SET;
bgscan_cfg->enable = false;
if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_BG_SCAN_CONFIG,
HostCmd_ACT_GEN_SET, 0, bgscan_cfg, true)) {
kfree(bgscan_cfg);
return -EFAULT;
}
kfree(bgscan_cfg);
priv->sched_scanning = false;
return 0;
}
static void static void
mwifiex_update_chan_statistics(struct mwifiex_private *priv, mwifiex_update_chan_statistics(struct mwifiex_private *priv,
struct mwifiex_ietypes_chanstats *tlv_stat) struct mwifiex_ietypes_chanstats *tlv_stat)
......
...@@ -1873,6 +1873,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, ...@@ -1873,6 +1873,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
case HostCmd_CMD_802_11_SCAN: case HostCmd_CMD_802_11_SCAN:
ret = mwifiex_cmd_802_11_scan(cmd_ptr, data_buf); ret = mwifiex_cmd_802_11_scan(cmd_ptr, data_buf);
break; break;
case HostCmd_CMD_802_11_BG_SCAN_CONFIG:
ret = mwifiex_cmd_802_11_bg_scan_config(priv, cmd_ptr,
data_buf);
break;
case HostCmd_CMD_802_11_BG_SCAN_QUERY: case HostCmd_CMD_802_11_BG_SCAN_QUERY:
ret = mwifiex_cmd_802_11_bg_scan_query(cmd_ptr); ret = mwifiex_cmd_802_11_bg_scan_query(cmd_ptr);
break; break;
......
...@@ -1076,9 +1076,12 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, ...@@ -1076,9 +1076,12 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
break; break;
case HostCmd_CMD_802_11_BG_SCAN_QUERY: case HostCmd_CMD_802_11_BG_SCAN_QUERY:
ret = mwifiex_ret_802_11_scan(priv, resp); ret = mwifiex_ret_802_11_scan(priv, resp);
cfg80211_sched_scan_results(priv->wdev.wiphy);
mwifiex_dbg(adapter, CMD, mwifiex_dbg(adapter, CMD,
"info: CMD_RESP: BG_SCAN result is ready!\n"); "info: CMD_RESP: BG_SCAN result is ready!\n");
break; break;
case HostCmd_CMD_802_11_BG_SCAN_CONFIG:
break;
case HostCmd_CMD_TXPWR_CFG: case HostCmd_CMD_TXPWR_CFG:
ret = mwifiex_ret_tx_power_cfg(priv, resp); ret = mwifiex_ret_tx_power_cfg(priv, resp);
break; break;
......
...@@ -688,6 +688,13 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) ...@@ -688,6 +688,13 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
HostCmd_ACT_GEN_GET, 0, NULL, false); HostCmd_ACT_GEN_GET, 0, NULL, false);
break; break;
case EVENT_BG_SCAN_STOPPED:
dev_dbg(adapter->dev, "event: BGS_STOPPED\n");
cfg80211_sched_scan_stopped(priv->wdev.wiphy);
if (priv->sched_scanning)
priv->sched_scanning = false;
break;
case EVENT_PORT_RELEASE: case EVENT_PORT_RELEASE:
mwifiex_dbg(adapter, EVENT, "event: PORT RELEASE\n"); mwifiex_dbg(adapter, EVENT, "event: PORT RELEASE\n");
priv->port_open = true; priv->port_open = true;
......
...@@ -504,6 +504,13 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter) ...@@ -504,6 +504,13 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
} }
} }
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
if (priv && priv->sched_scanning) {
dev_dbg(adapter->dev, "aborting bgscan!\n");
mwifiex_stop_bg_scan(priv);
cfg80211_sched_scan_stopped(priv->wdev.wiphy);
}
if (adapter->hs_activated) { if (adapter->hs_activated) {
mwifiex_dbg(adapter, CMD, mwifiex_dbg(adapter, CMD,
"cmd: HS Already activated\n"); "cmd: HS Already activated\n");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册