Currently a scan will only scan the first found stored hidden network.
This patch fixes it: it will scan all, taking into account the limit of
scan parameters the driver can take.

Thanks to Jukka for testing this.
---

1 memory leak and 1 invalid read fixed.
I simplified how frequencies are handled also. 

Fully tested, it seems to work properly.

 gsupplicant/gsupplicant.h |   1 +
 gsupplicant/supplicant.c  |   2 +-
 plugins/wifi.c            | 164 +++++++++++++++++++++++++++++++++-------------
 3 files changed, 122 insertions(+), 45 deletions(-)

diff --git a/gsupplicant/gsupplicant.h b/gsupplicant/gsupplicant.h
index 1b1fce2..da45075 100644
--- a/gsupplicant/gsupplicant.h
+++ b/gsupplicant/gsupplicant.h
@@ -148,6 +148,7 @@ struct _GSupplicantScanParams {
 
        uint8_t num_ssids;
 
+       uint8_t num_freqs;
        uint16_t *freqs;
 };
 
diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c
index 471c0bc..30f0660 100644
--- a/gsupplicant/supplicant.c
+++ b/gsupplicant/supplicant.c
@@ -2742,7 +2742,7 @@ static void add_scan_frequencies(DBusMessageIter *iter,
        unsigned int freq;
        int i;
 
-       for (i = 0; i < scan_data->num_ssids; i++) {
+       for (i = 0; i < scan_data->num_freqs; i++) {
                freq = scan_data->freqs[i];
                if (!freq)
                        break;
diff --git a/plugins/wifi.c b/plugins/wifi.c
index 07180d6..5f07869 100644
--- a/plugins/wifi.c
+++ b/plugins/wifi.c
@@ -107,6 +107,8 @@ struct wifi_data {
         * autoscan "emulation".
         */
        struct autoscan_params *autoscan;
+
+       GSupplicantScanParams *scan_params;
 };
 
 static GList *iface_list = NULL;
@@ -263,6 +265,9 @@ static void wifi_remove(struct connman_device *device)
 
        g_supplicant_interface_set_data(wifi->interface, NULL);
 
+       if (wifi->scan_params != NULL)
+               g_supplicant_free_scan_params(wifi->scan_params);
+
        g_free(wifi->autoscan);
        g_free(wifi->identifier);
        g_free(wifi);
@@ -290,7 +295,8 @@ static int add_scan_param(gchar *hex_ssid, char *raw_ssid, 
int ssid_len,
        unsigned int i;
        struct scan_ssid *scan_ssid;
 
-       if (driver_max_scan_ssids > scan_data->num_ssids &&
+       if ((driver_max_scan_ssids == 0 ||
+                       driver_max_scan_ssids > scan_data->num_ssids) &&
                        (hex_ssid != NULL || raw_ssid != NULL)) {
                gchar *ssid;
                unsigned int j = 0, hex;
@@ -344,36 +350,41 @@ static int add_scan_param(gchar *hex_ssid, char 
*raw_ssid, int ssid_len,
        scan_data->ssids = g_slist_reverse(scan_data->ssids);
 
        if (scan_data->freqs == NULL) {
-               scan_data->freqs = g_try_malloc0(sizeof(uint16_t) *
-                                               scan_data->num_ssids);
+               scan_data->freqs = g_try_malloc0(sizeof(uint16_t));
                if (scan_data->freqs == NULL) {
                        g_slist_free_full(scan_data->ssids, g_free);
                        return -ENOMEM;
                }
+
+               scan_data->num_freqs = 1;
+               scan_data->freqs[0] = freq;
        } else {
-               scan_data->freqs = g_try_realloc(scan_data->freqs,
-                               sizeof(uint16_t) * scan_data->num_ssids);
-               if (scan_data->freqs == NULL) {
-                       g_slist_free_full(scan_data->ssids, g_free);
-                       return -ENOMEM;
+               connman_bool_t duplicate = FALSE;
+
+               /* Don't add duplicate entries */
+               for (i = 0; i < scan_data->num_freqs; i++) {
+                       if (scan_data->freqs[i] == freq) {
+                               duplicate = TRUE;
+                               break;
+                       }
                }
-               scan_data->freqs[scan_data->num_ssids - 1] = 0;
-       }
 
-       /* Don't add duplicate entries */
-       for (i = 0; i < scan_data->num_ssids; i++) {
-               if (scan_data->freqs[i] == 0) {
-                       scan_data->freqs[i] = freq;
-                       break;
-               } else if (scan_data->freqs[i] == freq)
-                       break;
+               if (duplicate == FALSE) {
+                       scan_data->num_freqs++;
+                       scan_data->freqs = g_try_realloc(scan_data->freqs,
+                               sizeof(uint16_t) * scan_data->num_freqs);
+                       if (scan_data->freqs == NULL) {
+                               g_slist_free_full(scan_data->ssids, g_free);
+                               return -ENOMEM;
+                       }
+                       scan_data->freqs[scan_data->num_freqs - 1] = freq;
+               }
        }
 
        return 1;
 }
 
-static int get_hidden_connections(int max_ssids,
-                               GSupplicantScanParams *scan_data)
+static int get_hidden_connections(GSupplicantScanParams *scan_data)
 {
        struct connman_config_entry **entries;
        GKeyFile *keyfile;
@@ -415,13 +426,13 @@ static int get_hidden_connections(int max_ssids,
                name = g_key_file_get_string(keyfile, services[i], "Name",
                                                                NULL);
 
-               ret = add_scan_param(ssid, NULL, 0, freq, scan_data,
-                               max_ssids, name);
+               ret = add_scan_param(ssid, NULL, 0, freq, scan_data, 0, name);
                if (ret < 0)
                        add_param_failed++;
                else if (ret > 0)
                        num_ssids++;
 
+               g_free(ssid);
                g_free(name);
                g_key_file_free(keyfile);
        }
@@ -447,8 +458,7 @@ static int get_hidden_connections(int max_ssids,
                if (ssid == NULL)
                        continue;
 
-               ret = add_scan_param(NULL, ssid, len, 0, scan_data,
-                                                       max_ssids, ssid);
+               ret = add_scan_param(NULL, ssid, len, 0, scan_data, 0, ssid);
                if (ret < 0)
                        add_param_failed++;
                else if (ret > 0)
@@ -458,12 +468,82 @@ static int get_hidden_connections(int max_ssids,
        connman_config_free_entries(entries);
 
        if (add_param_failed > 0)
-               DBG("Unable to scan %d out of %d SSIDs (max is %d)",
-                       add_param_failed, num_ssids, max_ssids);
+               DBG("Unable to scan %d out of %d SSIDs",
+                                       add_param_failed, num_ssids);
 
        g_strfreev(services);
 
-       return num_ssids > max_ssids ? max_ssids : num_ssids;
+       return num_ssids;
+}
+
+static int get_hidden_connections_params(struct wifi_data *wifi,
+                                       GSupplicantScanParams *scan_params)
+{
+       int driver_max_ssids, i;
+       GSupplicantScanParams *orig_params;
+
+       /*
+        * Scan hidden networks so that we can autoconnect to them.
+        * We will assume 1 as a default number of ssid to scan.
+        */
+       driver_max_ssids = g_supplicant_interface_get_max_scan_ssids(
+                                                       wifi->interface);
+       if (driver_max_ssids == 0)
+               driver_max_ssids = 1;
+
+       DBG("max ssids %d", driver_max_ssids);
+
+       if (wifi->scan_params == NULL) {
+               wifi->scan_params = 
g_try_malloc0(sizeof(GSupplicantScanParams));
+               if (wifi->scan_params == NULL)
+                       return 0;
+
+               if (get_hidden_connections(wifi->scan_params) == 0) {
+                       g_supplicant_free_scan_params(wifi->scan_params);
+                       wifi->scan_params = NULL;
+
+                       return 0;
+               }
+       }
+
+       orig_params = wifi->scan_params;
+
+       /* Let's transfer driver_max_ssids params */
+       for (i = 0; i < driver_max_ssids; i++) {
+               struct scan_ssid *ssid;
+
+               if (wifi->scan_params->ssids == NULL)
+                       break;
+
+               ssid = orig_params->ssids->data;
+               orig_params->ssids = g_slist_remove(orig_params->ssids, ssid);
+               scan_params->ssids = g_slist_prepend(scan_params->ssids, ssid);
+       }
+
+       if (i > 0) {
+               scan_params->num_ssids = i;
+               scan_params->ssids = g_slist_reverse(scan_params->ssids);
+
+               scan_params->freqs = g_memdup(orig_params->freqs,
+                               sizeof(uint16_t) * orig_params->num_freqs);
+               if (scan_params->freqs == NULL)
+                       goto err;
+
+               scan_params->num_freqs = orig_params->num_freqs;
+
+       } else
+               goto err;
+
+       orig_params->num_ssids -= scan_params->num_ssids;
+
+       return scan_params->num_ssids;
+
+err:
+       g_slist_free_full(scan_params->ssids, g_free);
+       g_supplicant_free_scan_params(wifi->scan_params);
+       wifi->scan_params = NULL;
+
+       return 0;
 }
 
 static int throw_wifi_scan(struct connman_device *device,
@@ -514,10 +594,17 @@ static void scan_callback(int result, 
GSupplicantInterface *interface,
 
        DBG("result %d wifi %p", result, wifi);
 
-       if (wifi != NULL && wifi->hidden != NULL) {
-               connman_network_clear_hidden(wifi->hidden->user_data);
-               hidden_free(wifi->hidden);
-               wifi->hidden = NULL;
+       if (wifi != NULL) {
+               if (wifi->hidden != NULL) {
+                       connman_network_clear_hidden(wifi->hidden->user_data);
+                       hidden_free(wifi->hidden);
+                       wifi->hidden = NULL;
+               }
+
+               if (wifi->scan_params != NULL) {
+                       g_supplicant_free_scan_params(wifi->scan_params);
+                       wifi->scan_params = NULL;
+               }
        }
 
        if (result < 0)
@@ -548,32 +635,21 @@ static void scan_callback_hidden(int result,
        struct connman_device *device = user_data;
        struct wifi_data *wifi = connman_device_get_data(device);
        GSupplicantScanParams *scan_params;
-       int driver_max_ssids, ret;
+       int ret;
 
        DBG("result %d wifi %p", result, wifi);
 
        if (wifi == NULL)
                goto out;
 
-       /*
-        * Scan hidden networks so that we can autoconnect to them.
-        * We will assume 1 as a default number of ssid to scan.
-        */
-       driver_max_ssids = g_supplicant_interface_get_max_scan_ssids(
-                                                       wifi->interface);
-       if (driver_max_ssids == 0)
-               driver_max_ssids = 1;
-
-       DBG("max ssids %d", driver_max_ssids);
-
        scan_params = g_try_malloc0(sizeof(GSupplicantScanParams));
        if (scan_params == NULL)
                goto out;
 
-       if (get_hidden_connections(driver_max_ssids, scan_params) > 0) {
+       if (get_hidden_connections_params(wifi, scan_params) > 0) {
                ret = g_supplicant_interface_scan(wifi->interface,
                                                        scan_params,
-                                                       scan_callback,
+                                                       scan_callback_hidden,
                                                        device);
                if (ret == 0)
                        return;
-- 
1.8.2.1

_______________________________________________
connman mailing list
connman@connman.net
https://lists.connman.net/mailman/listinfo/connman

Reply via email to