diff options
| author | Michael Biebl <biebl@debian.org> | 2012-03-24 01:37:02 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2012-03-24 01:37:02 +0100 |
| commit | de06e5715e780baade318f3490ac7a4c9ce84e32 (patch) | |
| tree | 23fbc3fafc12072476eff98bee60100eb54c29db /src/supplicant-manager/nm-supplicant-interface.c | |
| parent | b436a68a20ff3114ded32a7a3d70cdd4954039f9 (diff) | |
Imported Upstream version 0.9.4.0 upstream/0.9.4.0
Diffstat (limited to 'src/supplicant-manager/nm-supplicant-interface.c')
| -rw-r--r-- | src/supplicant-manager/nm-supplicant-interface.c | 353 |
1 files changed, 317 insertions, 36 deletions
diff --git a/src/supplicant-manager/nm-supplicant-interface.c b/src/supplicant-manager/nm-supplicant-interface.c index 857cde51..f8ad8f18 100644 --- a/src/supplicant-manager/nm-supplicant-interface.c +++ b/src/supplicant-manager/nm-supplicant-interface.c @@ -15,10 +15,11 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2006 - 2010 Red Hat, Inc. + * Copyright (C) 2006 - 2012 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ +#include <config.h> #include <stdio.h> #include <string.h> #include <glib.h> @@ -55,11 +56,14 @@ static void wpas_iface_scan_done (DBusGProxy *proxy, /* Signals */ enum { - STATE, /* change in the interface's state */ - REMOVED, /* interface was removed by the supplicant */ - NEW_BSS, /* interface saw a new access point from a scan */ - SCAN_DONE, /* wifi scan is complete */ - CONNECTION_ERROR, /* an error occurred during a connection request */ + STATE, /* change in the interface's state */ + REMOVED, /* interface was removed by the supplicant */ + NEW_BSS, /* interface saw a new access point from a scan */ + BSS_UPDATED, /* a BSS property changed */ + BSS_REMOVED, /* supplicant removed BSS from its scan list */ + SCAN_DONE, /* wifi scan is complete */ + CONNECTION_ERROR, /* an error occurred during a connection request */ + CREDENTIALS_REQUEST, /* 802.1x identity or password requested */ LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = { 0 }; @@ -79,6 +83,8 @@ typedef struct { NMDBusManager * dbus_mgr; char * dev; gboolean is_wireless; + gboolean has_credreq; /* Whether querying 802.1x credentials is supported */ + gboolean fast_supported; char * object_path; guint32 state; @@ -92,6 +98,7 @@ typedef struct { DBusGProxy * props_proxy; char * net_path; guint32 blobs_left; + GHashTable * bss_proxies; guint32 last_scan; @@ -100,6 +107,28 @@ typedef struct { gboolean disposed; } NMSupplicantInterfacePrivate; +/* FIXME: remove this and just store the standard D-Bus properties + * proxy object in bss_proxies when we drop support for wpa_supplicant + * 0.7.x. + */ +typedef struct { + /* Proxy for standard D-Bus Properties interface */ + DBusGProxy *props; + /* Proxy for old wpa_supplicant-specific PropertiesChanged signal */ + DBusGProxy *old_props; +} BssProxies; + +static void +bss_proxies_free (gpointer data) +{ + BssProxies *proxies = data; + + g_object_unref (proxies->props); + g_object_unref (proxies->old_props); + memset (proxies, 0, sizeof (*proxies)); + g_free (proxies); +} + static gboolean cancel_all_cb (GObject *object, gpointer call_id, gpointer user_data) { @@ -192,6 +221,14 @@ emit_error_helper (NMSupplicantInterface *self, } static void +signal_new_bss (NMSupplicantInterface *self, + const char *object_path, + GHashTable *props) +{ + g_signal_emit (self, signals[NEW_BSS], 0, object_path, props); +} + +static void bssid_properties_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) { NMSupplicantInfo *info = (NMSupplicantInfo *) user_data; @@ -201,7 +238,7 @@ bssid_properties_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_ if (dbus_g_proxy_end_call (proxy, call_id, &error, DBUS_TYPE_G_MAP_OF_VARIANT, &props, G_TYPE_INVALID)) { - g_signal_emit (info->interface, signals[NEW_BSS], 0, props); + signal_new_bss (info->interface, dbus_g_proxy_get_path (proxy), props); g_hash_table_destroy (props); } else { if (!strstr (error->message, "The BSSID requested was invalid")) { @@ -213,31 +250,93 @@ bssid_properties_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_ } static void -request_bss_properties (NMSupplicantInterface *self, - GPtrArray *paths) +bss_properties_changed (DBusGProxy *proxy, + const char *interface, + GHashTable *props, + const char **unused, + gpointer user_data) +{ + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + + if (g_strcmp0 (interface, WPAS_DBUS_IFACE_BSS) == 0) + g_signal_emit (self, signals[BSS_UPDATED], 0, dbus_g_proxy_get_path (proxy), props); +} + +static void +old_bss_properties_changed (DBusGProxy *proxy, + GHashTable *props, + gpointer user_data) +{ + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + + g_signal_emit (self, signals[BSS_UPDATED], 0, dbus_g_proxy_get_path (proxy), props); +} + +static void +handle_new_bss (NMSupplicantInterface *self, + const char *object_path, + GHashTable *props) { NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - int i; - - /* Fire off a "properties" call for each returned BSSID */ - for (i = 0; i < paths->len; i++) { - NMSupplicantInfo *info; - DBusGProxy *proxy; - DBusGProxyCall *call; - - proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr), - WPAS_DBUS_SERVICE, - g_ptr_array_index (paths, i), - DBUS_INTERFACE_PROPERTIES); - info = nm_supplicant_info_new (self, proxy, priv->other_pcalls); - call = dbus_g_proxy_begin_call (proxy, "GetAll", - bssid_properties_cb, - info, - nm_supplicant_info_destroy, - G_TYPE_STRING, WPAS_DBUS_IFACE_BSS, - G_TYPE_INVALID); + NMSupplicantInfo *info; + DBusGProxyCall *call; + BssProxies *proxies; + + g_return_if_fail (object_path != NULL); + + if (g_hash_table_lookup (priv->bss_proxies, object_path)) + return; + + proxies = g_malloc0 (sizeof (*proxies)); + proxies->props = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr), + WPAS_DBUS_SERVICE, + object_path, + DBUS_INTERFACE_PROPERTIES); + proxies->old_props = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr), + WPAS_DBUS_SERVICE, + object_path, + WPAS_DBUS_IFACE_BSS); + g_hash_table_insert (priv->bss_proxies, + (gpointer) dbus_g_proxy_get_path (proxies->props), + proxies); + + /* Standard D-Bus PropertiesChanged signal */ + dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_BOXED_BOXED, + G_TYPE_NONE, + G_TYPE_STRING, DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_STRV, + G_TYPE_INVALID); + dbus_g_proxy_add_signal (proxies->props, "PropertiesChanged", + G_TYPE_STRING, DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_STRV, + G_TYPE_INVALID); + dbus_g_proxy_connect_signal (proxies->props, "PropertiesChanged", + G_CALLBACK (bss_properties_changed), + self, NULL); + + /* Old wpa_supplicant-specific PropertiesChanged signal; since it's using + * a different interface, we have to use a different DBusGProxy + */ + dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, + DBUS_TYPE_G_MAP_OF_VARIANT, + G_TYPE_INVALID); + dbus_g_proxy_add_signal (proxies->old_props, "PropertiesChanged", + DBUS_TYPE_G_MAP_OF_VARIANT, + G_TYPE_INVALID); + dbus_g_proxy_connect_signal (proxies->old_props, "PropertiesChanged", + G_CALLBACK (old_bss_properties_changed), + self, NULL); + + if (props) { + signal_new_bss (self, object_path, props); + } else { + info = nm_supplicant_info_new (self, proxies->props, priv->other_pcalls); + call = dbus_g_proxy_begin_call (proxies->props, "GetAll", + bssid_properties_cb, + info, + nm_supplicant_info_destroy, + G_TYPE_STRING, WPAS_DBUS_IFACE_BSS, + G_TYPE_INVALID); nm_supplicant_info_set_call (info, call); - g_object_unref (proxy); } } @@ -247,7 +346,20 @@ wpas_iface_bss_added (DBusGProxy *proxy, GHashTable *props, gpointer user_data) { - g_signal_emit (NM_SUPPLICANT_INTERFACE (user_data), signals[NEW_BSS], 0, props); + handle_new_bss (NM_SUPPLICANT_INTERFACE (user_data), object_path, props); +} + +static void +wpas_iface_bss_removed (DBusGProxy *proxy, + const char *object_path, + gpointer user_data) +{ + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + g_signal_emit (self, signals[BSS_REMOVED], 0, object_path); + + g_hash_table_remove (priv->bss_proxies, object_path); } static int @@ -318,6 +430,10 @@ set_state (NMSupplicantInterface *self, guint32 new_state) "BSSAdded", G_CALLBACK (wpas_iface_bss_added), self); + dbus_g_proxy_disconnect_signal (priv->iface_proxy, + "BSSRemoved", + G_CALLBACK (wpas_iface_bss_removed), + self); } } @@ -403,8 +519,13 @@ wpas_iface_properties_changed (DBusGProxy *proxy, set_state_from_string (self, g_value_get_string (value)); value = g_hash_table_lookup (props, "BSSs"); - if (value && G_VALUE_HOLDS (value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH)) - request_bss_properties (self, g_value_get_boxed (value)); + if (value && G_VALUE_HOLDS (value, DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH)) { + GPtrArray *paths = g_value_get_boxed (value); + int i; + + for (i = 0; paths && (i < paths->len); i++) + handle_new_bss (self, g_ptr_array_index (paths, i), NULL); + } } static void @@ -443,6 +564,92 @@ wpas_iface_get_props (NMSupplicantInterface *self) nm_supplicant_info_set_call (info, call); } +gboolean +nm_supplicant_interface_credentials_reply (NMSupplicantInterface *self, + const char *field, + const char *value, + GError **error) +{ + NMSupplicantInterfacePrivate *priv; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), FALSE); + g_return_val_if_fail (field != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + g_return_val_if_fail (priv->has_credreq == TRUE, FALSE); + + /* Need a network block object path */ + g_return_val_if_fail (priv->net_path, FALSE); + return dbus_g_proxy_call_with_timeout (priv->iface_proxy, "NetworkReply", + 5000, + error, + DBUS_TYPE_G_OBJECT_PATH, priv->net_path, + G_TYPE_STRING, field, + G_TYPE_STRING, value, + G_TYPE_INVALID); +} + +static void +wpas_iface_network_request (DBusGProxy *proxy, + const char *object_path, + const char *field, + const char *message, + gpointer user_data) +{ + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + g_return_if_fail (priv->has_credreq == TRUE); + g_return_if_fail (priv->net_path != NULL); + g_return_if_fail (g_strcmp0 (object_path, priv->net_path) == 0); + + g_signal_emit (self, signals[CREDENTIALS_REQUEST], 0, field, message); +} + +static void +iface_check_netreply_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) +{ + NMSupplicantInfo *info = (NMSupplicantInfo *) user_data; + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (info->interface); + GError *error = NULL; + + if ( dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID) + || dbus_g_error_has_name (error, "fi.w1.wpa_supplicant1.InvalidArgs")) { + /* We know NetworkReply is supported if the NetworkReply method returned + * successfully (which is unexpected since we sent a bogus network + * object path) or if we got an "InvalidArgs" (which indicates NetworkReply + * is supported). We know it's not supported if we get an + * "UnknownMethod" error. + */ + priv->has_credreq = TRUE; + + nm_log_dbg (LOGD_SUPPLICANT, "Supplicant %s network credentials requests", + priv->has_credreq ? "supports" : "does not support"); + } + g_clear_error (&error); +} + +static void +wpas_iface_check_network_reply (NMSupplicantInterface *self) +{ + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + NMSupplicantInfo *info; + DBusGProxyCall *call; + + info = nm_supplicant_info_new (self, priv->props_proxy, priv->other_pcalls); + call = dbus_g_proxy_begin_call (priv->iface_proxy, "NetworkReply", + iface_check_netreply_cb, + info, + nm_supplicant_info_destroy, + DBUS_TYPE_G_OBJECT_PATH, "/foobaraasdfasdf", + G_TYPE_STRING, "foobar", + G_TYPE_STRING, "foobar", + G_TYPE_INVALID); + nm_supplicant_info_set_call (info, call); +} + static void interface_add_done (NMSupplicantInterface *self, char *path) { @@ -486,6 +693,30 @@ interface_add_done (NMSupplicantInterface *self, char *path) self, NULL); + dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, + DBUS_TYPE_G_OBJECT_PATH, + G_TYPE_INVALID); + dbus_g_proxy_add_signal (priv->iface_proxy, "BSSRemoved", + DBUS_TYPE_G_OBJECT_PATH, + G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->iface_proxy, "BSSRemoved", + G_CALLBACK (wpas_iface_bss_removed), + self, + NULL); + + dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_STRING_STRING, + G_TYPE_NONE, + DBUS_TYPE_G_OBJECT_PATH, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_INVALID); + dbus_g_proxy_add_signal (priv->iface_proxy, "NetworkRequest", + DBUS_TYPE_G_OBJECT_PATH, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_INVALID); + dbus_g_proxy_connect_signal (priv->iface_proxy, "NetworkRequest", + G_CALLBACK (wpas_iface_network_request), + self, + NULL); + priv->props_proxy = dbus_g_proxy_new_for_name (nm_dbus_manager_get_connection (priv->dbus_mgr), WPAS_DBUS_SERVICE, path, @@ -493,6 +724,9 @@ interface_add_done (NMSupplicantInterface *self, char *path) /* Get initial properties */ wpas_iface_get_props (self); + /* Check whether NetworkReply is supported */ + wpas_iface_check_network_reply (self); + set_state (self, NM_SUPPLICANT_INTERFACE_STATE_READY); } @@ -574,6 +808,12 @@ interface_add_cb (DBusGProxy *proxy, } } +#if HAVE_WEXT +#define DEFAULT_WIFI_DRIVER "nl80211,wext" +#else +#define DEFAULT_WIFI_DRIVER "nl80211" +#endif + static void interface_add (NMSupplicantInterface *self, gboolean is_wireless) { @@ -602,7 +842,7 @@ interface_add (NMSupplicantInterface *self, gboolean is_wireless) driver = g_new0 (GValue, 1); g_value_init (driver, G_TYPE_STRING); - g_value_set_string (driver, is_wireless ? "nl80211,wext" : "wired"); + g_value_set_string (driver, is_wireless ? DEFAULT_WIFI_DRIVER : "wired"); g_hash_table_insert (hash, "Driver", driver); ifname = g_new0 (GValue, 1); @@ -851,7 +1091,15 @@ nm_supplicant_interface_set_config (NMSupplicantInterface * self, priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); nm_supplicant_interface_disconnect (self); - + + /* Make sure the supplicant supports EAP-FAST before trying to send + * it an EAP-FAST configuration. + */ + if (nm_supplicant_config_fast_required (cfg) && !priv->fast_supported) { + nm_log_warn (LOGD_SUPPLICANT, "EAP-FAST is not supported by the supplicant"); + return FALSE; + } + if (priv->cfg) g_object_unref (priv->cfg); priv->cfg = cfg; @@ -1017,6 +1265,7 @@ NMSupplicantInterface * nm_supplicant_interface_new (NMSupplicantManager *smgr, const char *ifname, gboolean is_wireless, + gboolean fast_supported, gboolean start_now) { NMSupplicantInterface *self; @@ -1039,6 +1288,7 @@ nm_supplicant_interface_new (NMSupplicantManager *smgr, priv->dev = g_strdup (ifname); priv->is_wireless = is_wireless; + priv->fast_supported = fast_supported; if (start_now) interface_add (self, priv->is_wireless); @@ -1063,6 +1313,8 @@ nm_supplicant_interface_init (NMSupplicantInterface * self) WPAS_DBUS_SERVICE, WPAS_DBUS_PATH, WPAS_DBUS_INTERFACE); + + priv->bss_proxies = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, bss_proxies_free); } static void @@ -1123,6 +1375,8 @@ dispose (GObject *object) if (priv->wpas_proxy) g_object_unref (priv->wpas_proxy); + g_hash_table_destroy (priv->bss_proxies); + if (priv->smgr) { if (priv->smgr_avail_id) g_signal_handler_disconnect (priv->smgr, priv->smgr_avail_id); @@ -1187,8 +1441,26 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NMSupplicantInterfaceClass, new_bss), NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); + _nm_marshal_VOID__STRING_POINTER, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER); + + signals[BSS_UPDATED] = + g_signal_new (NM_SUPPLICANT_INTERFACE_BSS_UPDATED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMSupplicantInterfaceClass, bss_updated), + NULL, NULL, + _nm_marshal_VOID__STRING_POINTER, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER); + + signals[BSS_REMOVED] = + g_signal_new (NM_SUPPLICANT_INTERFACE_BSS_REMOVED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMSupplicantInterfaceClass, bss_removed), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); signals[SCAN_DONE] = g_signal_new (NM_SUPPLICANT_INTERFACE_SCAN_DONE, @@ -1207,5 +1479,14 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) NULL, NULL, _nm_marshal_VOID__STRING_STRING, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); + + signals[CREDENTIALS_REQUEST] = + g_signal_new (NM_SUPPLICANT_INTERFACE_CREDENTIALS_REQUEST, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMSupplicantInterfaceClass, credentials_request), + NULL, NULL, + _nm_marshal_VOID__STRING_STRING, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); } |