mwifiex: add schedule scan support
authorXinming Hu <huxm@marvell.com>
Wed, 13 Jan 2016 09:26:52 +0000 (01:26 -0800)
committerKalle Valo <kvalo@codeaurora.org>
Fri, 29 Jan 2016 09:20:37 +0000 (11:20 +0200)
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: Xinming Hu <huxm@marvell.com>
Signed-off-by: chunfan chen <jeffc@marvell.com>
Signed-off-by: Cathy Luo <cluo@marvell.com>
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/marvell/mwifiex/cfg80211.c
drivers/net/wireless/marvell/mwifiex/fw.h
drivers/net/wireless/marvell/mwifiex/ioctl.h
drivers/net/wireless/marvell/mwifiex/main.c
drivers/net/wireless/marvell/mwifiex/main.h
drivers/net/wireless/marvell/mwifiex/scan.c
drivers/net/wireless/marvell/mwifiex/sta_cmd.c
drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
drivers/net/wireless/marvell/mwifiex/sta_event.c
drivers/net/wireless/marvell/mwifiex/sta_ioctl.c

index e7adef7..c27c6cc 100644 (file)
@@ -1962,6 +1962,9 @@ mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *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))
                return -EFAULT;
 
@@ -2217,6 +2220,9 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
                    "info: Trying to associate to %s and bssid %pM\n",
                    (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,
                                     priv->bss_mode, sme->channel, sme, 0);
        if (!ret) {
@@ -2420,6 +2426,9 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
                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);
        if (!user_scan_cfg)
                return -ENOMEM;
