mwifiex: fix unable to connect hidden SSID AP on DFS channel
authorchunfan chen <jeffc@marvell.com>
Wed, 5 Aug 2015 13:09:42 +0000 (06:09 -0700)
committerKalle Valo <kvalo@codeaurora.org>
Thu, 13 Aug 2015 12:34:53 +0000 (15:34 +0300)
We will check if any hidden SSID found in passive scan channels
and do specific SSID active scan for those channels.

Signed-off-by: chunfan chen <jeffc@marvell.com>
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/scan.c

index 9a8c1832d0686d42796e8a678d6bb46119538c9a..3ec2ac82e394a158e6c346d75e73a29715e7ec29 100644 (file)
@@ -685,6 +685,7 @@ struct mwifiex_fw_chan_stats {
 enum mwifiex_chan_scan_mode_bitmasks {
        MWIFIEX_PASSIVE_SCAN = BIT(0),
        MWIFIEX_DISABLE_CHAN_FILT = BIT(1),
+       MWIFIEX_HIDDEN_SSID_REPORT = BIT(4),
 };
 
 struct mwifiex_chan_scan_param_set {
index 7a970c28c5570524db8436cc8f9a23f1ee8ae2c0..5d3ae63baea4c1950203563f712bda2f83c04988 100644 (file)
@@ -301,7 +301,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
        adapter->iface_limit.sta_intf = MWIFIEX_MAX_STA_NUM;
        adapter->iface_limit.uap_intf = MWIFIEX_MAX_UAP_NUM;
        adapter->iface_limit.p2p_intf = MWIFIEX_MAX_P2P_NUM;
-
+       adapter->active_scan_triggered = false;
        setup_timer(&adapter->wakeup_timer, wakeup_timer_fn,
                    (unsigned long)adapter);
 }
index face7478937f6559e106c4932d6551569b8beaac..6b9512140e7aa6b21d36e55d128486cf29210e74 100644 (file)
@@ -666,6 +666,7 @@ struct mwifiex_private {
        struct mwifiex_11h_intf_state state_11h;
        struct mwifiex_ds_mem_rw mem_rw;
        struct sk_buff_head bypass_txq;
+       struct mwifiex_user_scan_chan hidden_chan[MWIFIEX_USER_SCAN_CHAN_MAX];
 };
 
 
@@ -986,6 +987,7 @@ struct mwifiex_adapter {
        u8 coex_tx_win_size;
        u8 coex_rx_win_size;
        bool drcs_enabled;
+       u8 active_scan_triggered;
 };
 
 void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter);
index ef8da8ebcbab4ee5af196c4ec854b178c3b81322..5847863a2d6bec573956ff88c42a16c3495333b3 100644 (file)
@@ -527,7 +527,8 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
 
                        if (ch->flags & IEEE80211_CHAN_NO_IR)
                                scan_chan_list[chan_idx].chan_scan_mode_bitmap
-                                       |= MWIFIEX_PASSIVE_SCAN;
+                                       |= (MWIFIEX_PASSIVE_SCAN |
+                                           MWIFIEX_HIDDEN_SSID_REPORT);
                        else
                                scan_chan_list[chan_idx].chan_scan_mode_bitmap
                                        &= ~MWIFIEX_PASSIVE_SCAN;
@@ -1049,7 +1050,8 @@ mwifiex_config_scan(struct mwifiex_private *priv,
                        if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
                                (scan_chan_list +
                                 chan_idx)->chan_scan_mode_bitmap
-                                       |= MWIFIEX_PASSIVE_SCAN;
+                                       |= (MWIFIEX_PASSIVE_SCAN |
+                                           MWIFIEX_HIDDEN_SSID_REPORT);
                        else
                                (scan_chan_list +
                                 chan_idx)->chan_scan_mode_bitmap
@@ -1600,6 +1602,62 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
        return ret;
 }
 
