wifi: probe-scan for hidden SSIDs
authorDan Williams <dcbw@redhat.com>
Wed, 2 May 2012 16:41:47 +0000 (11:41 -0500)
committerDan Williams <dcbw@redhat.com>
Wed, 2 May 2012 22:33:17 +0000 (17:33 -0500)
src/nm-device-wifi.c
src/supplicant-manager/nm-supplicant-interface.c
src/supplicant-manager/nm-supplicant-interface.h

index 1156973..f44eb3b 100644 (file)
@@ -153,8 +153,6 @@ struct _NMDeviceWifiPrivate {
        NMDeviceWifiCapabilities capabilities;
 };
 
-static gboolean request_wireless_scan (gpointer user_data);
-
 static void schedule_scan (NMDeviceWifi *self, gboolean backoff);
 
 static void cancel_pending_scan (NMDeviceWifi *self);
@@ -1545,20 +1543,102 @@ check_scanning_allowed (NMDeviceWifi *self)
 }
 
 static gboolean
+hidden_filter_func (NMConnectionProvider *provider,
+                    NMConnection *connection,
+                    gpointer user_data)
+{
+       NMSettingWireless *s_wifi;
+
+       s_wifi = (NMSettingWireless *) nm_connection_get_setting_wireless (connection);
+       return s_wifi ? nm_setting_wireless_get_hidden (s_wifi) : FALSE;
+}
+
+static GPtrArray *
+build_hidden_probe_list (NMDeviceWifi *self)
+{
+       NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+       guint max_scan_ssids = nm_supplicant_interface_get_max_scan_ssids (priv->supplicant.iface);
+       NMConnectionProvider *provider = nm_device_get_connection_provider (NM_DEVICE (self));
+       GSList *connections, *iter;
+       GPtrArray *ssids = NULL;
+       static GByteArray *nullssid = NULL;
+
+       /* Need at least two: wildcard SSID and one or more hidden SSIDs */
+       if (max_scan_ssids < 2)
+               return NULL;
+
+       /* Static wildcard SSID used for every scan */
+       if (G_UNLIKELY (nullssid == NULL))
+               nullssid = g_byte_array_new ();
+
+       connections = nm_connection_provider_get_best_connections (provider,
+                                                                  max_scan_ssids - 1,
+                                                                  NM_SETTING_WIRELESS_SETTING_NAME,
+                                                                  NULL,
+                                                                  hidden_filter_func,
+                                                                  NULL);
+       if (connections && connections->data) {
+               ssids = g_ptr_array_sized_new (max_scan_ssids - 1);
+               g_ptr_array_add (ssids, nullssid);  /* Add wildcard SSID */
+       }
+
+       for (iter = connections; iter; iter = g_slist_next (iter)) {
+               NMConnection *connection = iter->data;
+               NMSettingWireless *s_wifi;
+               const GByteArray *ssid;
+
+               s_wifi = (NMSettingWireless *) nm_connection_get_setting_wireless (connection);
+               g_assert (s_wifi);
+               ssid = nm_setting_wireless_get_ssid (s_wifi);
+               g_assert (ssid);
+               g_ptr_array_add (ssids, (gpointer) ssid);
+       }
+       g_slist_free (connections);
+
+       return ssids;
+}
+
+static gboolean
 request_wireless_scan (gpointer user_data)
 {
        NMDeviceWifi *self = NM_DEVICE_WIFI (user_data);
        NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
        gboolean backoff = FALSE;
+       GPtrArray *ssids = NULL;
 
        if (check_scanning_allowed (self)) {
                nm_log_dbg (LOGD_WIFI_SCAN, "(%s): scanning requested",
                            nm_device_get_iface (NM_DEVICE (self)));
 
-               if (nm_supplicant_interface_request_scan (priv->supplicant.iface)) {
+               ssids = build_hidden_probe_list (self);
+
+               if (nm_logging_level_enabled (LOGL_DEBUG)) {
+                       if (ssids) {
+                               guint i;
+                               char *foo;
+
+                               for (i = 0; i < ssids->len; i++) {
+                                       foo = nm_utils_ssid_to_utf8 (g_ptr_array_index (ssids, i));
+                                       nm_log_dbg (LOGD_WIFI_SCAN, "(%s): (%d) probe scanning SSID '%s'",
+                                                   nm_device_get_iface (NM_DEVICE (self)),
+                                                   i, foo ? foo : "<hidden>");
+                                       g_free (foo);
+                               }
+                       } else {
+                               nm_log_dbg (LOGD_WIFI_SCAN, "(%s): no SSIDs to probe scan",
+                                           nm_device_get_iface (NM_DEVICE (self)));
+                       }
+               }
+
+               if (nm_supplicant_interface_request_scan (priv->supplicant.iface, ssids)) {
                        /* success */
                        backoff = TRUE;
                }
+
+               if (ssids) {
+                       /* Elements owned by the connections, so we don't free them here */
+                       g_ptr_array_free (ssids, TRUE);
+               }
        } else {
                nm_log_dbg (LOGD_WIFI_SCAN, "(%s): scan requested but not allowed at this time",
                            nm_device_get_iface (NM_DEVICE (self)));
index 711fb76..ef9f7ce 100644 (file)
@@ -1202,8 +1202,18 @@ string_to_gvalue (const char *str)
        return val;
 }
 
+static GValue *
+byte_array_array_to_gvalue (const GPtrArray *array)
+{
+       GValue *val = g_slice_new0 (GValue);
+
+       g_value_init (val, DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UCHAR);
+       g_value_set_boxed (val, array);
+       return val;
+}
+
 gboolean
-nm_supplicant_interface_request_scan (NMSupplicantInterface * self)
+nm_supplicant_interface_request_scan (NMSupplicantInterface *self, const GPtrArray *ssids)
 {
        NMSupplicantInterfacePrivate *priv;
        NMSupplicantInfo *info;
@@ -1217,6 +1227,8 @@ nm_supplicant_interface_request_scan (NMSupplicantInterface * self)
        /* Scan parameters */
        hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, destroy_gvalue);
        g_hash_table_insert (hash, "Type", string_to_gvalue ("active"));
+       if (ssids)
+               g_hash_table_insert (hash, "SSIDs", byte_array_array_to_gvalue (ssids));
 
        info = nm_supplicant_info_new (self, priv->iface_proxy, priv->other_pcalls);
        call = dbus_g_proxy_begin_call (priv->iface_proxy, "Scan",
index 98ef713..c417e9b 100644 (file)
@@ -127,7 +127,7 @@ const char * nm_supplicant_interface_get_device (NMSupplicantInterface * iface);
 
 const char *nm_supplicant_interface_get_object_path (NMSupplicantInterface * iface);
 
-gboolean nm_supplicant_interface_request_scan (NMSupplicantInterface * self);
+gboolean nm_supplicant_interface_request_scan (NMSupplicantInterface * self, const GPtrArray *ssids);
 
 guint32 nm_supplicant_interface_get_state (NMSupplicantInterface * self);