@@ -2487,6 +2496,121 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
        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,
                                   struct mwifiex_private *priv)
 {
@@ -2848,6 +2972,9 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
        mwifiex_dev_debugfs_remove(priv);
 #endif
 
+       if (priv->sched_scanning)
+               priv->sched_scanning = false;
+
        mwifiex_stop_net_dev_queue(priv->netdev, adapter);
 
        skb_queue_walk_safe(&priv->bypass_txq, skb, tmp)
@@ -3701,6 +3828,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
        .set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config,
        .set_antenna = mwifiex_cfg80211_set_antenna,
        .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
        .suspend = mwifiex_cfg80211_suspend,
        .resume = mwifiex_cfg80211_resume,
@@ -3829,6 +3958,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
        wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
                        WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
                        WIPHY_FLAG_AP_UAPSD |
+                       WIPHY_FLAG_SUPPORTS_SCHED_SCAN |
                        WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
                        WIPHY_FLAG_HAS_CHANNEL_SWITCH |
                        WIPHY_FLAG_PS_ON_BY_DEFAULT;
@@ -3847,6 +3977,10 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
                                    NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
                                    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_rx = BIT(adapter->number_of_antenna) - 1;
 
index 426e76a..07bdc2a 100644 (file)
@@ -144,6 +144,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define TLV_TYPE_WILDCARDSSID       (PROPRIETARY_TLV_BASE_ID + 18)
 #define TLV_TYPE_TSFTIMESTAMP       (PROPRIETARY_TLV_BASE_ID + 19)
 #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_STA_MAC_ADDR       (PROPRIETARY_TLV_BASE_ID + 32)
 #define TLV_TYPE_BSSID              (PROPRIETARY_TLV_BASE_ID + 35)
@@ -177,6 +178,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define TLV_TYPE_TX_PAUSE           (PROPRIETARY_TLV_BASE_ID + 148)
 #define TLV_TYPE_COALESCE_RULE      (PROPRIETARY_TLV_BASE_ID + 154)
 #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_MC_GROUP_INFO      (PROPRIETARY_TLV_BASE_ID + 184)
 #define TLV_TYPE_TDLS_IDLE_TIMEOUT  (PROPRIETARY_TLV_BASE_ID + 194)
@@ -331,6 +333,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define HostCmd_CMD_802_11_MAC_ADDRESS                0x004D
 #define HostCmd_CMD_802_11D_DOMAIN_INFO               0x005b
 #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_WMM_GET_STATUS                    0x0071
 #define HostCmd_CMD_802_11_SUBSCRIBE_EVENT            0x0075
@@ -523,6 +526,7 @@ enum P2P_MODES {
 #define EVENT_CHANNEL_REPORT_RDY        0x00000054
 #define EVENT_TX_DATA_PAUSE             0x00000055
 #define EVENT_EXT_SCAN_REPORT           0x00000058
+#define EVENT_BG_SCAN_STOPPED           0x00000065
 #define EVENT_REMAIN_ON_CHAN_EXPIRED    0x0000005f
 #define EVENT_MULTI_CHAN_INFO           0x0000006a
 #define EVENT_TX_STATUS_REPORT         0x00000074
@@ -733,6 +737,16 @@ struct mwifiex_ie_types_num_probes {
        __le16 num_probes;
 } __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_header header;
        /* time gap in TUs to be used between two consecutive channels scan */
@@ -1425,6 +1439,36 @@ struct mwifiex_user_scan_cfg {
        u16 scan_chan_gap;
 } __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 {
        u8 grp_key_oui[4];
        u8 ptk_cnt[2];
@@ -1470,6 +1514,20 @@ struct mwifiex_ie_types_bss_scan_info {
        __le64 tsf;
 } __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 {
        u8 flush;
 } __packed;
@@ -2124,6 +2182,7 @@ struct host_cmd_ds_command {
                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_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_rsp bg_scan_query_resp;
                struct host_cmd_ds_802_11_associate associate;
index 4f0174c..6333b16 100644 (file)
@@ -414,6 +414,7 @@ struct mwifiex_ds_mef_cfg {
 #define MWIFIEX_VSIE_MASK_SCAN     0x01
 #define MWIFIEX_VSIE_MASK_ASSOC    0x02
 #define MWIFIEX_VSIE_MASK_ADHOC    0x04
+#define MWIFIEX_VSIE_MASK_BGSCAN   0x08
 
 enum {
        MWIFIEX_FUNC_INIT = 1,
index 79c16de..a99b72b 100644 (file)
@@ -746,6 +746,13 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb)
 
        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;
 }
 
index 35ab052..5f5bcf8 100644 (file)
@@ -198,6 +198,11 @@ do {                                                               \
                               buf, len, false);                \
 } while (0)
 
+/** Min BGSCAN interval 15 second */
+#define MWIFIEX_BGSCAN_INTERVAL 15000
+/** default repeat count */
+#define MWIFIEX_BGSCAN_REPEAT_COUNT 6
+
 struct mwifiex_dbg {
        u32 num_cmd_host_to_card_failure;
        u32 num_cmd_sleep_cfm_host_to_card_failure;
@@ -641,6 +646,7 @@ struct mwifiex_private {
        u32 mgmt_frame_mask;
        struct mwifiex_roc_cfg roc_cfg;
        bool scan_aborting;
+       u8 sched_scanning;
        u8 csa_chan;
        unsigned long csa_expire_time;
        u8 del_list_idx;
@@ -1198,6 +1204,10 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
                                struct host_cmd_ds_command *resp);
 int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv,
                                         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.
index c20017c..d4e2143 100644 (file)
@@ -547,6 +547,61 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
        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. */
 static int
 mwifiex_append_rate_tlv(struct mwifiex_private *priv,
@@ -2155,6 +2210,212 @@ int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv,
        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
 mwifiex_update_chan_statistics(struct mwifiex_private *priv,
                               struct mwifiex_ietypes_chanstats *tlv_stat)
index e486867..60f3ded 100644 (file)
@@ -1873,6 +1873,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
        case HostCmd_CMD_802_11_SCAN:
                ret = mwifiex_cmd_802_11_scan(cmd_ptr, data_buf);
                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:
                ret = mwifiex_cmd_802_11_bg_scan_query(cmd_ptr);
                break;
index 9ac7aa2..4b23d3b 100644 (file)
@@ -1076,9 +1076,12 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
                break;
        case HostCmd_CMD_802_11_BG_SCAN_QUERY:
                ret = mwifiex_ret_802_11_scan(priv, resp);
+               cfg80211_sched_scan_results(priv->wdev.wiphy);
                mwifiex_dbg(adapter, CMD,
                            "info: CMD_RESP: BG_SCAN result is ready!\n");
                break;
+       case HostCmd_CMD_802_11_BG_SCAN_CONFIG:
+               break;
        case HostCmd_CMD_TXPWR_CFG:
                ret = mwifiex_ret_tx_power_cfg(priv, resp);
                break;
index 23bae87..fd8061c 100644 (file)
@@ -688,6 +688,13 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
                                       HostCmd_ACT_GEN_GET, 0, NULL, false);
                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:
                mwifiex_dbg(adapter, EVENT, "event: PORT RELEASE\n");
                priv->port_open = true;
index 210b257..2cc1a32 100644 (file)
@@ -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) {
                mwifiex_dbg(adapter, CMD,
                            "cmd: HS Already activated\n");