+/* This function checks if SSID string contains all zeroes or length is zero */
+static bool mwifiex_is_hidden_ssid(struct cfg80211_ssid *ssid)
+{
+       int idx;
+
+       for (idx = 0; idx < ssid->ssid_len; idx++) {
+               if (ssid->ssid[idx])
+                       return false;
+       }
+
+       return true;
+}
+
+/* This function checks if any hidden SSID found in passive scan channels
+ * and save those channels for specific SSID active scan
+ */
+static int mwifiex_save_hidden_ssid_channels(struct mwifiex_private *priv,
+                                            struct cfg80211_bss *bss)
+{
+       struct mwifiex_bssdescriptor *bss_desc;
+       int ret;
+       int chid;
+
+       /* Allocate and fill new bss descriptor */
+       bss_desc = kzalloc(sizeof(*bss_desc), GFP_KERNEL);
+       if (!bss_desc)
+               return -ENOMEM;
+
+       ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc);
+       if (ret)
+               goto done;
+
+       if (mwifiex_is_hidden_ssid(&bss_desc->ssid)) {
+               mwifiex_dbg(priv->adapter, INFO, "found hidden SSID\n");
+               for (chid = 0 ; chid < MWIFIEX_USER_SCAN_CHAN_MAX; chid++) {
+                       if (priv->hidden_chan[chid].chan_number ==
+                           bss->channel->hw_value)
+                               break;
+
+                       if (!priv->hidden_chan[chid].chan_number) {
+                               priv->hidden_chan[chid].chan_number =
+                                       bss->channel->hw_value;
+                               priv->hidden_chan[chid].radio_type =
+                                       bss->channel->band;
+                               priv->hidden_chan[chid].scan_type =
+                                       MWIFIEX_SCAN_TYPE_ACTIVE;
+                               break;
+                       }
+               }
+       }
+
+done:
+       kfree(bss_desc);
+       return 0;
+}
+
 static int mwifiex_update_curr_bss_params(struct mwifiex_private *priv,
                                          struct cfg80211_bss *bss)
 {
@@ -1789,6 +1847,14 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
                                    .mac_address, ETH_ALEN))
                                mwifiex_update_curr_bss_params(priv, bss);
                        cfg80211_put_bss(priv->wdev.wiphy, bss);
+
+                       if ((chan->flags & IEEE80211_CHAN_RADAR) ||
+                           (chan->flags & IEEE80211_CHAN_NO_IR)) {
+                               mwifiex_dbg(adapter, INFO,
+                                           "radar or passive channel %d\n",
+                                           channel);
+                               mwifiex_save_hidden_ssid_channels(priv, bss);
+                       }
                }
        } else {
                mwifiex_dbg(adapter, WARN, "missing BSS channel IE\n");
@@ -1812,6 +1878,57 @@ static void mwifiex_complete_scan(struct mwifiex_private *priv)
        }
 }
 
+/* This function checks if any hidden SSID found in passive scan channels
+ * and do specific SSID active scan for those channels
+ */
+static int
+mwifiex_active_scan_req_for_passive_chan(struct mwifiex_private *priv)
+{
+       int ret;
+       struct mwifiex_adapter *adapter = priv->adapter;
+       u8 id = 0;
+       struct mwifiex_user_scan_cfg  *user_scan_cfg;
+
+       if (adapter->active_scan_triggered) {
+               adapter->active_scan_triggered = false;
+               return 0;
+       }
+
+       if (!priv->hidden_chan[0].chan_number) {
+               mwifiex_dbg(adapter, INFO, "No BSS with hidden SSID found on DFS channels\n");
+               return 0;
+       }
+       user_scan_cfg = kzalloc(sizeof(*user_scan_cfg), GFP_KERNEL);
+
+       if (!user_scan_cfg)
+               return -ENOMEM;
+
+       memset(user_scan_cfg, 0, sizeof(*user_scan_cfg));
+
+       for (id = 0; id < MWIFIEX_USER_SCAN_CHAN_MAX; id++) {
+               if (!priv->hidden_chan[id].chan_number)
+                       break;
+               memcpy(&user_scan_cfg->chan_list[id],
+                      &priv->hidden_chan[id],
+                      sizeof(struct mwifiex_user_scan_chan));
+       }
+
+       adapter->active_scan_triggered = true;
+       user_scan_cfg->num_ssids = priv->scan_request->n_ssids;
+       user_scan_cfg->ssid_list = priv->scan_request->ssids;
+
+       ret = mwifiex_scan_networks(priv, user_scan_cfg);
+       kfree(user_scan_cfg);
+
+       memset(&priv->hidden_chan, 0, sizeof(priv->hidden_chan));
+
+       if (ret) {
+               dev_err(priv->adapter->dev, "scan failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
 static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
 {
        struct mwifiex_adapter *adapter = priv->adapter;
@@ -1825,6 +1942,8 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
                adapter->scan_processing = false;
                spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
 
+               mwifiex_active_scan_req_for_passive_chan(priv);
+
                if (!adapter->ext_scan)
                        mwifiex_complete_scan(priv);
 
@@ -1851,15 +1970,17 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
                adapter->scan_processing = false;
                spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
 
-               if (priv->scan_request) {
-                       mwifiex_dbg(adapter, INFO,
-                                   "info: aborting scan\n");
-                       cfg80211_scan_done(priv->scan_request, 1);
-                       priv->scan_request = NULL;
-               } else {
-                       priv->scan_aborting = false;
-                       mwifiex_dbg(adapter, INFO,
-                                   "info: scan already aborted\n");
+               if (!adapter->active_scan_triggered) {
+                       if (priv->scan_request) {
+                               mwifiex_dbg(adapter, INFO,
+                                           "info: aborting scan\n");
+                               cfg80211_scan_done(priv->scan_request, 1);
+                               priv->scan_request = NULL;
+                       } else {
+                               priv->scan_aborting = false;
+                               mwifiex_dbg(adapter, INFO,
+                                           "info: scan already aborted\n");
+                       }
                }
        } else {
                /* Get scan command from scan_pending_q and put to