diff --git a/ChangeLog b/ChangeLog index 819e46d49e..10881da55f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,30 @@ +2006-12-19 Dan Williams + + Big wpa_supplicant + dbus update; need latest wpa_supplicant from CVS + plus a few other patches from wpa_supplicant bugzilla. + + * src/Makefile.am + src/NetworkManagerPolicy.c + src/NetworkManagerUtils.c + src/NetworkManagerUtils.h + src/nm-ap-security-leap.c + src/nm-ap-security-wep.c + src/nm-ap-security-wpa-eap.c + src/nm-ap-security-wpa-psk.c + src/nm-ap-security.c + src/nm-ap-security.h + src/nm-device-802-11-wireless.c + src/nm-device-802-11-wireless.h + src/supplicant-manager/nm-supplicant-config.c + src/supplicant-manager/nm-supplicant-config.h + src/supplicant-manager/nm-supplicant-interface.c + src/supplicant-manager/nm-supplicant-interface.h + src/supplicant-manager/nm-supplicant-marshal.list + src/supplicant-manager/nm-supplicant-settings-verify.c + src/supplicant-manager/nm-supplicant-settings-verify.h + - Move all connection management and association handling to + wpa_supplicant over dbus, rather than spawning a private copy + 2006-12-19 Dan Williams * src/NetworkManagerPolicy.c diff --git a/src/Makefile.am b/src/Makefile.am index 7b7b2e5c35..53cb168214 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -70,9 +70,7 @@ NetworkManager_SOURCES = \ nm-marshal-main.c \ kernel-types.h \ wpa.c \ - wpa.h \ - wpa_ctrl.c \ - wpa_ctrl.h + wpa.h nm-marshal.h: Makefile.am nm-marshal.list $(GLIB_GENMARSHAL) --prefix=nm_marshal $(srcdir)/nm-marshal.list --header > \ diff --git a/src/NetworkManagerPolicy.c b/src/NetworkManagerPolicy.c index 95ea24b4aa..ea78d89f41 100644 --- a/src/NetworkManagerPolicy.c +++ b/src/NetworkManagerPolicy.c @@ -255,11 +255,15 @@ static NMDevice * nm_policy_auto_get_best_device (NMData *data, NMAccessPoint ** highest_priority_dev = NM_DEVICE (best_wired_dev); else if (best_wireless_dev) { + gboolean can_activate; + + can_activate = nm_device_802_11_wireless_can_activate (best_wireless_dev); + *ap = nm_device_802_11_wireless_get_best_ap (best_wireless_dev); /* If the device doesn't have a "best" ap, then we can't use it */ if (!*ap) highest_priority_dev = NULL; - else + else if (can_activate == TRUE) highest_priority_dev = NM_DEVICE (best_wireless_dev); } diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index efaf14340f..f2ef6a4a10 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -39,7 +39,6 @@ #include "nm-device.h" #include "nm-device-802-11-wireless.h" #include "nm-device-802-3-ethernet.h" -#include "wpa_ctrl.h" #include #include @@ -716,129 +715,3 @@ int nm_utils_ip4_netmask_to_prefix (guint32 ip4_netmask) return (32 - (i-1)); } - -#define SUPPLICANT_DEBUG -#define RESPONSE_SIZE 2048 - - -static char * -kill_newline (char *s, size_t *l) -{ - g_return_val_if_fail (l != NULL, s); - - while ((--(*l) > 0) && (s[*l] != '\n')) - ; - if (s[*l] == '\n') - s[*l] = '\0'; - return s; -} - - -char * -nm_utils_supplicant_request (struct wpa_ctrl *ctrl, - const char *format, - ...) -{ - va_list args; - size_t len; - char * response = NULL; - char * command; - - g_return_val_if_fail (ctrl != NULL, NULL); - g_return_val_if_fail (format != NULL, NULL); - - va_start (args, format); - if (!(command = g_strdup_vprintf (format, args))) - return NULL; - va_end (args); - - response = g_malloc (RESPONSE_SIZE); - len = RESPONSE_SIZE; -#ifdef SUPPLICANT_DEBUG - nm_info ("SUP: sending command '%s'", command); -#endif - wpa_ctrl_request (ctrl, command, strlen (command), response, &len, NULL); - g_free (command); - response[len] = '\0'; -#ifdef SUPPLICANT_DEBUG - { - response = kill_newline (response, &len); - nm_info ("SUP: response was '%s'", response); - } -#endif - return response; -} - - -gboolean -nm_utils_supplicant_request_with_check (struct wpa_ctrl *ctrl, - const char *expected, - const char *func, - const char *err_msg_cmd, - const char *format, - ...) -{ - va_list args; - gboolean success = FALSE; - size_t len; - char * response = NULL; - char * command; - char * temp; - - g_return_val_if_fail (ctrl != NULL, FALSE); - g_return_val_if_fail (expected != NULL, FALSE); - g_return_val_if_fail (format != NULL, FALSE); - - va_start (args, format); - if (!(command = g_strdup_vprintf (format, args))) - goto out; - - response = g_malloc (RESPONSE_SIZE); - len = RESPONSE_SIZE; -#ifdef SUPPLICANT_DEBUG - /* Hack: don't print anything out for SCAN commands since they - * happen so often. - */ - if (strcmp (command, "SCAN") != 0) - nm_info ("SUP: sending command '%s'", err_msg_cmd ? err_msg_cmd : command); -#endif - wpa_ctrl_request (ctrl, command, strlen (command), response, &len, NULL); - response[len] = '\0'; -#ifdef SUPPLICANT_DEBUG - /* Hack: don't print anything out for SCAN commands since they - * happen so often. - */ - if (strcmp (command, "SCAN") != 0) { - response = kill_newline (response, &len); - nm_info ("SUP: response was '%s'", response); - } -#endif - - if (response) - { - if (strncmp (response, expected, strlen (expected)) == 0) - success = TRUE; - else - { - response = kill_newline (response, &len); - temp = g_strdup_printf ("%s: supplicant error for '%s'. Response: '%s'", - func, err_msg_cmd ? err_msg_cmd : command, response); - nm_warning_str (temp); - g_free (temp); - } - g_free (response); - } - else - { - temp = g_strdup_printf ("%s: supplicant error for '%s'. No response.", - func, err_msg_cmd ? err_msg_cmd : command); - nm_warning_str (temp); - g_free (temp); - } - g_free (command); - -out: - va_end (args); - return success; -} - diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index acf2eea4ac..959493bfd0 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -107,15 +107,4 @@ struct nl_addr * nm_utils_ip4_addr_to_nl_addr (guint32 ip4_addr); int nm_utils_ip4_netmask_to_prefix (guint32 ip4_netmask); -char * nm_utils_supplicant_request (struct wpa_ctrl *ctrl, - const char *format, - ...); - -gboolean nm_utils_supplicant_request_with_check (struct wpa_ctrl *ctrl, - const char *expected, - const char *func, - const char *alt_cmd_for_err_msg, - const char *format, - ...); - #endif diff --git a/src/nm-ap-security-leap.c b/src/nm-ap-security-leap.c index 1933d6233b..795e6c033b 100644 --- a/src/nm-ap-security-leap.c +++ b/src/nm-ap-security-leap.c @@ -29,7 +29,7 @@ #include "nm-ap-security-private.h" #include "dbus-helpers.h" #include "nm-device-802-11-wireless.h" -#include "NetworkManagerUtils.h" +#include "nm-supplicant-config.h" #define NM_AP_SECURITY_LEAP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AP_SECURITY_LEAP, NMAPSecurityLEAPPrivate)) @@ -98,42 +98,32 @@ real_serialize (NMAPSecurity *instance, DBusMessageIter *iter) static gboolean real_write_supplicant_config (NMAPSecurity *instance, - struct wpa_ctrl *ctrl, - int nwid, + NMSupplicantConfig * config, gboolean user_created) { - NMAPSecurityLEAP * self = NM_AP_SECURITY_LEAP (instance); - gboolean success = FALSE; - char * msg; - const char * password = nm_ap_security_get_key(instance); + NMAPSecurityLEAP * self = NM_AP_SECURITY_LEAP (instance); + gboolean success = FALSE; + const char * password = nm_ap_security_get_key (instance); g_return_val_if_fail (nm_ap_security_get_we_cipher (instance) == NM_AUTH_TYPE_LEAP, FALSE); - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, "SET_NETWORK %i proto WPA", nwid)) + if (!nm_supplicant_config_add_option (config, "proto", "WPA", -1)) goto out; - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, "SET_NETWORK %i key_mgmt %s", - nwid, self->priv->key_mgmt)) + if (!nm_supplicant_config_add_option (config, "key_mgmt", self->priv->key_mgmt, -1)) goto out; - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, "SET_NETWORK %i eap LEAP", nwid)) + if (!nm_supplicant_config_add_option (config, "eap", "LEAP", -1)) goto out; - if (self->priv->username && strlen (self->priv->username) > 0) - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, "SET_NETWORK %i identity \"%s\"", - nwid, self->priv->username)) + if (self->priv->username && strlen (self->priv->username) > 0) { + if (!nm_supplicant_config_add_option (config, "identity", self->priv->username, -1)) goto out; + } - if (password && strlen (password) > 0) - { - msg = g_strdup_printf ("SET_NETWORK %i password ", nwid); - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, msg, "SET_NETWORK %i password \"%s\"", - nwid, password)) - { - g_free (msg); + if (password && strlen (password) > 0) { + if (!nm_supplicant_config_add_option (config, "password", password, -1)) goto out; - } - g_free (msg); } success = TRUE; diff --git a/src/nm-ap-security-wep.c b/src/nm-ap-security-wep.c index fcd806b3dc..12ce58c92b 100644 --- a/src/nm-ap-security-wep.c +++ b/src/nm-ap-security-wep.c @@ -30,7 +30,7 @@ #include "dbus-helpers.h" #include "nm-device-802-11-wireless.h" #include "nm-utils.h" -#include "NetworkManagerUtils.h" +#include "nm-supplicant-config.h" #define NM_AP_SECURITY_WEP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AP_SECURITY_WEP, NMAPSecurityWEPPrivate)) @@ -113,40 +113,39 @@ real_serialize (NMAPSecurity *instance, DBusMessageIter *iter) static gboolean real_write_supplicant_config (NMAPSecurity *instance, - struct wpa_ctrl *ctrl, - int nwid, + NMSupplicantConfig * config, gboolean adhoc) { - gboolean success = FALSE; - char * msg = NULL; - const char * key = nm_ap_security_get_key (instance); + gboolean success = FALSE; + const char * key = nm_ap_security_get_key (instance); + char * bin_key = NULL; /* WEP network setup */ - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, - "SET_NETWORK %i key_mgmt NONE", nwid)) + if (!nm_supplicant_config_add_option (config, "key_mgmt", "NONE", -1)) goto out; /* * If the user selected "Shared" (aka restricted) key, set it explicitly. Otherwise, * let wpa_supplicant default to the right thing, which is an open key. */ - if (get_auth_algorithm (NM_AP_SECURITY_WEP (instance)) == IW_AUTH_ALG_SHARED_KEY) - { - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, msg, - "SET_NETWORK %i auth_alg SHARED", nwid)); + if (get_auth_algorithm (NM_AP_SECURITY_WEP (instance)) == IW_AUTH_ALG_SHARED_KEY) { + if (!nm_supplicant_config_add_option (config, "auth_alg", "SHARED", -1)) + goto out; } - msg = g_strdup_printf ("SET_NETWORK %i wep_key0 ", nwid); - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, msg, - "SET_NETWORK %i wep_key0 %s", nwid, key)) - { - g_free (msg); + bin_key = cipher_hexstr2bin(key, strlen (key)); + if (bin_key == NULL) { + nm_warning ("Not enough memory to convert key."); goto out; } - g_free (msg); - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, - "SET_NETWORK %i wep_tx_keyidx 0", nwid)) + if (!nm_supplicant_config_add_option (config, "wep_key0", bin_key, -1)) { + g_free (bin_key); + goto out; + } + g_free (bin_key); + + if (!nm_supplicant_config_add_option (config, "wep_tx_keyidx", "0", -1)) goto out; success = TRUE; diff --git a/src/nm-ap-security-wpa-eap.c b/src/nm-ap-security-wpa-eap.c index 26b42a67ec..7d13ffc448 100644 --- a/src/nm-ap-security-wpa-eap.c +++ b/src/nm-ap-security-wpa-eap.c @@ -30,7 +30,7 @@ #include "nm-ap-security-private.h" #include "dbus-helpers.h" #include "nm-device-802-11-wireless.h" -#include "NetworkManagerUtils.h" +#include "nm-supplicant-config.h" #define NM_AP_SECURITY_WPA_EAP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AP_SECURITY_WPA_EAP, NMAPSecurityWPA_EAPPrivate)) @@ -167,24 +167,22 @@ get_eap_method (int eap_method) static gboolean real_write_supplicant_config (NMAPSecurity *instance, - struct wpa_ctrl *ctrl, - int nwid, + NMSupplicantConfig * config, gboolean adhoc) { NMAPSecurityWPA_EAP * self = NM_AP_SECURITY_WPA_EAP (instance); - gboolean success = FALSE; - char * msg; - const char * identity = self->priv->identity; - const char * anon_identity = self->priv->anon_identity; - const char * passwd = self->priv->passwd; - const char * private_key_passwd = self->priv->private_key_passwd; - const char * private_key_file = self->priv->private_key_file; - const char * ca_cert_file = self->priv->ca_cert_file; - const char * client_cert_file = self->priv->client_cert_file; - int wpa_version = self->priv->wpa_version; - int key_mgmt = self->priv->key_mgmt; - int eap_method = self->priv->eap_method; - int key_type = self->priv->key_type; + gboolean success = FALSE; + const char * identity = self->priv->identity; + const char * anon_identity = self->priv->anon_identity; + const char * passwd = self->priv->passwd; + const char * private_key_passwd = self->priv->private_key_passwd; + const char * private_key_file = self->priv->private_key_file; + const char * ca_cert_file = self->priv->ca_cert_file; + const char * client_cert_file = self->priv->client_cert_file; + int wpa_version = self->priv->wpa_version; + int key_mgmt = self->priv->key_mgmt; + int eap_method = self->priv->eap_method; + int key_type = self->priv->key_type; g_return_val_if_fail (nm_ap_security_get_we_cipher (instance) == NM_AUTH_TYPE_WPA_EAP, FALSE); g_return_val_if_fail (key_mgmt == IW_AUTH_KEY_MGMT_802_1X, FALSE); @@ -204,80 +202,66 @@ real_write_supplicant_config (NMAPSecurity *instance, /* WPA-EAP network setup */ - if (self->priv->wpa_version == IW_AUTH_WPA_VERSION_WPA) - { - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, "SET_NETWORK %i proto WPA", nwid)) + if (self->priv->wpa_version == IW_AUTH_WPA_VERSION_WPA) { + if (!nm_supplicant_config_add_option (config, "proto", "WPA", -1)) goto out; - } - else - { - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, "SET_NETWORK %i proto WPA2", nwid)) + } else { + if (!nm_supplicant_config_add_option (config, "proto", "WPA2", -1)) goto out; } - if (key_type != IW_AUTH_CIPHER_WEP104) - { - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, "SET_NETWORK %i key_mgmt WPA-EAP", nwid)) + if (key_type != IW_AUTH_CIPHER_WEP104) { + if (!nm_supplicant_config_add_option (config, "key_mgmt", "WPA-EAP", -1)) goto out; - } - else - { + } else { /* So-called Dynamic WEP */ - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, "SET_NETWORK %i key_mgmt IEEE8021X", nwid)) + if (!nm_supplicant_config_add_option (config, "key_mgmt", "IEEE8021X", -1)) goto out; } - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, "SET_NETWORK %i eap %s", nwid, get_eap_method (eap_method))) + if (!nm_supplicant_config_add_option (config, "eap", get_eap_method (eap_method), -1)) goto out; - if (identity && strlen (identity) > 0) - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, "SET_NETWORK %i identity \"%s\"", nwid, identity)) + if (identity && strlen (identity) > 0) { + if (!nm_supplicant_config_add_option (config, "identity", identity, -1)) goto out; - - if (passwd && strlen (passwd) > 0) - { - msg = g_strdup_printf ("SET_NETWORK %i password ", nwid); - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, msg, "SET_NETWORK %i password \"%s\"", nwid, passwd)) - { - g_free (msg); - goto out; - } - g_free (msg); } - if (anon_identity && strlen (anon_identity) > 0) - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, "SET_NETWORK %i anonymous_identity \"%s\"", nwid, anon_identity)) + if (passwd && strlen (passwd) > 0) { + if (!nm_supplicant_config_add_option (config, "password", passwd, -1)) goto out; - - if (private_key_file && strlen (private_key_file) > 0) - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, "SET_NETWORK %i private_key \"%s\"", nwid, private_key_file)) - goto out; - - if (private_key_passwd && strlen (private_key_passwd) > 0) - { - msg = g_strdup_printf ("SET_NETWORK %i private_key_passwd ", nwid); - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, msg, "SET_NETWORK %i private_key_passwd \"%s\"", nwid, private_key_passwd)) - { - g_free (msg); - goto out; - } - g_free (msg); } - if (client_cert_file && strlen (client_cert_file) > 0) - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, "SET_NETWORK %i client_cert \"%s\"", nwid, client_cert_file)) + if (anon_identity && strlen (anon_identity) > 0) { + if (!nm_supplicant_config_add_option (config, "anonymous_identity", anon_identity, -1)) goto out; + } - if (ca_cert_file && strlen (ca_cert_file) > 0) - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, "SET_NETWORK %i ca_cert \"%s\"", nwid, ca_cert_file)) + if (private_key_file && strlen (private_key_file) > 0) { + if (!nm_supplicant_config_add_option (config, "private_key", private_key_file, -1)) goto out; + } + + if (private_key_passwd && strlen (private_key_passwd) > 0) { + if (!nm_supplicant_config_add_option (config, "private_key_passwd", private_key_passwd, -1)) + goto out; + } + + if (client_cert_file && strlen (client_cert_file) > 0) { + if (!nm_supplicant_config_add_option (config, "client_cert", client_cert_file, -1)) + goto out; + } + + if (ca_cert_file && strlen (ca_cert_file) > 0) { + if (!nm_supplicant_config_add_option (config, "ca_cert", ca_cert_file, -1)) + goto out; + } /* * Set the pairwise and group cipher, if the user provided one. If user selected "Automatic", we * let wpa_supplicant sort it out. Likewise, if the user selected "Dynamic WEP", we do nothing. */ - if (key_type != NM_AUTH_TYPE_WPA_PSK_AUTO && key_type != IW_AUTH_CIPHER_WEP104) - { + if (key_type != NM_AUTH_TYPE_WPA_PSK_AUTO && key_type != IW_AUTH_CIPHER_WEP104) { const char *cipher; /* @@ -289,12 +273,10 @@ real_write_supplicant_config (NMAPSecurity *instance, else /* IW_AUTH_CIPHER_CCMP */ cipher = "CCMP"; - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, - "SET_NETWORK %i pairwise %s", nwid, cipher)) + if (!nm_supplicant_config_add_option (config, "pairwise", cipher, -1)) goto out; - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, - "SET_NETWORK %i group %s", nwid, cipher)) + if (!nm_supplicant_config_add_option (config, "group", cipher, -1)) goto out; } diff --git a/src/nm-ap-security-wpa-psk.c b/src/nm-ap-security-wpa-psk.c index 48ca76d2ca..65680bb8aa 100644 --- a/src/nm-ap-security-wpa-psk.c +++ b/src/nm-ap-security-wpa-psk.c @@ -29,7 +29,8 @@ #include "nm-ap-security-private.h" #include "dbus-helpers.h" #include "nm-device-802-11-wireless.h" -#include "NetworkManagerUtils.h" +#include "nm-supplicant-config.h" +#include "nm-utils.h" #define NM_AP_SECURITY_WPA_PSK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AP_SECURITY_WPA_PSK, NMAPSecurityWPA_PSKPrivate)) @@ -132,31 +133,25 @@ real_serialize (NMAPSecurity *instance, DBusMessageIter *iter) static gboolean real_write_supplicant_config (NMAPSecurity *instance, - struct wpa_ctrl *ctrl, - int nwid, + NMSupplicantConfig * config, gboolean adhoc) { NMAPSecurityWPA_PSK * self = NM_AP_SECURITY_WPA_PSK (instance); - gboolean success = FALSE; - char * msg = NULL; - const char * key = nm_ap_security_get_key (instance); - int cipher = nm_ap_security_get_we_cipher (instance); - char * key_mgmt = "WPA-PSK"; - char * pairwise_cipher = NULL; - char * group_cipher = NULL; + gboolean success = FALSE; + const char * key = nm_ap_security_get_key (instance); + int cipher = nm_ap_security_get_we_cipher (instance); + char * key_mgmt = "WPA-PSK"; + char * pairwise_cipher = NULL; + char * group_cipher = NULL; + char * bin_key = NULL; /* WPA-PSK network setup */ - if (self->priv->wpa_version == IW_AUTH_WPA_VERSION_WPA) - { - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, - "SET_NETWORK %i proto WPA", nwid)) + if (self->priv->wpa_version == IW_AUTH_WPA_VERSION_WPA) { + if (!nm_supplicant_config_add_option (config, "proto", "WPA", -1)) goto out; - } - else if (self->priv->wpa_version == IW_AUTH_WPA_VERSION_WPA2) - { - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, - "SET_NETWORK %i proto WPA2", nwid)) + } else if (self->priv->wpa_version == IW_AUTH_WPA_VERSION_WPA2) { + if (!nm_supplicant_config_add_option (config, "proto", "WPA2", -1)) goto out; } @@ -164,18 +159,20 @@ real_write_supplicant_config (NMAPSecurity *instance, if (adhoc) key_mgmt = "WPA-NONE"; - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, - "SET_NETWORK %i key_mgmt %s", nwid, key_mgmt)) + if (!nm_supplicant_config_add_option (config, "key_mgmt", key_mgmt, -1)) goto out; - msg = g_strdup_printf ("SET_NETWORK %i psk ", nwid); - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, msg, - "SET_NETWORK %i psk %s", nwid, key)) - { - g_free (msg); + bin_key = cipher_hexstr2bin(key, strlen (key)); + if (bin_key == NULL) { + nm_warning ("Not enough memory to convert key."); goto out; } - g_free (msg); + + if (!nm_supplicant_config_add_option (config, "psk", bin_key, -1)) { + g_free (bin_key); + goto out; + } + g_free (bin_key); /* * FIXME: Technically, the pairwise cipher does not need to be the same as @@ -193,14 +190,11 @@ real_write_supplicant_config (NMAPSecurity *instance, pairwise_cipher = "NONE"; /* If user selected "Automatic", we let wpa_supplicant sort it out */ - if (cipher != NM_AUTH_TYPE_WPA_PSK_AUTO) - { - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, - "SET_NETWORK %i pairwise %s", nwid, pairwise_cipher)) + if (cipher != NM_AUTH_TYPE_WPA_PSK_AUTO) { + if (!nm_supplicant_config_add_option (config, "pairwise", pairwise_cipher, -1)) goto out; - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, - "SET_NETWORK %i group %s", nwid, group_cipher)) + if (!nm_supplicant_config_add_option (config, "group", group_cipher, -1)) goto out; } diff --git a/src/nm-ap-security.c b/src/nm-ap-security.c index 043ee03d69..d7777e9d88 100644 --- a/src/nm-ap-security.c +++ b/src/nm-ap-security.c @@ -31,9 +31,8 @@ #include "nm-ap-security-wpa-eap.h" #include "nm-ap-security-leap.h" #include "nm-device-802-11-wireless.h" -#include "wpa_ctrl.h" +#include "nm-supplicant-config.h" #include "nm-utils.h" -#include "NetworkManagerUtils.h" #define NM_AP_SECURITY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AP_SECURITY, NMAPSecurityPrivate)) @@ -169,19 +168,18 @@ nm_ap_security_get_authentication_required (NMAPSecurity *self) gboolean nm_ap_security_write_supplicant_config (NMAPSecurity *self, - struct wpa_ctrl *ctrl, - int nwid, + NMSupplicantConfig * config, gboolean adhoc) { + NMAPSecurityClass * class = NM_AP_SECURITY_GET_CLASS (self); + g_return_val_if_fail (self != NULL, FALSE); - g_return_val_if_fail (ctrl != NULL, FALSE); - g_return_val_if_fail (nwid >= 0, FALSE); + g_return_val_if_fail (config != NULL, FALSE); if (self->priv->dispose_has_run) return FALSE; - return NM_AP_SECURITY_GET_CLASS (self)->write_supplicant_config_func (self, - ctrl, nwid, adhoc); + return class->write_supplicant_config_func (self, config, adhoc); } void @@ -238,13 +236,11 @@ real_serialize (NMAPSecurity *self, DBusMessageIter *iter) static gboolean real_write_supplicant_config (NMAPSecurity *self, - struct wpa_ctrl *ctrl, - int nwid, + NMSupplicantConfig * config, gboolean adhoc) { - /* Unencrypted network setup */ - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, - "SET_NETWORK %i key_mgmt NONE", nwid)) + /* Unencrypted network */ + if (!nm_supplicant_config_add_option (config, "key_mgmt", "NONE", -1)) return FALSE; return TRUE; diff --git a/src/nm-ap-security.h b/src/nm-ap-security.h index 3765a0b346..c16b717645 100644 --- a/src/nm-ap-security.h +++ b/src/nm-ap-security.h @@ -25,6 +25,8 @@ #include #include +#include "supplicant-manager/nm-supplicant-types.h" + /* Grr */ #ifndef NM_DEVICE_802_11_WIRELESS_DEFINED #define NM_DEVICE_802_11_WIRELESS_DEFINED @@ -53,24 +55,23 @@ struct _NMAPSecurity }; struct NMAccessPoint; -struct wpa_ctrl; struct _NMAPSecurityClass { GObjectClass parent; /* class members */ - NMAPSecurity * (*copy_constructor_func) (NMAPSecurity *self); + NMAPSecurity * (*copy_constructor_func) (NMAPSecurity *self); - int (*serialize_func) (NMAPSecurity *self, DBusMessageIter *iter); + int (*serialize_func) (NMAPSecurity *self, + DBusMessageIter *iter); - gboolean (*write_supplicant_config_func)(NMAPSecurity *self, - struct wpa_ctrl *ctrl, - int nwid, - gboolean adhoc); + gboolean (*write_supplicant_config_func) (NMAPSecurity *self, + NMSupplicantConfig * config, + gboolean adhoc); - guint32 (*get_default_capabilities_func)(NMAPSecurity *self); - gboolean (*get_authentication_required_func)(NMAPSecurity *self); + guint32 (*get_default_capabilities_func) (NMAPSecurity *self); + gboolean (*get_authentication_required_func) (NMAPSecurity *self); }; @@ -92,8 +93,7 @@ int nm_ap_security_serialize (NMAPSecurity *self, DBusMessageIter *iter); gboolean nm_ap_security_write_supplicant_config (NMAPSecurity *self, - struct wpa_ctrl *ctrl, - int nwid, + NMSupplicantConfig * config, gboolean adhoc); const char * nm_ap_security_get_description (NMAPSecurity *self); diff --git a/src/nm-device-802-11-wireless.c b/src/nm-device-802-11-wireless.c index 3fe0451364..32afb0a19d 100644 --- a/src/nm-device-802-11-wireless.c +++ b/src/nm-device-802-11-wireless.c @@ -43,7 +43,7 @@ #include "nm-dbus-nmi.h" #include "nm-supplicant-manager.h" #include "nm-supplicant-interface.h" -#include "wpa_ctrl.h" +#include "nm-supplicant-config.h" #include "cipher.h" #include "dbus-dict-helpers.h" @@ -51,16 +51,19 @@ #define NM_DEVICE_802_11_WIRELESS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_802_11_WIRELESS, NMDevice80211WirelessPrivate)) -struct _Supplicant -{ - GPid pid; - GSource * watch; - GSource * status; - struct wpa_ctrl * ctrl; - GSource * timeout; +typedef struct Supplicant { + NMSupplicantManager * mgr; + NMSupplicantInterface * iface; - GSource * stdout; -}; + /* signal handler ids */ + guint iface_error_id; + guint iface_state_id; + guint iface_scanned_ap_id; + guint iface_scan_result_id; + guint iface_con_state_id; + + GSource * con_timeout; +} Supplicant; struct _NMDevice80211WirelessPrivate { @@ -84,10 +87,7 @@ struct _NMDevice80211WirelessPrivate guint32 last_scan; GSource * pending_scan; - struct _Supplicant supplicant; - - NMSupplicantManager * sup_mgr; - NMSupplicantInterface * sup_iface; + Supplicant supplicant; guint32 failed_link_count; GSource * link_timeout; @@ -116,9 +116,10 @@ static gboolean link_to_specific_ap (NMDevice80211Wireless *self, NMAccessPoint *ap, gboolean default_link); -static void supplicant_cleanup (NMDevice80211Wireless *self); +static void cleanup_association_attempt (NMDevice80211Wireless * self, + gboolean disconnect); -static void remove_link_timeout (NMDevice80211Wireless *self); +static void remove_supplicant_timeouts (NMDevice80211Wireless *self); static void nm_device_802_11_wireless_disable_encryption (NMDevice80211Wireless *self); @@ -145,6 +146,9 @@ static void supplicant_mgr_state_cb (NMSupplicantInterface * iface, guint32 old_state, NMDevice80211Wireless *self); +static void cleanup_supplicant_interface (NMDevice80211Wireless * self); + + /* * nm_device_802_11_wireless_update_bssid * @@ -382,41 +386,49 @@ nm_device_802_11_wireless_init (NMDevice80211Wireless * self) self->priv = NM_DEVICE_802_11_WIRELESS_GET_PRIVATE (self); self->priv->dispose_has_run = FALSE; self->priv->is_initialized = FALSE; + self->priv->supplicant.iface_error_id = 0; memset (&(self->priv->hw_addr), 0, sizeof (struct ether_addr)); - self->priv->supplicant.pid = -1; } static void init_supplicant_interface (NMDevice80211Wireless * self) { - g_return_if_fail (self != NULL); + Supplicant * sup; + guint id; - self->priv->sup_iface = nm_supplicant_manager_get_iface (self->priv->sup_mgr, - NM_DEVICE (self)); - if (self->priv->sup_iface == NULL) { + g_return_if_fail (self != NULL); + sup = (Supplicant *) &self->priv->supplicant; + + sup->iface = nm_supplicant_manager_get_iface (sup->mgr, + NM_DEVICE (self)); + if (sup->iface == NULL) { nm_warning ("Couldn't initialize supplicant interface for %s.", nm_device_get_iface (NM_DEVICE (self))); } else { - g_signal_connect (G_OBJECT (self->priv->sup_iface), - "state", - G_CALLBACK (supplicant_iface_state_cb), - self); + id = g_signal_connect (G_OBJECT (sup->iface), + "state", + G_CALLBACK (supplicant_iface_state_cb), + self); + sup->iface_state_id = id; - g_signal_connect (G_OBJECT (self->priv->sup_iface), - "scanned-ap", - G_CALLBACK (supplicant_iface_scanned_ap_cb), - self); + id = g_signal_connect (G_OBJECT (sup->iface), + "scanned-ap", + G_CALLBACK (supplicant_iface_scanned_ap_cb), + self); + sup->iface_scanned_ap_id = id; - g_signal_connect (G_OBJECT (self->priv->sup_iface), - "scan-result", - G_CALLBACK (supplicant_iface_scan_result_cb), - self); + id = g_signal_connect (G_OBJECT (sup->iface), + "scan-result", + G_CALLBACK (supplicant_iface_scan_result_cb), + self); + sup->iface_scan_result_id = id; - g_signal_connect (G_OBJECT (self->priv->sup_iface), - "connection-state", - G_CALLBACK (supplicant_iface_connection_state_cb), - self); + id = g_signal_connect (G_OBJECT (sup->iface), + "connection-state", + G_CALLBACK (supplicant_iface_connection_state_cb), + self); + sup->iface_con_state_id = id; } } @@ -481,12 +493,12 @@ real_init (NMDevice *dev) nm_dev_sock_close (sk); } - self->priv->sup_mgr = nm_supplicant_manager_get (); - g_signal_connect (G_OBJECT (self->priv->sup_mgr), + self->priv->supplicant.mgr = nm_supplicant_manager_get (); + g_signal_connect (G_OBJECT (self->priv->supplicant.mgr), "state", G_CALLBACK (supplicant_mgr_state_cb), self); - if (nm_supplicant_manager_get_state (self->priv->sup_mgr) == NM_SUPPLICANT_MANAGER_STATE_IDLE) { + if (nm_supplicant_manager_get_state (self->priv->supplicant.mgr) == NM_SUPPLICANT_MANAGER_STATE_IDLE) { init_supplicant_interface (self); } } @@ -495,10 +507,29 @@ static void real_update_link (NMDevice *dev) { NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (dev); + gboolean new_link = FALSE; + guint32 state; - /* If the supplicant isn't running, we can't possibly have a link */ - if (!self->priv->supplicant.pid) - nm_device_set_active_link (NM_DEVICE (self), FALSE); + /* Ignore link changes when scanning */ + if (self->priv->scanning) + return; + + if (!self->priv->supplicant.iface) + goto out; + + state = nm_supplicant_interface_get_state (self->priv->supplicant.iface); + if (state != NM_SUPPLICANT_INTERFACE_STATE_READY) + goto out; + + state = nm_supplicant_interface_get_connection_state (self->priv->supplicant.iface); + if ( state == NM_SUPPLICANT_INTERFACE_CON_STATE_COMPLETED + || state == NM_SUPPLICANT_INTERFACE_CON_STATE_ASSOCIATED + || state == NM_SUPPLICANT_INTERFACE_CON_STATE_4WAY_HANDSHAKE + || state == NM_SUPPLICANT_INTERFACE_CON_STATE_GROUP_HANDSHAKE) + new_link = TRUE; + +out: + nm_device_set_active_link (NM_DEVICE (self), new_link); } @@ -541,8 +572,7 @@ real_deactivate_quickly (NMDevice *dev) { NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (dev); - supplicant_cleanup (self); - remove_link_timeout (self); + cleanup_association_attempt (self, TRUE); /* Clean up stuff, don't leave the card associated */ nm_device_802_11_wireless_set_essid (self, ""); @@ -1075,6 +1105,28 @@ nm_device_802_11_wireless_ap_list_get (NMDevice80211Wireless *self) } +/* Return TRUE if activation is possible, FALSE if not */ +gboolean +nm_device_802_11_wireless_can_activate (NMDevice80211Wireless * self) +{ + NMSupplicantInterface * sup_iface; + guint32 state; + + g_return_val_if_fail (self != NULL, FALSE); + + sup_iface = self->priv->supplicant.iface; + + if (sup_iface == NULL) + return FALSE; + + state = nm_supplicant_interface_get_state (sup_iface); + if (state == NM_SUPPLICANT_INTERFACE_STATE_READY) + return TRUE; + + return FALSE; +} + + static gboolean set_scan_interval_cb (gpointer user_data) { @@ -1724,10 +1776,6 @@ static void supplicant_iface_scan_result_cb (NMSupplicantInterface * iface, { g_return_if_fail (self != NULL); - /* No matter what the scan result was (error, success), reset - * our internal scan tracking variable. - */ - self->priv->scanning = FALSE; schedule_scan (self); } @@ -1753,8 +1801,11 @@ request_wireless_scan (gpointer user_data) if (!(caps & NM_DEVICE_CAP_NM_SUPPORTED) || !(caps & NM_DEVICE_CAP_WIRELESS_SCAN)) goto out; - g_source_unref (self->priv->pending_scan); /* Balance g_timeout_source_new() */ - self->priv->pending_scan = NULL; + if (self->priv->pending_scan) { + g_source_destroy (self->priv->pending_scan); + g_source_unref (self->priv->pending_scan); /* Balance g_timeout_source_new() */ + self->priv->pending_scan = NULL; + } /* Reschedule ourselves if all wireless is disabled, we're asleep, * or we are currently activating. @@ -1781,16 +1832,14 @@ request_wireless_scan (gpointer user_data) } /* Make sure we have a valid supplicant interface */ - if ( !self->priv->sup_iface - || nm_supplicant_interface_get_state (self->priv->sup_iface) != NM_SUPPLICANT_INTERFACE_STATE_READY) { + if ( !self->priv->supplicant.iface + || nm_supplicant_interface_get_state (self->priv->supplicant.iface) != NM_SUPPLICANT_INTERFACE_STATE_READY) { schedule_scan (self); goto out; } - self->priv->scanning = TRUE; - if (!nm_supplicant_interface_request_scan (self->priv->sup_iface)) { - /* Some sort of error requesting the scan */ - self->priv->scanning = FALSE; + if (!nm_supplicant_interface_request_scan (self->priv->supplicant.iface)) { + /* If some sort of error occurred, just try again later */ schedule_scan (self); } @@ -1825,9 +1874,7 @@ cancel_pending_scan (NMDevice80211Wireless *self) { g_return_if_fail (self != NULL); - self->priv->scanning = FALSE; - if (self->priv->pending_scan) - { + if (self->priv->pending_scan) { g_source_destroy (self->priv->pending_scan); /* Balance g_source_attach() */ g_source_unref (self->priv->pending_scan); /* Balance g_timeout_source_new() */ self->priv->pending_scan = NULL; @@ -2014,36 +2061,6 @@ ap_is_auth_required (NMAccessPoint *ap, gboolean *has_key) * WPA Supplicant control stuff * */ -static void -supplicant_iface_state_cb (NMSupplicantInterface * iface, - guint32 new_state, - guint32 old_state, - NMDevice80211Wireless *self) -{ - g_return_if_fail (self != NULL); - - nm_info ("(%s) supplicant interface is now in state %d (from %d).", - nm_device_get_iface (NM_DEVICE (self)), - new_state, - old_state); - - if (new_state == NM_SUPPLICANT_INTERFACE_STATE_READY) { - /* Start the scanning timeout for devices that can do scanning */ - if (nm_device_get_capabilities (NM_DEVICE (self)) & NM_DEVICE_CAP_WIRELESS_SCAN) - { - guint source_id; - - self->priv->pending_scan = g_idle_source_new (); - g_source_set_callback (self->priv->pending_scan, - request_wireless_scan, self, NULL); - source_id = g_source_attach (self->priv->pending_scan, - nm_device_get_main_context (NM_DEVICE (self))); - } - } else if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) { - cancel_pending_scan (self); - } -} - static void cull_scan_list (NMDevice80211Wireless * self) @@ -2314,70 +2331,31 @@ supplicant_iface_scanned_ap_cb (NMSupplicantInterface * iface, out: if (ap) nm_ap_unref (ap); - - /* When we start getting scan results, scanning is over */ - if (self->priv->scanning) - self->priv->scanning = FALSE; } static void -supplicant_iface_connection_state_cb (NMSupplicantInterface * iface, - guint32 new_state, - guint32 old_state, - NMDevice80211Wireless *self) -{ - g_return_if_fail (self != NULL); -} - - -static void -supplicant_mgr_state_cb (NMSupplicantInterface * iface, - guint32 new_state, - guint32 old_state, - NMDevice80211Wireless *self) +remove_supplicant_interface_connection_error_handler (NMDevice80211Wireless * self) { g_return_if_fail (self != NULL); - if (new_state == old_state) - return; - - /* If the supplicant went away, release the supplicant interface */ - if (new_state == NM_SUPPLICANT_MANAGER_STATE_DOWN) { - if (self->priv->sup_iface) { - NMData * app_data = nm_device_get_app_data (NM_DEVICE (self)); - - nm_supplicant_manager_release_iface (self->priv->sup_mgr, - self->priv->sup_iface); - self->priv->sup_iface = NULL; - nm_policy_schedule_device_change_check (app_data); - } - } else if (new_state == NM_SUPPLICANT_MANAGER_STATE_IDLE) { - if (!self->priv->sup_iface) { - /* request a supplicant interface from the supplicant manager */ - init_supplicant_interface (self); - } + if (self->priv->supplicant.iface_error_id != 0) { + g_signal_handler_disconnect (self->priv->supplicant.iface, + self->priv->supplicant.iface_error_id); + self->priv->supplicant.iface_error_id = 0; } } -/****************************************************************************/ -/* WPA Supplicant control stuff - * - * Originally from: - * - * wpa_supplicant wrapper - * - * Copyright (C) 2005 Kay Sievers - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 of the License. - */ +static void +cleanup_association_attempt (NMDevice80211Wireless * self, gboolean disconnect) +{ + g_return_if_fail (self != NULL); -#define WPA_SUPPLICANT_GLOBAL_SOCKET LOCALSTATEDIR"/run/wpa_supplicant-global" -#define WPA_SUPPLICANT_CONTROL_SOCKET LOCALSTATEDIR"/run/wpa_supplicant" -#define WPA_SUPPLICANT_NUM_RETRIES 20 -#define WPA_SUPPLICANT_RETRY_TIME_US 100*1000 + remove_supplicant_interface_connection_error_handler (self); + remove_supplicant_timeouts (self); + if (disconnect && self->priv->supplicant.iface) + nm_supplicant_interface_disconnect (self->priv->supplicant.iface); +} static void @@ -2385,106 +2363,12 @@ remove_link_timeout (NMDevice80211Wireless *self) { g_return_if_fail (self != NULL); - if (self->priv->link_timeout != NULL) - { + if (self->priv->link_timeout != NULL) { g_source_destroy (self->priv->link_timeout); self->priv->link_timeout = NULL; } } -static void -supplicant_remove_timeout (NMDevice80211Wireless *self) -{ - g_return_if_fail (self != NULL); - - /* Remove any pending timeouts on the request */ - if (self->priv->supplicant.timeout != NULL) - { - g_source_destroy (self->priv->supplicant.timeout); - self->priv->supplicant.timeout = NULL; - } -} - -static char * -supplicant_get_device_socket_path (NMDevice80211Wireless *self) -{ - const char *iface; - - g_return_val_if_fail (self != NULL, NULL); - - iface = nm_device_get_iface (NM_DEVICE (self)); - return g_strdup_printf (WPA_SUPPLICANT_CONTROL_SOCKET "/%s", iface); -} - -static void -supplicant_cleanup (NMDevice80211Wireless *self) -{ - char * sock_path; - - g_return_if_fail (self != NULL); - - if (self->priv->supplicant.pid > 0) - { - kill (self->priv->supplicant.pid, SIGTERM); - self->priv->supplicant.pid = -1; - } - if (self->priv->supplicant.watch) - { - g_source_destroy (self->priv->supplicant.watch); - self->priv->supplicant.watch = NULL; - } - if (self->priv->supplicant.status) - { - g_source_destroy (self->priv->supplicant.status); - self->priv->supplicant.status = NULL; - } - if (self->priv->supplicant.ctrl) - { - wpa_ctrl_close (self->priv->supplicant.ctrl); - self->priv->supplicant.ctrl = NULL; - } - if (self->priv->supplicant.stdout) - { - g_source_destroy (self->priv->supplicant.stdout); - self->priv->supplicant.stdout = NULL; - } - - supplicant_remove_timeout (self); - remove_link_timeout (self); - - /* HACK: should be fixed in wpa_supplicant. Will likely - * require accomodations for selinux. - */ - unlink (WPA_SUPPLICANT_GLOBAL_SOCKET); - sock_path = supplicant_get_device_socket_path (self); - unlink (sock_path); - g_free (sock_path); -} - -static void -supplicant_watch_cb (GPid pid, - gint status, - gpointer user_data) -{ - NMDevice * dev = NM_DEVICE (user_data); - NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (user_data); - - g_assert (self); - - if (WIFEXITED (status)) - nm_warning ("wpa_supplicant exited with error code %d", WEXITSTATUS (status)); - else if (WIFSTOPPED (status)) - nm_warning ("wpa_supplicant stopped unexpectedly with signal %d", WSTOPSIG (status)); - else if (WIFSIGNALED (status)) - nm_warning ("wpa_supplicant died with signal %d", WTERMSIG (status)); - else - nm_warning ("wpa_supplicant died from an unknown cause"); - - supplicant_cleanup (self); - - nm_device_set_active_link (dev, FALSE); -} - /* * link_timeout_cb @@ -2495,554 +2379,603 @@ supplicant_watch_cb (GPid pid, static gboolean link_timeout_cb (gpointer user_data) { - NMDevice * dev = NM_DEVICE (user_data); - NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (user_data); - NMActRequest * req = nm_device_get_act_request (dev); - NMAccessPoint * ap = nm_act_request_get_ap (req); - gboolean has_key; + NMDevice * dev = NM_DEVICE (user_data); + NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (user_data); + NMActRequest * req = NULL; + NMAccessPoint * ap = NULL; + gboolean has_key; g_assert (dev); - /* Disconnect event during initial authentication and credentials - * ARE checked - we are likely to have wrong key. Ask the user for - * another one. - */ - if ( (nm_act_request_get_stage (req) == NM_ACT_STAGE_DEVICE_CONFIG) - && (ap_is_auth_required (ap, &has_key) && has_key)) - { - /* Association/authentication failed, we must have bad encryption key */ - nm_info ("Activation (%s/wireless): disconnected during association," - " asking for new key.", nm_device_get_iface (dev)); - supplicant_remove_timeout(self); - nm_dbus_get_user_key_for_network (req, TRUE); - } - else - { - nm_info ("%s: link timed out.", nm_device_get_iface (dev)); - nm_device_set_active_link (dev, FALSE); - } + req = nm_device_get_act_request (dev); + if (req) + ap = nm_act_request_get_ap (req); + if (req == NULL || ap == NULL) { + nm_warning ("couldn't get activation request or activation AP."); + nm_device_set_active_link (dev, FALSE); + if (nm_device_is_activating (dev)) { + cleanup_association_attempt (self, TRUE); + nm_policy_schedule_activation_failed (req); + } + return FALSE; + } + + /* Disconnect event during initial authentication and credentials + * ARE checked - we are likely to have wrong key. Ask the user for + * another one. + */ + if ( (nm_act_request_get_stage (req) == NM_ACT_STAGE_DEVICE_CONFIG) + && (ap_is_auth_required (ap, &has_key) && has_key)) { + /* Association/authentication failed, we must have bad encryption key */ + nm_info ("Activation (%s/wireless): disconnected during association," + " asking for new key.", nm_device_get_iface (dev)); + cleanup_association_attempt (self, TRUE); + nm_dbus_get_user_key_for_network (req, TRUE); + } else { + nm_info ("%s: link timed out.", nm_device_get_iface (dev)); + nm_device_set_active_link (dev, FALSE); + } return FALSE; } -#define MESSAGE_LEN 2048 +struct state_cb_data { + NMDevice80211Wireless * self; + guint32 new_state; + guint32 old_state; +}; static gboolean -supplicant_status_cb (GIOChannel *source, - GIOCondition condition, - gpointer user_data) +schedule_state_handler (NMDevice80211Wireless * self, + GSourceFunc handler, + guint32 new_state, + guint32 old_state) { - NMDevice * dev = NM_DEVICE (user_data); - NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (user_data); - char * message; - size_t len; - struct wpa_ctrl * ctrl; - NMActRequest * req; + struct state_cb_data * cb_data; + GSource * source; - g_assert (self); + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (handler != NULL, FALSE); - /* Do nothing if we're supposed to be canceling activation. - * We'll get cleaned up by the cancellation handlers later. - */ - if (nm_device_activation_should_cancel (dev)) + if (new_state == old_state) return TRUE; - ctrl = self->priv->supplicant.ctrl; - g_return_val_if_fail (ctrl != NULL, FALSE); + cb_data = g_slice_new0 (struct state_cb_data); + if (cb_data == NULL) { + nm_warning ("Not enough memory to process supplicant manager state" + " change."); + return FALSE; + } + + cb_data->self = self; + cb_data->new_state = new_state; + cb_data->old_state = old_state; + + source = g_idle_source_new (); + g_source_set_callback (source, handler, cb_data, NULL); + g_source_attach (source, nm_device_get_main_context (NM_DEVICE (self))); + g_source_unref (source); + + return TRUE; +} + +static gboolean +supplicant_iface_state_cb_handler (gpointer user_data) +{ + struct state_cb_data * cb_data = (struct state_cb_data *) user_data; + NMDevice80211Wireless * self; + guint32 new_state, old_state; + + g_return_val_if_fail (cb_data != NULL, FALSE); + + self = cb_data->self; + new_state = cb_data->new_state; + old_state = cb_data->old_state; + + nm_info ("(%s) supplicant interface is now in state %d (from %d).", + nm_device_get_iface (NM_DEVICE (self)), + new_state, + old_state); + + if (new_state == NM_SUPPLICANT_INTERFACE_STATE_READY) { + NMData * app_data = nm_device_get_app_data (NM_DEVICE (self)); + + /* Start the scanning timeout for devices that can do scanning */ + if (nm_device_get_capabilities (NM_DEVICE (self)) & NM_DEVICE_CAP_WIRELESS_SCAN) { + guint source_id; + + self->priv->pending_scan = g_idle_source_new (); + g_source_set_callback (self->priv->pending_scan, + request_wireless_scan, self, NULL); + source_id = g_source_attach (self->priv->pending_scan, + nm_device_get_main_context (NM_DEVICE (self))); + } + + /* Device may be able to be activated now */ + nm_policy_schedule_device_change_check (app_data); + } else if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) { + cancel_pending_scan (self); + cleanup_association_attempt (self, FALSE); + cleanup_supplicant_interface (self); + nm_device_set_active_link (NM_DEVICE (self), FALSE); + } + + g_slice_free (struct state_cb_data, cb_data); + return FALSE; +} + + +static void +supplicant_iface_state_cb (NMSupplicantInterface * iface, + guint32 new_state, + guint32 old_state, + NMDevice80211Wireless *self) +{ + g_return_if_fail (self != NULL); + + schedule_state_handler (self, + supplicant_iface_state_cb_handler, + new_state, + old_state); +} + + +static gboolean +supplicant_iface_connection_state_cb_handler (gpointer user_data) +{ + struct state_cb_data * cb_data = (struct state_cb_data *) user_data; + NMDevice80211Wireless * self; + NMDevice * dev; + NMActRequest * req; + guint32 new_state, old_state; + + g_return_val_if_fail (cb_data != NULL, FALSE); + + self = cb_data->self; + dev = NM_DEVICE (self); + new_state = cb_data->new_state; + old_state = cb_data->old_state; req = nm_device_get_act_request (NM_DEVICE (self)); + if (!req) { + /* The device is not activating or already activated; do nothing. */ + goto out; + } - message = g_malloc (MESSAGE_LEN); - len = MESSAGE_LEN; - wpa_ctrl_recv (ctrl, message, &len); - message[len] = '\0'; + nm_debug ("(%s) Supplicant interface state change: %d -> %d", + nm_device_get_iface (NM_DEVICE (self)), old_state, new_state); - if (strstr (message, WPA_EVENT_CONNECTED) != NULL) - { - remove_link_timeout (self); + if (new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_COMPLETED) { + remove_supplicant_interface_connection_error_handler (self); + remove_supplicant_timeouts (self); nm_device_set_active_link (dev, TRUE); /* If this is the initial association during device activation, * schedule the next activation stage. */ - if (req && (nm_act_request_get_stage (req) == NM_ACT_STAGE_DEVICE_CONFIG)) - { - NMAccessPoint *ap = nm_act_request_get_ap (req); + if (nm_act_request_get_stage (req) == NM_ACT_STAGE_DEVICE_CONFIG) { + NMAccessPoint * ap = nm_act_request_get_ap (req); nm_info ("Activation (%s/wireless) Stage 2 of 5 (Device Configure) " - "successful. Connected to access point '%s'.", - nm_device_get_iface (NM_DEVICE (self)), - nm_ap_get_essid (ap) ? nm_ap_get_essid (ap) : "(none)"); - supplicant_remove_timeout (self); + "successful. Connected to wireless network '%s'.", + nm_device_get_iface (NM_DEVICE (self)), + nm_ap_get_essid (ap) ? nm_ap_get_essid (ap) : "(none)"); nm_device_activate_schedule_stage3_ip_config_start (req); } - } - else if (strstr (message, WPA_EVENT_DISCONNECTED) != NULL) - { - if (nm_device_is_activated (dev) || nm_device_is_activating (dev)) - { + } else if (new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED) { + if (nm_device_is_activated (dev) || nm_device_is_activating (dev)) { + gboolean has_link = nm_device_has_active_link (NM_DEVICE (self)); + /* Start the link timeout so we allow some time for reauthentication */ - if ((self->priv->link_timeout == NULL) && !self->priv->scanning) - { - GMainContext * context = nm_device_get_main_context (dev); - self->priv->link_timeout = g_timeout_source_new (20000); + if (!has_link && (self->priv->link_timeout == NULL) && !self->priv->scanning) { + GMainContext * context = nm_device_get_main_context (dev); + self->priv->link_timeout = g_timeout_source_new (12000); g_source_set_callback (self->priv->link_timeout, link_timeout_cb, self, NULL); g_source_attach (self->priv->link_timeout, context); } - } - else - { + } else { nm_device_set_active_link (dev, FALSE); } } - g_free (message); + if (new_state == NM_SUPPLICANT_INTERFACE_CON_STATE_SCANNING) { + self->priv->scanning = TRUE; + } else { + self->priv->scanning = FALSE; + } - return TRUE; +out: + g_slice_free (struct state_cb_data, cb_data); + return FALSE; } -#define NM_SUPPLICANT_TIMEOUT 20 /* how long we wait for wpa_supplicant to associate (in seconds) */ - -static unsigned int -get_supplicant_timeout (NMDevice80211Wireless *self) +static void +supplicant_iface_connection_state_cb (NMSupplicantInterface * iface, + guint32 new_state, + guint32 old_state, + NMDevice80211Wireless *self) { - if (self->priv->num_freqs > 14) - return NM_SUPPLICANT_TIMEOUT * 2; - return NM_SUPPLICANT_TIMEOUT; + g_return_if_fail (self != NULL); + + schedule_state_handler (self, + supplicant_iface_connection_state_cb_handler, + new_state, + old_state); } +static void +cleanup_supplicant_interface (NMDevice80211Wireless * self) +{ + Supplicant * sup; + + g_return_if_fail (self != NULL); + + sup = &self->priv->supplicant; + + if (sup->iface_error_id > 0) { + g_signal_handler_disconnect (sup->iface, sup->iface_error_id); + sup->iface_error_id = 0; + } + + if (sup->iface_state_id > 0) { + g_signal_handler_disconnect (sup->iface, sup->iface_state_id); + sup->iface_state_id = 0; + } + + if (sup->iface_scanned_ap_id > 0) { + g_signal_handler_disconnect (sup->iface, sup->iface_scanned_ap_id); + sup->iface_scanned_ap_id = 0; + } + + if (sup->iface_scan_result_id > 0) { + g_signal_handler_disconnect (sup->iface, sup->iface_scan_result_id); + sup->iface_scan_result_id = 0; + } + + if (sup->iface_con_state_id > 0) { + g_signal_handler_disconnect (sup->iface, sup->iface_con_state_id); + sup->iface_con_state_id = 0; + } + + if (sup->iface) { + nm_supplicant_manager_release_iface (sup->mgr, sup->iface); + sup->iface = NULL; + } +} + + +static gboolean +supplicant_mgr_state_cb_handler (gpointer user_data) +{ + struct state_cb_data * cb_data = (struct state_cb_data *) user_data; + NMDevice80211Wireless * self; + guint32 new_state, old_state; + + g_return_val_if_fail (cb_data != NULL, FALSE); + + self = cb_data->self; + new_state = cb_data->new_state; + old_state = cb_data->old_state; + + nm_info ("(%s) supplicant manager is now in state %d (from %d).", + nm_device_get_iface (NM_DEVICE (self)), + new_state, + old_state); + + /* If the supplicant went away, release the supplicant interface */ + if (new_state == NM_SUPPLICANT_MANAGER_STATE_DOWN) { + if (self->priv->supplicant.iface) { + NMDevice * dev = NM_DEVICE (self); + NMData * app_data = nm_device_get_app_data (dev); + + cleanup_association_attempt (self, FALSE); + cleanup_supplicant_interface (self); + + nm_device_set_active_link (NM_DEVICE (self), FALSE); + + if (nm_device_is_activating (dev)) { + NMActRequest * req = nm_device_get_act_request (dev); + nm_policy_schedule_activation_failed (req); + } else if (nm_device_is_activated (dev)) { + nm_policy_schedule_device_change_check (app_data); + } + } + } else if (new_state == NM_SUPPLICANT_MANAGER_STATE_IDLE) { + if (!self->priv->supplicant.iface) { + /* request a supplicant interface from the supplicant manager */ + init_supplicant_interface (self); + } + } + + g_slice_free (struct state_cb_data, cb_data); + return FALSE; +} + +static void +supplicant_mgr_state_cb (NMSupplicantInterface * iface, + guint32 new_state, + guint32 old_state, + NMDevice80211Wireless *self) +{ + g_return_if_fail (self != NULL); + + schedule_state_handler (self, + supplicant_mgr_state_cb_handler, + new_state, + old_state); +} + +struct iface_con_error_cb_data { + NMDevice80211Wireless * self; + char * name; + char * message; +}; + + +static gboolean +supplicant_iface_connection_error_cb_handler (gpointer user_data) +{ + struct iface_con_error_cb_data * cb_data = (struct iface_con_error_cb_data *) user_data; + NMDevice80211Wireless * self; + NMActRequest * req; + + g_return_val_if_fail (cb_data != NULL, FALSE); + + self = cb_data->self; + req = nm_device_get_act_request (NM_DEVICE (self)); + + if (!nm_device_is_activating (NM_DEVICE (self))) + goto out; + + nm_info ("Activation (%s/wireless): association request to the supplicant " + "failed: %s - %s", + nm_device_get_iface (NM_DEVICE (self)), + cb_data->name, + cb_data->message); + + cleanup_association_attempt (self, TRUE); + nm_policy_schedule_activation_failed (req); + +out: + g_free (cb_data->name); + g_free (cb_data->message); + g_slice_free (struct iface_con_error_cb_data, cb_data); + return FALSE; +} + + +static void +supplicant_iface_connection_error_cb (NMSupplicantInterface * iface, + const char * name, + const char * message, + NMDevice80211Wireless * self) +{ + struct iface_con_error_cb_data * cb_data; + GSource * source; + + g_return_if_fail (self != NULL); + + cb_data = g_slice_new0 (struct iface_con_error_cb_data); + if (cb_data == NULL) { + nm_warning ("Not enough memory to process supplicant connection error."); + return; + } + + cb_data->self = self; + cb_data->name = g_strdup (name); + cb_data->message = g_strdup (message); + + source = g_idle_source_new (); + g_source_set_callback (source, + supplicant_iface_connection_error_cb_handler, + cb_data, + NULL); + g_source_attach (source, nm_device_get_main_context (NM_DEVICE (self))); + g_source_unref (source); +} + +static void +remove_supplicant_connection_timeout (NMDevice80211Wireless *self) +{ + g_return_if_fail (self != NULL); + + /* Remove any pending timeouts on the request */ + if (self->priv->supplicant.con_timeout != NULL) { + g_source_destroy (self->priv->supplicant.con_timeout); + self->priv->supplicant.con_timeout = NULL; + } +} + /* - * supplicant_timeout_cb + * supplicant_connection_timeout_cb * * Called when the supplicant has been unable to connect to an access point * within a specified period of time. */ static gboolean -supplicant_timeout_cb (gpointer user_data) +supplicant_connection_timeout_cb (gpointer user_data) { - NMDevice * dev = NM_DEVICE (user_data); - NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (user_data); - NMActRequest * req = nm_device_get_act_request (dev); - NMAccessPoint * ap = nm_act_request_get_ap (req); - gboolean has_key; + NMDevice * dev = NM_DEVICE (user_data); + NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (user_data); + NMActRequest * req = nm_device_get_act_request (dev); + NMAccessPoint * ap = nm_act_request_get_ap (req); + gboolean has_key; g_assert (self); + cleanup_association_attempt (self, TRUE); + /* Timed out waiting for authentication success; if the security method * in use does not require access point side authentication (Open System * WEP, for example) then we are likely using the wrong authentication * algorithm or key. Request new one from the user. */ - if (!ap_is_auth_required (ap, &has_key) && has_key) - { + if (!ap_is_auth_required (ap, &has_key) && has_key) { /* Activation failed, we must have bad encryption key */ - nm_info ("Activation (%s/wireless): association took too long (>%us), asking for new key.", - nm_device_get_iface (dev), get_supplicant_timeout (self)); + nm_info ("Activation (%s/wireless): association took too long, " + "asking for new key.", + nm_device_get_iface (dev)); + nm_dbus_get_user_key_for_network (req, TRUE); - } - else - { - nm_info ("Activation (%s/wireless): association took too long (>%us), failing activation.", - nm_device_get_iface (dev), get_supplicant_timeout (self)); - if (nm_device_is_activating (dev)) + } else { + if (nm_device_is_activating (dev)) { + nm_info ("Activation (%s/wireless): association took too long, " + "failing activation.", + nm_device_get_iface (dev)); + nm_policy_schedule_activation_failed (nm_device_get_act_request (dev)); + } } return FALSE; } -/* - * supplicant_log_stdout - * - * Read text from a GIOChannel that's hooked up to the stdout of - * wpa_supplicant, then write that text to NM's syslog service. - * Adapted from Gnome's bug-buddy. - * - */ -static gboolean -supplicant_log_stdout (GIOChannel *ioc, GIOCondition condition, gpointer data) -{ - NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (data); - gboolean retval = FALSE; - char *buf; - gsize len; - GIOStatus io_status; - GTimeVal start_time, cur_time; - - #define LINE_SIZE 1024 - buf = g_malloc0 (LINE_SIZE); - g_get_current_time (&start_time); - try_read: - io_status = g_io_channel_read_chars (ioc, buf, LINE_SIZE-1, &len, NULL); - switch (io_status) - { - case G_IO_STATUS_AGAIN: - g_usleep (G_USEC_PER_SEC / 60); - /* Only wait for data for 1/2 a second */ - g_get_current_time (&cur_time); - /* Subtract 1/2 second from current time so we don't have - * to modify start_time. - */ - g_time_val_add (&cur_time, -1 * (G_USEC_PER_SEC / 2)); - /* Compare times. If cur_time is less, keep trying to read */ - if ((cur_time.tv_sec < start_time.tv_sec) - || ((cur_time.tv_sec == start_time.tv_sec) - && (cur_time.tv_usec < start_time.tv_usec))) - goto try_read; - nm_warning ("Waited too long for wpa_supplicant output, some may be lost."); - break; - case G_IO_STATUS_ERROR: - nm_warning ("Error reading wpa_supplicant output."); - break; - case G_IO_STATUS_NORMAL: - retval = TRUE; - break; - default: - break; - } - - if (len > 0) - { - char *end; - char *start; - - /* Log each line separately; sometimes we get a couple lines at a time */ - buf[LINE_SIZE-1] = '\0'; - start = end = &buf[0]; - while (*end != '\0') - { - if (*end == '\n') - { - *end = '\0'; - nm_info ("wpa_supplicant(%d): %s", self->priv->supplicant.pid, start); - start = end + 1; - } - end++; - } - } - g_free (buf); - - return retval; -} - -/* - * supplicant_child_setup - * - * Set the process group ID of the newly forked process - * - */ static void -supplicant_child_setup (gpointer user_data G_GNUC_UNUSED) +remove_supplicant_timeouts (NMDevice80211Wireless *self) { - /* We are in the child process at this point */ - pid_t pid = getpid (); - setpgid (pid, pid); -} + g_return_if_fail (self != NULL); -static gboolean -supplicant_exec (NMDevice80211Wireless *self) -{ - gboolean success = FALSE; - char * argv[4]; - GError * error = NULL; - GPid pid = -1; - int sup_stdout; - - argv[0] = WPA_SUPPLICANT_BIN; - argv[1] = "-g"; - argv[2] = WPA_SUPPLICANT_GLOBAL_SOCKET; - argv[3] = NULL; - - success = g_spawn_async_with_pipes ("/", argv, NULL, 0, - &supplicant_child_setup, NULL, &pid, NULL, &sup_stdout, - NULL, &error); - if (!success) - { - if (error) - { - nm_warning ("Couldn't start wpa_supplicant. Error: (%d) %s", - error->code, error->message); - g_error_free (error); - } - else - nm_warning ("Couldn't start wpa_supplicant due to an unknown error."); - } - else - { - GIOChannel * channel; - const char * charset = NULL; - - /* Monitor output from supplicant and redirect to syslog */ - channel = g_io_channel_unix_new (sup_stdout); - g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL); - g_get_charset (&charset); - g_io_channel_set_encoding (channel, charset, NULL); - self->priv->supplicant.stdout = g_io_create_watch (channel, G_IO_IN | G_IO_ERR); - g_source_set_priority (self->priv->supplicant.stdout, G_PRIORITY_LOW); - g_source_set_callback (self->priv->supplicant.stdout, (GSourceFunc) supplicant_log_stdout, self, NULL); - g_source_attach (self->priv->supplicant.stdout, nm_device_get_main_context (NM_DEVICE (self))); - g_io_channel_unref (channel); - - /* Monitor the child process so we know when it stops */ - self->priv->supplicant.pid = pid; - if (self->priv->supplicant.watch) - g_source_destroy (self->priv->supplicant.watch); - self->priv->supplicant.watch = g_child_watch_source_new (pid); - g_source_set_callback (self->priv->supplicant.watch, (GSourceFunc) supplicant_watch_cb, self, NULL); - g_source_attach (self->priv->supplicant.watch, nm_device_get_main_context (NM_DEVICE (self))); - } - - return success; + remove_supplicant_connection_timeout (self); + remove_link_timeout (self); } -static gboolean -supplicant_interface_init (NMDevice80211Wireless *self) +static NMSupplicantConfig * +build_supplicant_config (NMDevice80211Wireless *self, + NMActRequest *req) { - struct wpa_ctrl * ctrl = NULL; - char * socket_path; - const char * iface = nm_device_get_iface (NM_DEVICE (self)); - gboolean success = FALSE; - int tries = 0; + NMSupplicantConfig * config = NULL; + NMAccessPoint * ap = NULL; + const char * essid; + gboolean is_adhoc; - /* Try to open wpa_supplicant's global control socket */ - for (tries = 0; tries < WPA_SUPPLICANT_NUM_RETRIES && !ctrl; tries++) - { - ctrl = wpa_ctrl_open (WPA_SUPPLICANT_GLOBAL_SOCKET, NM_RUN_DIR); - g_usleep (WPA_SUPPLICANT_RETRY_TIME_US); - } - - if (!ctrl) - { - nm_info ("Error opening supplicant global control interface."); - goto exit; - } - - /* wpa_cli -g/var/run/wpa_supplicant-global interface_add eth1 "" wext /var/run/wpa_supplicant */ - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, - "INTERFACE_ADD %s\t\twext\t" WPA_SUPPLICANT_CONTROL_SOCKET "\t", iface)) - goto exit; - wpa_ctrl_close (ctrl); - - /* Get a control socket to wpa_supplicant for this interface. - * Try a couple times to work around naive socket naming - * in wpa_ctrl that sometimes collides with stale ones. - */ - socket_path = supplicant_get_device_socket_path (self); - while (!self->priv->supplicant.ctrl && (tries++ < 10)) - self->priv->supplicant.ctrl = wpa_ctrl_open (socket_path, NM_RUN_DIR); - g_free (socket_path); - if (!self->priv->supplicant.ctrl) - { - nm_info ("Error opening control interface to supplicant."); - goto exit; - } - success = TRUE; - -exit: - return success; -} - - -static gboolean -supplicant_send_network_config (NMDevice80211Wireless *self, - NMActRequest *req) -{ - NMAccessPoint * ap = NULL; - gboolean success = FALSE; - char * response = NULL; - int nwid; - const char * essid; - struct wpa_ctrl * ctrl; - gboolean is_adhoc; - const char * hex_essid; - const char * ap_scan = "AP_SCAN 1"; - guint32 caps; - gboolean supports_wpa; - - g_return_val_if_fail (self != NULL, FALSE); - g_return_val_if_fail (req != NULL, FALSE); + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (req != NULL, NULL); ap = nm_act_request_get_ap (req); g_assert (ap); - ctrl = self->priv->supplicant.ctrl; - g_assert (ctrl); + config = nm_supplicant_config_new (NM_DEVICE (self)); + if (config == NULL) + goto out; - /* Assume that drivers that don't support WPA pretty much suck, - * and can't handle NM scanning along with wpa_supplicant. Which - * is the case for most of them, airo in particular. - */ - caps = nm_device_get_type_capabilities (NM_DEVICE (self)); - supports_wpa = (caps & NM_802_11_CAP_PROTO_WPA) - || (caps & NM_802_11_CAP_PROTO_WPA2); - - /* Use "AP_SCAN 2" if: - * - The wireless network is non-broadcast or Ad-Hoc - * - The wireless driver does not support WPA (stupid drivers...) - */ + /* Use "AP_SCAN 2" if the wireless network is non-broadcast or Ad-Hoc */ is_adhoc = (nm_ap_get_mode(ap) == IW_MODE_ADHOC); - if (!nm_ap_get_broadcast (ap) || is_adhoc || !supports_wpa) - ap_scan = "AP_SCAN 2"; - - /* Tell wpa_supplicant that we'll do the scanning */ - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, ap_scan)) - goto out; - - /* Standard network setup info */ - if (!(response = nm_utils_supplicant_request (ctrl, "ADD_NETWORK"))) - { - nm_warning ("Supplicant error for ADD_NETWORK.\n"); - goto out; + if (!nm_ap_get_broadcast (ap) || (nm_ap_get_mode(ap) == IW_MODE_ADHOC)) { + nm_supplicant_config_set_ap_scan (config, 2); } - if (sscanf (response, "%i\n", &nwid) != 1) - { - nm_warning ("Supplicant error for ADD_NETWORK. Response: '%s'\n", response); - g_free (response); - goto out; - } - g_free (response); - - if (nm_device_activation_should_cancel (NM_DEVICE (self))) - goto out; essid = nm_ap_get_orig_essid (ap); - hex_essid = cipher_bin2hexstr (essid, strlen (essid), -1); - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, - "SET_NETWORK %i ssid %s", nwid, hex_essid)) - goto out; + nm_supplicant_config_add_option (config, "ssid", essid, -1); /* For non-broadcast networks, we need to set "scan_ssid 1" to scan with probe request frames. * However, don't try to probe Ad-Hoc networks. */ - if (!nm_ap_get_broadcast (ap) && !is_adhoc) - { - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, - "SET_NETWORK %i scan_ssid 1", nwid)) - goto out; + if (!nm_ap_get_broadcast (ap) && !is_adhoc) { + if (!nm_supplicant_config_add_option (config, "scan_ssid", "1", -1)) + goto error; } /* Ad-Hoc ? */ - if (is_adhoc) - { - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, - "SET_NETWORK %i mode 1", nwid)) - goto out; + if (is_adhoc) { + if (!nm_supplicant_config_add_option (config, "mode", "1", -1)) + goto error; } - if (nm_device_activation_should_cancel (NM_DEVICE (self))) - goto out; - - if (!nm_ap_security_write_supplicant_config (nm_ap_get_security (ap), ctrl, nwid, is_adhoc)) - goto out; - - if (nm_device_activation_should_cancel (NM_DEVICE (self))) - goto out; - - if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, - "ENABLE_NETWORK %i", nwid, essid)) - goto out; - - success = TRUE; -out: - return success; -} - - -static gboolean -supplicant_monitor_start (NMDevice80211Wireless *self) -{ - gboolean success = FALSE; - int fd = -1; - GIOChannel * channel; - GMainContext * context; - - g_return_val_if_fail (self != NULL, FALSE); - - /* register network event monitor */ - if (wpa_ctrl_attach (self->priv->supplicant.ctrl) != 0) - goto out; - - if ((fd = wpa_ctrl_get_fd (self->priv->supplicant.ctrl)) < 0) - goto out; - - context = nm_device_get_main_context (NM_DEVICE (self)); - channel = g_io_channel_unix_new (fd); - self->priv->supplicant.status = g_io_create_watch (channel, G_IO_IN); - g_source_set_callback (self->priv->supplicant.status, (GSourceFunc) supplicant_status_cb, self, NULL); - g_source_attach (self->priv->supplicant.status, context); - - /* Set up a timeout on the association to kill it after get_supplicant_time() seconds */ - self->priv->supplicant.timeout = g_timeout_source_new (get_supplicant_timeout (self) * 1000); - g_source_set_callback (self->priv->supplicant.timeout, supplicant_timeout_cb, self, NULL); - g_source_attach (self->priv->supplicant.timeout, context); - - success = TRUE; + if (!nm_ap_security_write_supplicant_config (nm_ap_get_security (ap), + config, + is_adhoc)) + goto error; out: - return success; + return config; + +error: + g_object_unref (config); + return NULL; } - - - /****************************************************************************/ + static NMActStageReturn real_act_stage2_config (NMDevice *dev, NMActRequest *req) { - NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (dev); - NMAccessPoint * ap = nm_act_request_get_ap (req); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - const char * iface; - gboolean ask_user = FALSE; + NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (dev); + NMAccessPoint * ap = nm_act_request_get_ap (req); + NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; + const char * iface = nm_device_get_iface (dev); + gboolean ask_user = FALSE; + NMSupplicantConfig * config = NULL; + GMainContext * context; + gulong id = 0; g_assert (ap); - supplicant_cleanup (self); + remove_supplicant_timeouts (self); /* If we need an encryption key, get one */ - if (ap_need_key (self, ap, &ask_user)) - { + if (ap_need_key (self, ap, &ask_user)) { nm_dbus_get_user_key_for_network (req, ask_user); return NM_ACT_STAGE_RETURN_POSTPONE; } - iface = nm_device_get_iface (dev); - if (!supplicant_exec (self)) - { - nm_warning ("Activation (%s/wireless): couldn't start the supplicant.", - iface); + config = build_supplicant_config (self, req); + if (config == NULL) { + nm_warning ("Activation (%s/wireless): couldn't build wireless " + "configuration.", iface); goto out; } - if (!supplicant_interface_init (self)) - { - nm_warning ("Activation (%s/wireless): couldn't connect to the supplicant.", - iface); + + if (nm_device_activation_should_cancel (NM_DEVICE (self))) + goto out; + + /* Hook up error signal handler to capture association errors */ + id = g_signal_connect (G_OBJECT (self->priv->supplicant.iface), + "connection-error", + G_CALLBACK (supplicant_iface_connection_error_cb), + self); + self->priv->supplicant.iface_error_id = id; + + if (!nm_supplicant_interface_set_config (self->priv->supplicant.iface, config)) { + nm_warning ("Activation (%s/wireless): couldn't send wireless " + "configuration to the supplicant.", iface); goto out; } - if (!supplicant_send_network_config (self, req)) - { - nm_warning ("Activation (%s/wireless): couldn't send wireless configuration" - " to the supplicant.", iface); - goto out; - } - if (!supplicant_monitor_start (self)) - { - nm_warning ("Activation (%s/wireless): couldn't monitor the supplicant.", - iface); + + /* Set up a timeout on the connection attempt to fail it after 25 seconds */ + self->priv->supplicant.con_timeout = g_timeout_source_new (25000); + if (!self->priv->supplicant.con_timeout) { + nm_warning ("Activation (%s/wireless): couldn't start supplicant " + "timeout timer.", iface); goto out; } + g_source_set_callback (self->priv->supplicant.con_timeout, + supplicant_connection_timeout_cb, + self, + NULL); + context = nm_device_get_main_context (dev); + g_source_attach (self->priv->supplicant.con_timeout, context); /* We'll get stage3 started when the supplicant connects */ ret = NM_ACT_STAGE_RETURN_POSTPONE; out: + if (ret == NM_ACT_STAGE_RETURN_FAILURE) { + cleanup_association_attempt (self, TRUE); + } + + if (config) { + /* Supplicant interface object refs the config; we no longer care about + * it after this function. + */ + g_object_unref (config); + } return ret; } @@ -3308,15 +3241,15 @@ nm_device_802_11_wireless_dispose (GObject *object) cancel_pending_scan (self); - if (self->priv->sup_iface) { - nm_supplicant_manager_release_iface (self->priv->sup_mgr, - self->priv->sup_iface); - self->priv->sup_iface = NULL; + if (self->priv->supplicant.iface) { + nm_supplicant_manager_release_iface (self->priv->supplicant.mgr, + self->priv->supplicant.iface); + self->priv->supplicant.iface = NULL; } - if (self->priv->sup_mgr) { - g_object_unref (self->priv->sup_mgr); - self->priv->sup_mgr = NULL; + if (self->priv->supplicant.mgr) { + g_object_unref (self->priv->supplicant.mgr); + self->priv->supplicant.mgr = NULL; } out: diff --git a/src/nm-device-802-11-wireless.h b/src/nm-device-802-11-wireless.h index d3c70e5170..70f379be37 100644 --- a/src/nm-device-802-11-wireless.h +++ b/src/nm-device-802-11-wireless.h @@ -120,6 +120,8 @@ int nm_device_802_11_wireless_get_mode (NMDevice80211Wireless *self); gint8 nm_device_802_11_wireless_get_signal_strength (NMDevice80211Wireless *self); +gboolean nm_device_802_11_wireless_can_activate (NMDevice80211Wireless * self); + G_END_DECLS diff --git a/src/supplicant-manager/nm-supplicant-config.c b/src/supplicant-manager/nm-supplicant-config.c index 786f745c7c..d1f7a5f943 100644 --- a/src/supplicant-manager/nm-supplicant-config.c +++ b/src/supplicant-manager/nm-supplicant-config.c @@ -19,11 +19,14 @@ * (C) Copyright 2006 Red Hat, Inc. */ +#include #include #include "nm-supplicant-config.h" #include "nm-supplicant-settings-verify.h" #include "nm-utils.h" +#include "dbus-dict-helpers.h" +#include "cipher.h" #define NM_SUPPLICANT_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ NM_TYPE_SUPPLICANT_CONFIG, \ @@ -34,11 +37,19 @@ static void nm_supplicant_config_set_device (NMSupplicantConfig *con, NMDevice *dev); +struct option { + char * key; + char * value; + guint32 len; + enum OptType type; +}; + struct _NMSupplicantConfigPrivate { - NMDevice * dev; - GHashTable * config; - gboolean dispose_has_run; + NMDevice * dev; + GSList * config; + guint32 ap_scan; + gboolean dispose_has_run; }; NMSupplicantConfig * @@ -57,8 +68,8 @@ static void nm_supplicant_config_init (NMSupplicantConfig * self) { self->priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self); - self->priv->config = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, - g_free); + self->priv->config = NULL; + self->priv->ap_scan = 1; self->priv->dispose_has_run = FALSE; } @@ -76,34 +87,100 @@ nm_supplicant_config_set_device (NMSupplicantConfig *self, gboolean nm_supplicant_config_add_option (NMSupplicantConfig *self, const char * key, - const char * value) + const char * value, + gint32 len) { + GSList * elt; + struct option * opt; + OptType type; + g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (key != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); - if (!nm_supplicant_settings_verify_setting (key, value)) { - nm_debug ("Key '%s' and/or value '%s' invalid.", key, value); + if (len < 0) + len = strlen (value); + + type = nm_supplicant_settings_verify_setting (key, value, len); + if (type == TYPE_INVALID) { + char buf[255]; + memset (&buf[0], 0, sizeof (buf)); + memcpy (&buf[0], value, len > 254 ? 254 : len); + nm_debug ("Key '%s' and/or value '%s' invalid.", key, buf); return FALSE; } - if (g_hash_table_lookup (self->priv->config, key)) { - nm_debug ("Key '%s' already in table.", key); - return FALSE; + for (elt = self->priv->config; elt; elt = g_slist_next (elt)) { + struct option * tmp_opt = (struct option *) elt->data; + + if (strcmp (tmp_opt->key, key) == 0) { + nm_debug ("Key '%s' already in table.", key); + return FALSE; + } } - g_hash_table_insert (self->priv->config, g_strdup (key), g_strdup (value)); + opt = g_slice_new0 (struct option); + if (opt == NULL) { + nm_debug ("Couldn't allocate memory for new config option."); + return FALSE; + } + opt->key = g_strdup (key); + if (opt->key == NULL) { + nm_debug ("Couldn't allocate memory for new config option key."); + g_slice_free (struct option, opt); + return FALSE; + } + opt->value = g_malloc0 (sizeof (char) * len); + if (opt->value == NULL) { + nm_debug ("Couldn't allocate memory for new config option value."); + g_free (opt->key); + g_slice_free (struct option, opt); + return FALSE; + } + memcpy (opt->value, value, len); + + opt->len = len; + opt->type = type; + self->priv->config = g_slist_append (self->priv->config, opt); + return TRUE; } +static void +free_option (struct option * opt) +{ + g_return_if_fail (opt != NULL); + g_free (opt->key); + g_free (opt->value); +} + gboolean nm_supplicant_config_remove_option (NMSupplicantConfig *self, const char * key) { + GSList * elt; + GSList * found = NULL; + g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (key != NULL, FALSE); - return g_hash_table_remove (self->priv->config, key); + for (elt = self->priv->config; elt; elt = g_slist_next (elt)) { + struct option * opt = (struct option *) elt->data; + + if (strcmp (opt->key, key) == 0) { + found = elt; + break; + } + } + + if (!found) + return FALSE; + + self->priv->config = g_slist_remove_link (self->priv->config, found); + free_option (found->data); + g_slice_free (struct option, found->data); + g_slist_free1 (found); + return TRUE; } static void @@ -143,9 +220,15 @@ nm_supplicant_config_finalize (GObject *object) NMSupplicantConfig * self = NM_SUPPLICANT_CONFIG (object); NMSupplicantConfigClass * klass; GObjectClass * parent_class; + GSList * elt; /* Complete object destruction */ - g_hash_table_destroy (self->priv->config); + for (elt = self->priv->config; elt; elt = g_slist_next (elt)) { + free_option (elt->data); + g_slice_free (struct option, elt->data); + } + g_slist_free (self->priv->config); + self->priv->config = NULL; /* Chain up to the parent class */ klass = NM_SUPPLICANT_CONFIG_CLASS (g_type_class_peek (NM_TYPE_SUPPLICANT_CONFIG)); @@ -189,3 +272,87 @@ nm_supplicant_config_get_type (void) } return type; } + +guint32 +nm_supplicant_config_get_ap_scan (NMSupplicantConfig * self) +{ + g_return_val_if_fail (self != NULL, 1); + + return self->priv->ap_scan; +} + +void +nm_supplicant_config_set_ap_scan (NMSupplicantConfig * self, + guint32 ap_scan) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (ap_scan >= 0 && ap_scan <=2); + + self->priv->ap_scan = ap_scan; +} + +gboolean +nm_supplicant_config_add_to_dbus_message (NMSupplicantConfig * self, + DBusMessage * message) +{ + GSList * elt; + DBusMessageIter iter, iter_dict; + gboolean success = FALSE; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (message != NULL, FALSE); + + dbus_message_iter_init_append (message, &iter); + + if (!nmu_dbus_dict_open_write (&iter, &iter_dict)) { + nm_warning ("dict open write failed!"); + goto out; + } + + for (elt = self->priv->config; elt; elt = g_slist_next (elt)) { + struct option * opt = (struct option *) elt->data; + + switch (opt->type) { + case TYPE_INT: + if (!nmu_dbus_dict_append_string (&iter_dict, opt->key, opt->value)) { + nm_warning ("couldn't append INT option '%s' to dict", opt->key); + goto out; + } + break; + + case TYPE_KEYWORD: + if (!nmu_dbus_dict_append_string (&iter_dict, opt->key, opt->value)) { + nm_warning ("couldn't append KEYWORD option '%s' to dict", opt->key); + goto out; + } + break; + + case TYPE_BYTES: + { + if (!nmu_dbus_dict_append_byte_array (&iter_dict, + opt->key, + opt->value, + opt->len)) { + nm_warning ("couldn't append BYTES option '%s' to dict", opt->key); + goto out; + } + } + break; + + default: + nm_warning ("unknown option '%s', type %d", opt->key, opt->type); + goto out; + break; + } + } + + if (!nmu_dbus_dict_close_write (&iter, &iter_dict)) { + nm_warning ("dict close write failed!"); + goto out; + } + + success = TRUE; + +out: + return success; +} diff --git a/src/supplicant-manager/nm-supplicant-config.h b/src/supplicant-manager/nm-supplicant-config.h index 2b63425bb8..feb357b1f2 100644 --- a/src/supplicant-manager/nm-supplicant-config.h +++ b/src/supplicant-manager/nm-supplicant-config.h @@ -60,11 +60,20 @@ NMSupplicantConfig * nm_supplicant_config_new (NMDevice *dev); gboolean nm_supplicant_config_add_option (NMSupplicantConfig *scfg, const char * key, - const char * value); + const char * value, + gint32 len); gboolean nm_supplicant_config_remove_option (NMSupplicantConfig *self, const char * key); +guint32 nm_supplicant_config_get_ap_scan (NMSupplicantConfig * self); + +void nm_supplicant_config_set_ap_scan (NMSupplicantConfig * self, + guint32 ap_scan); + +gboolean nm_supplicant_config_add_to_dbus_message (NMSupplicantConfig * self, + DBusMessage * message); + G_END_DECLS #endif /* NM_SUPPLICANT_CONFIG_H */ diff --git a/src/supplicant-manager/nm-supplicant-interface.c b/src/supplicant-manager/nm-supplicant-interface.c index f39311cc22..2ccb27e279 100644 --- a/src/supplicant-manager/nm-supplicant-interface.c +++ b/src/supplicant-manager/nm-supplicant-interface.c @@ -28,6 +28,7 @@ #include "nm-device-802-3-ethernet.h" #include "nm-utils.h" #include "nm-supplicant-marshal.h" +#include "nm-supplicant-config.h" #include "nm-dbus-manager.h" #include "dbus-dict-helpers.h" #include "NetworkManagerMain.h" @@ -71,6 +72,7 @@ enum { SCANNED_AP, /* interface saw a new access point from a scan */ SCAN_RESULT, /* result of a wireless scan request */ CONNECTION_STATE, /* link state of the device's connection */ + CONNECTION_ERROR, /* an error occurred during a connection request */ LAST_SIGNAL }; static guint nm_supplicant_interface_signals[LAST_SIGNAL] = { 0 }; @@ -95,7 +97,8 @@ struct _NMSupplicantInterfacePrivate NMDevice * dev; guint32 state; - GSList * pcalls; + GSList * assoc_pcalls; + GSList * other_pcalls; guint32 con_state; @@ -110,61 +113,61 @@ struct _NMSupplicantInterfacePrivate gboolean dispose_has_run; }; -static void -add_pcall (NMSupplicantInterface * self, - DBusPendingCall * pcall) +static GSList * +pcall_list_add_pcall (GSList * pcall_list, + DBusPendingCall * pcall) { GSList * elt; - g_return_if_fail (self != NULL); - g_return_if_fail (pcall != NULL); + g_return_val_if_fail (pcall != NULL, pcall_list); - for (elt = self->priv->pcalls; elt; elt = g_slist_next (elt)) { + for (elt = pcall_list; elt; elt = g_slist_next (elt)) { if (pcall == elt->data) - return; + return pcall_list; } - self->priv->pcalls = g_slist_append (self->priv->pcalls, pcall); + return g_slist_append (pcall_list, pcall); } -static void -remove_pcall (NMSupplicantInterface * self, - DBusPendingCall * pcall) +static GSList * +pcall_list_remove_pcall (GSList * pcall_list, + DBusPendingCall * pcall) { GSList * elt; - g_return_if_fail (self != NULL); - g_return_if_fail (pcall != NULL); + g_return_val_if_fail (pcall != NULL, pcall_list); - for (elt = self->priv->pcalls; elt; elt = g_slist_next (elt)) { - DBusPendingCall * list_pcall = (DBusPendingCall *) elt->data; + for (elt = pcall_list; elt; elt = g_slist_next (elt)) { + DBusPendingCall * item = (DBusPendingCall *) elt->data; - if (list_pcall == pcall) { + if (item == pcall) { if (!dbus_pending_call_get_completed (pcall)) dbus_pending_call_cancel (pcall); - self->priv->pcalls = g_slist_remove_link (self->priv->pcalls, elt); + dbus_pending_call_unref (pcall); + pcall_list = g_slist_remove_link (pcall_list, elt); g_slist_free_1 (elt); - return; + goto out; } } + +out: + return pcall_list; } -static void -clear_pcalls (NMSupplicantInterface * self) +static GSList * +pcall_list_clear (GSList * pcall_list) { GSList * elt; - g_return_if_fail (self != NULL); - - for (elt = self->priv->pcalls; elt; elt = g_slist_next (elt)) { + for (elt = pcall_list; elt; elt = g_slist_next (elt)) { DBusPendingCall * pcall = (DBusPendingCall *) elt->data; if (!dbus_pending_call_get_completed (pcall)) dbus_pending_call_cancel (pcall); dbus_pending_call_unref (pcall); } - g_slist_free (self->priv->pcalls); - self->priv->pcalls = NULL; + g_slist_free (pcall_list); + return NULL; } @@ -197,7 +200,8 @@ nm_supplicant_interface_init (NMSupplicantInterface * self) self->priv->smgr = NULL; self->priv->dev = NULL; self->priv->wpas_iface_op = NULL; - self->priv->pcalls = NULL; + self->priv->assoc_pcalls = NULL; + self->priv->other_pcalls = NULL; self->priv->dispose_has_run = FALSE; self->priv->dbus_mgr = nm_dbus_manager_get (NULL); @@ -306,7 +310,8 @@ nm_supplicant_interface_dispose (GObject *object) } /* Cancel pending calls before unrefing the dbus manager */ - clear_pcalls (self); + self->priv->other_pcalls = pcall_list_clear (self->priv->other_pcalls); + self->priv->assoc_pcalls = pcall_list_clear (self->priv->assoc_pcalls); if (self->priv->dbus_mgr) { if (self->priv->wpas_sig_handler_id) { @@ -337,11 +342,15 @@ nm_supplicant_interface_finalize (GObject *object) NMSupplicantInterfaceClass * klass; GObjectClass * parent_class; - if (self->priv->wpas_iface_op) + if (self->priv->wpas_iface_op) { g_free (self->priv->wpas_iface_op); + self->priv->wpas_iface_op = NULL; + } - if (self->priv->wpas_net_op) + if (self->priv->wpas_net_op) { g_free (self->priv->wpas_net_op); + self->priv->wpas_net_op = NULL; + } /* Chain up to the parent class */ klass = NM_SUPPLICANT_INTERFACE_CLASS (g_type_class_peek (NM_TYPE_SUPPLICANT_INTERFACE)); @@ -439,6 +448,16 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) nm_supplicant_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); klass->connection_state = NULL; + + nm_supplicant_interface_signals[CONNECTION_ERROR] = + g_signal_new ("connection-error", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMSupplicantInterfaceClass, connection_error), + NULL, NULL, + nm_supplicant_marshal_VOID__CHAR_CHAR, + G_TYPE_NONE, 2, G_TYPE_CHAR, G_TYPE_CHAR); + klass->connection_error = NULL; } GType @@ -466,6 +485,22 @@ nm_supplicant_interface_get_type (void) return type; } +static void +emit_error_helper (NMSupplicantInterface * self, + const char * name, + const char * message) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (name != NULL); + g_return_if_fail (message != NULL); + + g_signal_emit (G_OBJECT (self), + nm_supplicant_interface_signals[CONNECTION_ERROR], + 0, + name, + message); +} + static void set_wpas_iface_op_from_message (NMSupplicantInterface * self, @@ -535,7 +570,7 @@ out: dbus_message_unref (reply); if (dbus_error_is_set (&error)) dbus_error_free (&error); - remove_pcall (self, pcall); + self->priv->other_pcalls = pcall_list_remove_pcall (self->priv->other_pcalls, pcall); } static void @@ -574,7 +609,7 @@ request_bssid_properties (NMSupplicantInterface * self, nm_warning ("could not send dbus message."); goto out; } - add_pcall (self, pcall); + self->priv->other_pcalls = pcall_list_add_pcall (self->priv->other_pcalls, pcall); out: if (message) @@ -631,7 +666,7 @@ out: dbus_message_unref (reply); if (dbus_error_is_set (&error)) dbus_error_free (&error); - remove_pcall (self, pcall); + self->priv->other_pcalls = pcall_list_remove_pcall (self->priv->other_pcalls, pcall); } static gboolean @@ -673,7 +708,7 @@ request_scan_results (gpointer user_data) nm_warning ("could not send dbus message."); goto out; } - add_pcall (self, pcall); + self->priv->other_pcalls = pcall_list_add_pcall (self->priv->other_pcalls, pcall); g_get_current_time (&cur_time); self->priv->last_scan = cur_time.tv_sec; @@ -836,11 +871,22 @@ iface_state_cb (DBusPendingCall * pcall, if (!(reply = dbus_pending_call_steal_reply (pcall))) goto out; + if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) { + if (!dbus_set_error_from_message (&error, reply)) { + nm_warning ("couldn't get error information."); + } else { + nm_warning ("could not get interface state: %s - %s.", + error.name, + error.message); + } + goto out; + } + if (!dbus_message_get_args (reply, &error, DBUS_TYPE_STRING, &state_str, DBUS_TYPE_INVALID)) { - nm_warning ("could not get scan results: %s - %s.", + nm_warning ("could not get interface state: %s - %s.", error.name, error.message); goto out; @@ -854,7 +900,7 @@ out: dbus_message_unref (reply); if (dbus_error_is_set (&error)) dbus_error_free (&error); - remove_pcall (self, pcall); + self->priv->other_pcalls = pcall_list_remove_pcall (self->priv->other_pcalls, pcall); } static void @@ -894,7 +940,7 @@ wpas_iface_get_state (NMSupplicantInterface *self) nm_warning ("could not send dbus message."); goto out; } - add_pcall (self, pcall); + self->priv->other_pcalls = pcall_list_add_pcall (self->priv->other_pcalls, pcall); out: if (message) @@ -962,7 +1008,7 @@ out: dbus_message_unref (reply); if (dbus_error_is_set (&error)) dbus_error_free (&error); - remove_pcall (self, pcall); + self->priv->other_pcalls = pcall_list_remove_pcall (self->priv->other_pcalls, pcall); } @@ -1034,7 +1080,7 @@ nm_supplicant_interface_add_to_supplicant (NMSupplicantInterface * self, nm_warning ("could not send dbus message."); goto out; } - add_pcall (self, pcall); + self->priv->other_pcalls = pcall_list_add_pcall (self->priv->other_pcalls, pcall); out: if (message) @@ -1107,7 +1153,8 @@ nm_supplicant_interface_set_state (NMSupplicantInterface * self, /* If the interface is transitioning to DOWN and there's are * in-progress pending calls, cancel them. */ - clear_pcalls (self); + self->priv->other_pcalls = pcall_list_clear (self->priv->other_pcalls); + self->priv->assoc_pcalls = pcall_list_clear (self->priv->assoc_pcalls); } self->priv->state = new_state; @@ -1144,56 +1191,498 @@ nm_supplicant_interface_smgr_state_changed (NMSupplicantManager * smgr, } } -#if 0 + static void -add_config_to_iface (NMSupplicantInterface *self) +remove_network_cb (DBusPendingCall * pcall, + NMSupplicantInterface * self) { - DBusConnection * dbus_connection; - DBusMessage * message = NULL; + DBusError error; + DBusMessage * reply = NULL; + + g_return_if_fail (pcall != NULL); + g_return_if_fail (self != NULL); + + dbus_error_init (&error); + + nm_dbus_send_with_callback_replied (pcall, __func__); + + if (!dbus_pending_call_get_completed (pcall)) + goto out; + + if (!(reply = dbus_pending_call_steal_reply (pcall))) + goto out; + + if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) { + dbus_set_error_from_message (&error, reply); + nm_warning ("Couldn't remove network from supplicant interface: %s - %s", + error.name, + error.message); + } + +out: + if (reply) + dbus_message_unref (reply); + if (dbus_error_is_set (&error)) + dbus_error_free (&error); + self->priv->other_pcalls = pcall_list_remove_pcall (self->priv->other_pcalls, pcall); +} + +static void +disconnect_cb (DBusPendingCall * pcall, + NMSupplicantInterface * self) +{ + DBusError error; + DBusMessage * reply = NULL; + + g_return_if_fail (pcall != NULL); + g_return_if_fail (self != NULL); + + dbus_error_init (&error); + + nm_dbus_send_with_callback_replied (pcall, __func__); + + if (!dbus_pending_call_get_completed (pcall)) + goto out; + + if (!(reply = dbus_pending_call_steal_reply (pcall))) + goto out; + + if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) { + dbus_set_error_from_message (&error, reply); + nm_warning ("Couldn't disconnect supplicant interface: %s - %s", + error.name, + error.message); + } + +out: + if (reply) + dbus_message_unref (reply); + if (dbus_error_is_set (&error)) + dbus_error_free (&error); + self->priv->other_pcalls = pcall_list_remove_pcall (self->priv->other_pcalls, pcall); +} + +void +nm_supplicant_interface_disconnect (NMSupplicantInterface * self) +{ + DBusMessage * message = NULL; DBusPendingCall * pcall = NULL; + DBusConnection * dbus_connection; g_return_if_fail (self != NULL); + /* Clear and cancel all pending calls related to a prior + * connection attempt. + */ + self->priv->assoc_pcalls = pcall_list_clear (self->priv->assoc_pcalls); + + /* Don't do anything if there is no connection to the supplicant yet. */ + if (!self->priv->wpas_iface_op) + return; + dbus_connection = nm_dbus_manager_get_dbus_connection (self->priv->dbus_mgr); if (!dbus_connection) { nm_warning ("could not get the dbus connection."); goto out; } + /* Don't try to disconnect if the supplicant interface is already + * disconnected. + */ + if (self->priv->con_state != NM_SUPPLICANT_INTERFACE_CON_STATE_DISCONNECTED + && self->priv->con_state != NM_SUPPLICANT_INTERFACE_CON_STATE_INACTIVE) { + if (self->priv->wpas_net_op) { + g_free (self->priv->wpas_net_op); + self->priv->wpas_net_op = NULL; + } + return; + } + + /* Remove any network that was added by NetworkManager */ + if (self->priv->wpas_net_op) { + message = dbus_message_new_method_call (WPAS_DBUS_SERVICE, + self->priv->wpas_iface_op, + WPAS_DBUS_IFACE_INTERFACE, + "removeNetwork"); + if (!message) { + nm_warning ("Couldn't create dbus message."); + goto out; + } + + if (!dbus_message_append_args (message, + DBUS_TYPE_OBJECT_PATH, &self->priv->wpas_net_op, + DBUS_TYPE_INVALID)) { + nm_warning ("Couldn't compose removeNetwork dbus message."); + goto out; + } + + pcall = nm_dbus_send_with_callback (dbus_connection, + message, + (DBusPendingCallNotifyFunction) remove_network_cb, + self, + NULL, + __func__); + dbus_message_unref (message); + g_free (self->priv->wpas_net_op); + self->priv->wpas_net_op = NULL; + } + + /* Send a general disconnect command */ message = dbus_message_new_method_call (WPAS_DBUS_SERVICE, - WPAS_DBUS_IFACE_INTERFACE, self->priv->wpas_iface_op, - "addNetwork"); + WPAS_DBUS_IFACE_INTERFACE, + "disconnect"); if (!message) { nm_warning ("Couldn't create dbus message."); goto out; } -#if 0 pcall = nm_dbus_send_with_callback (dbus_connection, message, - (DBusPendingCallNotifyFunction) nm_supplicant_interface_add_config_cb, + (DBusPendingCallNotifyFunction) disconnect_cb, self, NULL, __func__); -#endif out: - ; + if (message) + dbus_message_unref (message); } -#endif -void +#define WPAS_DBUS_IFACE_NETWORK WPAS_DBUS_INTERFACE ".Network" + +static void +select_network_cb (DBusPendingCall * pcall, + NMSupplicantInterface * self) +{ + DBusError error; + DBusMessage * reply = NULL; + + g_return_if_fail (pcall != NULL); + g_return_if_fail (self != NULL); + + dbus_error_init (&error); + + nm_dbus_send_with_callback_replied (pcall, __func__); + + if (!dbus_pending_call_get_completed (pcall)) { + emit_error_helper (self, "SelectNetworkError", "pending call not yet completed"); + goto out; + } + + if (!(reply = dbus_pending_call_steal_reply (pcall))) { + emit_error_helper (self, "SelectNetworkError", "could not steal reply"); + goto out; + } + + if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) { + dbus_set_error_from_message (&error, reply); + nm_warning ("Couldn't select network config: %s - %s", + error.name, + error.message); + emit_error_helper (self, error.name, error.message); + goto out; + } + +out: + if (reply) + dbus_message_unref (reply); + if (dbus_error_is_set (&error)) + dbus_error_free (&error); + self->priv->assoc_pcalls = pcall_list_remove_pcall (self->priv->assoc_pcalls, pcall); +} + +static void +set_network_cb (DBusPendingCall * pcall, + NMSupplicantInterface * self) +{ + DBusError error; + DBusMessage * reply = NULL; + DBusConnection * dbus_connection; + DBusMessage * message = NULL; + + g_return_if_fail (pcall != NULL); + g_return_if_fail (self != NULL); + + dbus_connection = nm_dbus_manager_get_dbus_connection (self->priv->dbus_mgr); + if (!dbus_connection) { + nm_warning ("could not get the dbus connection."); + emit_error_helper (self, "SetNetworkError", "could not get the dbus connection."); + goto out; + } + + dbus_error_init (&error); + + nm_dbus_send_with_callback_replied (pcall, __func__); + + if (!dbus_pending_call_get_completed (pcall)) { + emit_error_helper (self, "SetNetworkError", "pending call not yet completed"); + goto out; + } + + if (!(reply = dbus_pending_call_steal_reply (pcall))) { + emit_error_helper (self, "SetNetworkError", "could not steal reply"); + goto out; + } + + if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) { + dbus_set_error_from_message (&error, reply); + nm_warning ("Couldn't set network config: %s - %s", + error.name, + error.message); + emit_error_helper (self, error.name, error.message); + goto out; + } + + message = dbus_message_new_method_call (WPAS_DBUS_SERVICE, + self->priv->wpas_iface_op, + WPAS_DBUS_IFACE_INTERFACE, + "selectNetwork"); + if (!message) { + nm_warning ("Couldn't create dbus message."); + emit_error_helper (self, "SetNetworkError", "could not create dbus message."); + goto out; + } + + if (!dbus_message_append_args (message, + DBUS_TYPE_OBJECT_PATH, &self->priv->wpas_net_op, + DBUS_TYPE_INVALID)) { + emit_error_helper (self, "SetNetworkError", "could not add arguments to message."); + goto out; + } + + nm_dbus_send_with_callback (dbus_connection, + message, + (DBusPendingCallNotifyFunction) select_network_cb, + self, + NULL, + __func__); + +out: + if (reply) + dbus_message_unref (reply); + if (message) + dbus_message_unref (message); + if (dbus_error_is_set (&error)) + dbus_error_free (&error); + self->priv->assoc_pcalls = pcall_list_remove_pcall (self->priv->assoc_pcalls, pcall); +} + +static void +add_network_cb (DBusPendingCall * pcall, + NMSupplicantInterface * self) +{ + DBusError error; + DBusMessage * reply = NULL; + DBusMessage * message = NULL; + DBusConnection * dbus_connection = NULL; + char * net_op = NULL; + + g_return_if_fail (pcall != NULL); + g_return_if_fail (self != NULL); + + dbus_connection = nm_dbus_manager_get_dbus_connection (self->priv->dbus_mgr); + if (!dbus_connection) { + nm_warning ("could not get the dbus connection."); + emit_error_helper (self, "AddNetworkError", "could not get the dbus connection."); + goto out; + } + + dbus_error_init (&error); + + nm_dbus_send_with_callback_replied (pcall, __func__); + + if (!dbus_pending_call_get_completed (pcall)) { + emit_error_helper (self, "AddNetworkError", "pending call not yet completed."); + goto out; + } + + if (!(reply = dbus_pending_call_steal_reply (pcall))) { + emit_error_helper (self, "AddNetworkError", "could not steal reply"); + goto out; + } + + if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) { + dbus_set_error_from_message (&error, reply); + nm_warning ("Couldn't add a network to the supplicant interface: %s - %s", + error.name, + error.message); + emit_error_helper (self, error.name, error.message); + goto out; + } + + if (!dbus_message_get_args (reply, + &error, + DBUS_TYPE_OBJECT_PATH, &net_op, + DBUS_TYPE_INVALID)) { + nm_warning ("couldn't get network object path from the supplicant: %s - %s", + error.name, + error.message); + emit_error_helper (self, error.name, error.message); + goto out; + } + self->priv->wpas_net_op = g_strdup (net_op); + + message = dbus_message_new_method_call (WPAS_DBUS_SERVICE, + self->priv->wpas_net_op, + WPAS_DBUS_IFACE_NETWORK, + "set"); + if (!message) { + nm_warning ("Couldn't create dbus message."); + emit_error_helper (self, "AddNetworkError", "could not create dbus message."); + goto out; + } + + if (!nm_supplicant_config_add_to_dbus_message (self->priv->cfg, message)) { + emit_error_helper (self, "AddNetworkError", "could not add config to dbus message."); + goto out; + } + + nm_dbus_send_with_callback (dbus_connection, + message, + (DBusPendingCallNotifyFunction) set_network_cb, + self, + NULL, + __func__); + dbus_message_unref (message); + +out: + if (reply) + dbus_message_unref (reply); + if (dbus_error_is_set (&error)) + dbus_error_free (&error); + self->priv->assoc_pcalls = pcall_list_remove_pcall (self->priv->assoc_pcalls, pcall); +} + +static void +set_ap_scan_cb (DBusPendingCall * pcall, + NMSupplicantInterface * self) +{ + DBusError error; + DBusMessage * reply = NULL; + DBusMessage * message = NULL; + DBusConnection * dbus_connection = NULL; + + g_return_if_fail (pcall != NULL); + g_return_if_fail (self != NULL); + + dbus_connection = nm_dbus_manager_get_dbus_connection (self->priv->dbus_mgr); + if (!dbus_connection) { + nm_warning ("could not get the dbus connection."); + emit_error_helper (self, "SetAPScanError", "could not get the dbus connection."); + goto out; + } + + dbus_error_init (&error); + + nm_dbus_send_with_callback_replied (pcall, __func__); + + if (!dbus_pending_call_get_completed (pcall)) { + emit_error_helper (self, "SetAPScanError", "pending call not yet completed."); + goto out; + } + + if (!(reply = dbus_pending_call_steal_reply (pcall))) { + emit_error_helper (self, "SetAPScanError", "could not steal reply"); + goto out; + } + + if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) { + dbus_set_error_from_message (&error, reply); + nm_warning ("Couldn't send AP scan mode to the supplicant interface: %s - %s", + error.name, + error.message); + emit_error_helper (self, error.name, error.message); + goto out; + } + + message = dbus_message_new_method_call (WPAS_DBUS_SERVICE, + self->priv->wpas_iface_op, + WPAS_DBUS_IFACE_INTERFACE, + "addNetwork"); + if (!message) { + nm_warning ("Couldn't create dbus message."); + emit_error_helper (self, "SetAPScanError", "couldn't create addNetwork message"); + goto out; + } + + pcall = nm_dbus_send_with_callback (dbus_connection, + message, + (DBusPendingCallNotifyFunction) add_network_cb, + self, + NULL, + __func__); + +out: + if (reply) + dbus_message_unref (reply); + if (dbus_error_is_set (&error)) + dbus_error_free (&error); + self->priv->assoc_pcalls = pcall_list_remove_pcall (self->priv->assoc_pcalls, pcall); +} + +#include +gboolean nm_supplicant_interface_set_config (NMSupplicantInterface * self, NMSupplicantConfig * cfg) { - g_return_if_fail (self != NULL); + DBusConnection * dbus_connection; + DBusMessage * message = NULL; + DBusPendingCall * pcall = NULL; + gboolean success = FALSE; + guint32 ap_scan; + + g_return_val_if_fail (self != NULL, FALSE); + + dbus_connection = nm_dbus_manager_get_dbus_connection (self->priv->dbus_mgr); + if (!dbus_connection) { + nm_warning ("could not get the dbus connection."); + goto out; + } + + nm_supplicant_interface_disconnect (self); if (self->priv->cfg) g_object_unref (self->priv->cfg); self->priv->cfg = cfg; - if (self->priv->cfg) - g_object_ref (self->priv->cfg); + + if (cfg == NULL) { + success = TRUE; + goto out; + } + + g_object_ref (self->priv->cfg); + + message = dbus_message_new_method_call (WPAS_DBUS_SERVICE, + self->priv->wpas_iface_op, + WPAS_DBUS_IFACE_INTERFACE, + "setAPScan"); + if (!message) { + nm_warning ("Couldn't create dbus message."); + goto out; + } + + ap_scan = nm_supplicant_config_get_ap_scan (self->priv->cfg); + if (!dbus_message_append_args (message, + DBUS_TYPE_UINT32, &ap_scan, + DBUS_TYPE_INVALID)) + { + nm_warning ("couldn't set ap scan message arguments."); + goto out; + } + + pcall = nm_dbus_send_with_callback (dbus_connection, + message, + (DBusPendingCallNotifyFunction) set_ap_scan_cb, + self, + NULL, + __func__); + success = TRUE; + +out: + if (message) + dbus_message_unref (message); + return success; } NMDevice * @@ -1249,7 +1738,7 @@ out: dbus_message_unref (reply); if (dbus_error_is_set (&error)) dbus_error_free (&error); - remove_pcall (self, pcall); + self->priv->other_pcalls = pcall_list_remove_pcall (self->priv->other_pcalls, pcall); } gboolean @@ -1288,7 +1777,7 @@ nm_supplicant_interface_request_scan (NMSupplicantInterface * self) nm_warning ("could not send dbus message."); goto out; } - add_pcall (self, pcall); + self->priv->other_pcalls = pcall_list_add_pcall (self->priv->other_pcalls, pcall); success = TRUE; out: diff --git a/src/supplicant-manager/nm-supplicant-interface.h b/src/supplicant-manager/nm-supplicant-interface.h index 411456d5df..d0c7afa6b7 100644 --- a/src/supplicant-manager/nm-supplicant-interface.h +++ b/src/supplicant-manager/nm-supplicant-interface.h @@ -109,6 +109,10 @@ struct _NMSupplicantInterfaceClass void (* connection_state) (NMSupplicantInterface * iface, guint32 new_state, guint32 old_state); + + void (* connection_error) (NMSupplicantInterface * iface, + const char * name, + const char * message); }; @@ -117,8 +121,10 @@ GType nm_supplicant_interface_get_type (void); NMSupplicantInterface * nm_supplicant_interface_new (NMSupplicantManager * smgr, NMDevice * dev); -void nm_supplicant_interface_set_config (NMSupplicantInterface * iface, - NMSupplicantConfig * cfg); +gboolean nm_supplicant_interface_set_config (NMSupplicantInterface * iface, + NMSupplicantConfig * cfg); + +void nm_supplicant_interface_disconnect (NMSupplicantInterface * iface); NMDevice * nm_supplicant_interface_get_device (NMSupplicantInterface * iface); diff --git a/src/supplicant-manager/nm-supplicant-marshal.list b/src/supplicant-manager/nm-supplicant-marshal.list index 6cb743158f..3cf9be041a 100644 --- a/src/supplicant-manager/nm-supplicant-marshal.list +++ b/src/supplicant-manager/nm-supplicant-marshal.list @@ -1 +1,2 @@ VOID:UINT,UINT +VOID:CHAR,CHAR diff --git a/src/supplicant-manager/nm-supplicant-settings-verify.c b/src/supplicant-manager/nm-supplicant-settings-verify.c index 8207676dae..92cb10703c 100644 --- a/src/supplicant-manager/nm-supplicant-settings-verify.c +++ b/src/supplicant-manager/nm-supplicant-settings-verify.c @@ -27,36 +27,38 @@ #include "nm-supplicant-settings-verify.h" -enum OptType { - TYPE_INT = 0, - TYPE_STRING, - TYPE_KEYWORD -}; - struct Opt { - const char * key; - const enum OptType type; - const gint32 int_low; /* Inclusive */ - const gint32 int_high; /* Inclusive */ - const gboolean str_allowed_multiple; - const char ** str_allowed; + const char * key; + const OptType type; + const gint32 int_low; /* Inclusive */ + const gint32 int_high; /* Inclusive; max length for strings */ + const gboolean str_allowed_multiple; + const char ** str_allowed; }; -static gboolean validate_type_int (const struct Opt * opt, const char * value); -static gboolean validate_type_string (const struct Opt * opt, const char * value); -static gboolean validate_type_keyword (const struct Opt * opt, const char * value); +static gboolean validate_type_int (const struct Opt * opt, + const char * value, + const guint32 len); -typedef gboolean (*validate_func)(const struct Opt *, const char *); +static gboolean validate_type_bytes (const struct Opt * opt, + const char * value, + const guint32 len); + +static gboolean validate_type_keyword (const struct Opt * opt, + const char * value, + const guint32 len); + +typedef gboolean (*validate_func)(const struct Opt *, const char *, const guint32); struct validate_entry { - const enum OptType type; + const OptType type; const validate_func func; }; static const struct validate_entry validate_table[] = { - { TYPE_INT, validate_type_int }, - { TYPE_STRING, validate_type_string }, + { TYPE_INT, validate_type_int }, + { TYPE_BYTES, validate_type_bytes }, { TYPE_KEYWORD, validate_type_keyword }, }; @@ -76,49 +78,51 @@ const char * phase2_allowed[] = {"auth=MSCHAPV2", "auth=PAP", "autheap=TLS", "autheap=MSCHAPV2", "autheap=MD5", NULL }; static const struct Opt opt_table[] = { - { "ssid", TYPE_STRING, 0, 0, FALSE, NULL }, - { "bssid", TYPE_STRING, 0, 0, FALSE, NULL }, + { "ssid", TYPE_BYTES, 0, 32,FALSE, NULL }, + { "bssid", TYPE_BYTES, 0, 6, FALSE, NULL }, { "scan_ssid", TYPE_INT, 0, 1, FALSE, NULL }, { "mode", TYPE_INT, 0, 1, FALSE, NULL }, { "auth_alg", TYPE_KEYWORD, 0, 0, FALSE, auth_alg_allowed }, - { "psk", TYPE_STRING, 0, 0, FALSE, NULL }, + { "psk", TYPE_BYTES, 0, 0, FALSE, NULL }, { "pairwise", TYPE_KEYWORD, 0, 0, FALSE, pairwise_allowed }, { "group", TYPE_KEYWORD, 0, 0, FALSE, group_allowed }, { "proto", TYPE_KEYWORD, 0, 0, FALSE, proto_allowed }, { "key_mgmt", TYPE_KEYWORD, 0, 0, FALSE, key_mgmt_allowed }, - { "wep_key0", TYPE_STRING, 0, 0, FALSE, NULL }, - { "wep_key1", TYPE_STRING, 0, 0, FALSE, NULL }, - { "wep_key2", TYPE_STRING, 0, 0, FALSE, NULL }, - { "wep_key3", TYPE_STRING, 0, 0, FALSE, NULL }, + { "wep_key0", TYPE_BYTES, 0, 0, FALSE, NULL }, + { "wep_key1", TYPE_BYTES, 0, 0, FALSE, NULL }, + { "wep_key2", TYPE_BYTES, 0, 0, FALSE, NULL }, + { "wep_key3", TYPE_BYTES, 0, 0, FALSE, NULL }, { "wep_tx_keyidx", TYPE_INT, 0, 3, FALSE, NULL }, { "eapol_flags", TYPE_INT, 0, 3, FALSE, NULL }, { "eap", TYPE_KEYWORD, 0, 0, FALSE, eap_allowed }, - { "identity", TYPE_STRING, 0, 0, FALSE, NULL }, - { "password", TYPE_STRING, 0, 0, FALSE, NULL }, - { "ca_cert", TYPE_STRING, 0, 0, FALSE, NULL }, - { "client_cert", TYPE_STRING, 0, 0, FALSE, NULL }, - { "private_key", TYPE_STRING, 0, 0, FALSE, NULL }, - { "private_key_passwd", TYPE_STRING, 0, 0, FALSE, NULL }, + { "identity", TYPE_BYTES, 0, 0, FALSE, NULL }, + { "password", TYPE_BYTES, 0, 0, FALSE, NULL }, + { "ca_cert", TYPE_BYTES, 0, 0, FALSE, NULL }, + { "client_cert", TYPE_BYTES, 0, 0, FALSE, NULL }, + { "private_key", TYPE_BYTES, 0, 0, FALSE, NULL }, + { "private_key_passwd", TYPE_BYTES, 0, 0, FALSE, NULL }, { "phase1", TYPE_KEYWORD, 0, 0, TRUE, phase1_allowed }, { "phase2", TYPE_KEYWORD, 0, 0, TRUE, phase2_allowed }, - { "anonymous_identity", TYPE_STRING, 0, 0, FALSE, NULL }, - { "ca_cert2", TYPE_STRING, 0, 0, FALSE, NULL }, - { "client_cert2", TYPE_STRING, 0, 0, FALSE, NULL }, - { "private_key2", TYPE_STRING, 0, 0, FALSE, NULL }, - { "private_key2_passwd",TYPE_STRING, 0, 0, FALSE, NULL }, - { "pin", TYPE_STRING, 0, 0, FALSE, NULL }, - { "pcsc", TYPE_STRING, 0, 0, FALSE, NULL }, - { "nai", TYPE_STRING, 0, 0, FALSE, NULL }, - { "eappsk", TYPE_STRING, 0, 0, FALSE, NULL }, - { "pac_file", TYPE_STRING, 0, 0, FALSE, NULL }, + { "anonymous_identity", TYPE_BYTES, 0, 0, FALSE, NULL }, + { "ca_cert2", TYPE_BYTES, 0, 0, FALSE, NULL }, + { "client_cert2", TYPE_BYTES, 0, 0, FALSE, NULL }, + { "private_key2", TYPE_BYTES, 0, 0, FALSE, NULL }, + { "private_key2_passwd",TYPE_BYTES, 0, 0, FALSE, NULL }, + { "pin", TYPE_BYTES, 0, 0, FALSE, NULL }, + { "pcsc", TYPE_BYTES, 0, 0, FALSE, NULL }, + { "nai", TYPE_BYTES, 0, 0, FALSE, NULL }, + { "eappsk", TYPE_BYTES, 0, 0, FALSE, NULL }, + { "pac_file", TYPE_BYTES, 0, 0, FALSE, NULL }, { "engine", TYPE_INT, 0, 1, FALSE, NULL }, - { "engine_id", TYPE_STRING, 0, 0, FALSE, NULL }, - { "key_id", TYPE_STRING, 0, 0, FALSE, NULL }, + { "engine_id", TYPE_BYTES, 0, 0, FALSE, NULL }, + { "key_id", TYPE_BYTES, 0, 0, FALSE, NULL }, }; static gboolean -validate_type_int (const struct Opt * opt, const char * value) +validate_type_int (const struct Opt * opt, + const char * value, + const guint32 len) { long int intval; @@ -140,20 +144,26 @@ validate_type_int (const struct Opt * opt, const char * value) } static gboolean -validate_type_string (const struct Opt * opt, const char * value) +validate_type_bytes (const struct Opt * opt, + const char * value, + const guint32 len) { + guint32 check_len; + g_return_val_if_fail (opt != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); - /* FIXME: what can we do with a string other than length? */ - if (strlen (value) > PATH_MAX) + check_len = opt->int_high ? opt->int_high : 255; + if (len > check_len) return FALSE; return TRUE; } static gboolean -validate_type_keyword (const struct Opt * opt, const char * value) +validate_type_keyword (const struct Opt * opt, + const char * value, + const guint32 len) { char ** allowed; gchar ** candidates = NULL; @@ -168,7 +178,8 @@ validate_type_keyword (const struct Opt * opt, const char * value) goto out; /* validate each space-separated word in 'value' */ - for (candidate = candidates; *candidate; candidate++, found = FALSE) { + for (candidate = candidates; *candidate; candidate++) { + found = FALSE; for (allowed = (char **) opt->str_allowed; *allowed; allowed++) { if (strcmp (*candidate, *allowed) == 0) { found = TRUE; @@ -184,11 +195,12 @@ out: return found; } -gboolean +OptType nm_supplicant_settings_verify_setting (const char * key, - const char * value) + const char * value, + const guint32 len) { - gboolean valid = FALSE; + OptType type = TYPE_INVALID; int opt_count = sizeof (opt_table) / sizeof (opt_table[0]); int val_count = sizeof (validate_table) / sizeof (validate_table[0]); int i, j; @@ -196,17 +208,20 @@ nm_supplicant_settings_verify_setting (const char * key, g_return_val_if_fail (key != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); - for (i = 0; i < opt_count && !valid; i++) { + for (i = 0; i < opt_count; i++) { if (strcmp (opt_table[i].key, key) != 0) continue; for (j = 0; j < val_count; j++) { if (validate_table[j].type == opt_table[i].type) { - valid = (*(validate_table[j].func))(&opt_table[i], value); - break; + if ((*(validate_table[j].func))(&opt_table[i], value, len)) { + type = opt_table[i].type; + break; + } } } } - return valid; + return type; } + diff --git a/src/supplicant-manager/nm-supplicant-settings-verify.h b/src/supplicant-manager/nm-supplicant-settings-verify.h index 8211789f86..2d7a967b02 100644 --- a/src/supplicant-manager/nm-supplicant-settings-verify.h +++ b/src/supplicant-manager/nm-supplicant-settings-verify.h @@ -22,10 +22,16 @@ #ifndef NM_SUPPLICANT_SETTINGS_VERIFY_H #define NM_SUPPLICANT_SETTINGS_VERIFY_H -gboolean nm_supplicant_settings_verify_setting (const char * key, - const char * value); - +typedef enum OptType { + TYPE_INVALID = 0, + TYPE_INT, + TYPE_BYTES, + TYPE_KEYWORD +} OptType; +OptType nm_supplicant_settings_verify_setting (const char * key, + const char * value, + const guint32 len); #endif /* NM_SUPPLICANT_SETTINGS_VERIFY_H */ diff --git a/src/wpa_ctrl.c b/src/wpa_ctrl.c deleted file mode 100644 index f8e55e86d7..0000000000 --- a/src/wpa_ctrl.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * wpa_supplicant/hostapd control interface library - * Copyright (c) 2004-2005, Jouni Malinen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - */ - -/* WHACK #include "includes.h" */ -#include -#include -#include -#include - -#define CONFIG_CTRL_IFACE -#ifdef CONFIG_CTRL_IFACE - -#ifndef CONFIG_CTRL_IFACE_UDP -#include -#endif /* CONFIG_CTRL_IFACE_UDP */ - -#include "wpa_ctrl.h" -/* WHACK #include "common.h" */ - -/** - * struct wpa_ctrl - Internal structure for control interface library - * - * This structure is used by the wpa_supplicant/hostapd control interface - * library to store internal data. Programs using the library should not touch - * this data directly. They can only use the pointer to the data structure as - * an identifier for the control interface connection and use this as one of - * the arguments for most of the control interface library functions. - */ -struct wpa_ctrl { - int s; -#ifdef CONFIG_CTRL_IFACE_UDP - struct sockaddr_in local; - struct sockaddr_in dest; -#else /* CONFIG_CTRL_IFACE_UDP */ - struct sockaddr_un local; - struct sockaddr_un dest; -#endif /* CONFIG_CTRL_IFACE_UDP */ -}; - - -struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path, - const char *local_path_dir) -{ - struct wpa_ctrl *ctrl; -#ifndef CONFIG_CTRL_IFACE_UDP - static int counter = 0; -#endif /* CONFIG_CTRL_IFACE_UDP */ - - ctrl = malloc(sizeof(*ctrl)); - if (ctrl == NULL) - return NULL; - memset(ctrl, 0, sizeof(*ctrl)); - -#ifdef CONFIG_CTRL_IFACE_UDP - ctrl->s = socket(PF_INET, SOCK_DGRAM, 0); - if (ctrl->s < 0) { - perror("socket"); - free(ctrl); - return NULL; - } - - ctrl->local.sin_family = AF_INET; - ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1); - if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, - sizeof(ctrl->local)) < 0) { - close(ctrl->s); - free(ctrl); - return NULL; - } - - ctrl->dest.sin_family = AF_INET; - ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1); - ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT); - if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, - sizeof(ctrl->dest)) < 0) { - perror("connect"); - close(ctrl->s); - free(ctrl); - return NULL; - } -#else /* CONFIG_CTRL_IFACE_UDP */ - ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0); - if (ctrl->s < 0) { - free(ctrl); - return NULL; - } - - ctrl->local.sun_family = AF_UNIX; - snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path), - "%s/wpa_ctrl_%d-%d", local_path_dir, getpid(), counter++); - if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, - sizeof(ctrl->local)) < 0) { - close(ctrl->s); - free(ctrl); - return NULL; - } - - ctrl->dest.sun_family = AF_UNIX; - snprintf(ctrl->dest.sun_path, sizeof(ctrl->dest.sun_path), "%s", - ctrl_path); - if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, - sizeof(ctrl->dest)) < 0) { - close(ctrl->s); - unlink(ctrl->local.sun_path); - free(ctrl); - return NULL; - } -#endif /* CONFIG_CTRL_IFACE_UDP */ - - return ctrl; -} - - -void wpa_ctrl_close(struct wpa_ctrl *ctrl) -{ -#ifndef CONFIG_CTRL_IFACE_UDP - unlink(ctrl->local.sun_path); -#endif /* CONFIG_CTRL_IFACE_UDP */ - close(ctrl->s); - free(ctrl); -} - - -int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, - char *reply, size_t *reply_len, - void (*msg_cb)(char *msg, size_t len)) -{ - struct timeval tv; - int res; - fd_set rfds; - - if (send(ctrl->s, cmd, cmd_len, 0) < 0) - return -1; - - for (;;) { - tv.tv_sec = 2; - tv.tv_usec = 0; - FD_ZERO(&rfds); - FD_SET(ctrl->s, &rfds); - res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); - if (FD_ISSET(ctrl->s, &rfds)) { - res = recv(ctrl->s, reply, *reply_len, 0); - if (res < 0) - return res; - if (res > 0 && reply[0] == '<') { - /* This is an unsolicited message from - * wpa_supplicant, not the reply to the - * request. Use msg_cb to report this to the - * caller. */ - if (msg_cb) { - /* Make sure the message is nul - * terminated. */ - if ((size_t) res == *reply_len) - res = (*reply_len) - 1; - reply[res] = '\0'; - msg_cb(reply, res); - } - continue; - } - *reply_len = res; - break; - } else { - return -2; - } - } - return 0; -} - - -static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach) -{ - char buf[10]; - int ret; - size_t len = 10; - - ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6, - buf, &len, NULL); - if (ret < 0) - return ret; - if (len == 3 && memcmp(buf, "OK\n", 3) == 0) - return 0; - return -1; -} - - -int wpa_ctrl_attach(struct wpa_ctrl *ctrl) -{ - return wpa_ctrl_attach_helper(ctrl, 1); -} - - -int wpa_ctrl_detach(struct wpa_ctrl *ctrl) -{ - return wpa_ctrl_attach_helper(ctrl, 0); -} - - -int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len) -{ - int res; - - res = recv(ctrl->s, reply, *reply_len, 0); - if (res < 0) - return res; - *reply_len = res; - return 0; -} - - -int wpa_ctrl_pending(struct wpa_ctrl *ctrl) -{ - struct timeval tv; - int res; - fd_set rfds; - tv.tv_sec = 0; - tv.tv_usec = 0; - FD_ZERO(&rfds); - FD_SET(ctrl->s, &rfds); - res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); - return FD_ISSET(ctrl->s, &rfds); -} - - -int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl) -{ - return ctrl->s; -} - -#endif /* CONFIG_CTRL_IFACE */ diff --git a/src/wpa_ctrl.h b/src/wpa_ctrl.h deleted file mode 100644 index 719ecc5700..0000000000 --- a/src/wpa_ctrl.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * wpa_supplicant/hostapd control interface library - * Copyright (c) 2004-2005, Jouni Malinen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - */ - -#ifndef WPA_CTRL_H -#define WPA_CTRL_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* wpa_supplicant control interface - fixed message prefixes */ - -/** Interactive request for identity/password/pin */ -#define WPA_CTRL_REQ "CTRL-REQ-" - -/** Response to identity/password/pin request */ -#define WPA_CTRL_RSP "CTRL-RSP-" - -/* Event messages with fixed prefix */ -/** Authentication completed successfully and data connection enabled */ -#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED " -/** Disconnected, data connection is not available */ -#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED " -/** wpa_supplicant is exiting */ -#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING " -/** Password change was completed successfully */ -#define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED " -/** EAP-Request/Notification received */ -#define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION " -/** EAP authentication started (EAP-Request/Identity received) */ -#define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED " -/** EAP method selected */ -#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD " -/** EAP authentication completed successfully */ -#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS " -/** EAP authentication failed (EAP-Failure received) */ -#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE " - - -/* wpa_supplicant/hostapd control interface access */ - -/** - * wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd - * @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used. - * Returns: Pointer to abstract control interface data or %NULL on failure - * - * This function is used to open a control interface to wpa_supplicant/hostapd. - * ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd. This path - * is configured in wpa_supplicant/hostapd and other programs using the control - * interface need to use matching path configuration. - */ -struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path, const char *local_path_dir); - - -/** - * wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd - * @ctrl: Control interface data from wpa_ctrl_open() - * - * This function is used to close a control interface. - */ -void wpa_ctrl_close(struct wpa_ctrl *ctrl); - - -/** - * wpa_ctrl_request - Send a command to wpa_supplicant/hostapd - * @ctrl: Control interface data from wpa_ctrl_open() - * @cmd: Command; usually, ASCII text, e.g., "PING" - * @cmd_len: Length of the cmd in bytes - * @reply: Buffer for the response - * @reply_len: Reply buffer length - * @msg_cb: Callback function for unsolicited messages or %NULL if not used - * Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout - * - * This function is used to send commands to wpa_supplicant/hostapd. Received - * response will be written to reply and reply_len is set to the actual length - * of the reply. This function will block for up to two seconds while waiting - * for the reply. If unsolicited messages are received, the blocking time may - * be longer. - * - * msg_cb can be used to register a callback function that will be called for - * unsolicited messages received while waiting for the command response. These - * messages may be received if wpa_ctrl_request() is called at the same time as - * wpa_supplicant/hostapd is sending such a message. This can happen only if - * the program has used wpa_ctrl_attach() to register itself as a monitor for - * event messages. Alternatively to msg_cb, programs can register two control - * interface connections and use one of them for commands and the other one for - * receiving event messages, in other words, call wpa_ctrl_attach() only for - * the control interface connection that will be used for event messages. - */ -int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, - char *reply, size_t *reply_len, - void (*msg_cb)(char *msg, size_t len)); - - -/** - * wpa_ctrl_attach - Register as an event monitor for the control interface - * @ctrl: Control interface data from wpa_ctrl_open() - * Returns: 0 on success, -1 on failure, -2 on timeout - * - * This function registers the control interface connection as a monitor for - * wpa_supplicant/hostapd events. After a success wpa_ctrl_attach() call, the - * control interface connection starts receiving event messages that can be - * read with wpa_ctrl_recv(). - */ -int wpa_ctrl_attach(struct wpa_ctrl *ctrl); - - -/** - * wpa_ctrl_detach - Unregister event monitor from the control interface - * @ctrl: Control interface data from wpa_ctrl_open() - * Returns: 0 on success, -1 on failure, -2 on timeout - * - * This function unregisters the control interface connection as a monitor for - * wpa_supplicant/hostapd events, i.e., cancels the registration done with - * wpa_ctrl_attach(). - */ -int wpa_ctrl_detach(struct wpa_ctrl *ctrl); - - -/** - * wpa_ctrl_recv - Receive a pending control interface message - * @ctrl: Control interface data from wpa_ctrl_open() - * @reply: Buffer for the message data - * @reply_len: Length of the reply buffer - * Returns: 0 on success, -1 on failure - * - * This function will receive a pending control interface message. This - * function will block if no messages are available. The received response will - * be written to reply and reply_len is set to the actual length of the reply. - * wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach() - * must have been used to register the control interface as an event monitor. - */ -int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len); - - -/** - * wpa_ctrl_pending - Check whether there are pending event messages - * @ctrl: Control interface data from wpa_ctrl_open() - * Returns: Non-zero if there are pending messages - * - * This function will check whether there are any pending control interface - * message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is - * only used for event messages, i.e., wpa_ctrl_attach() must have been used to - * register the control interface as an event monitor. - */ -int wpa_ctrl_pending(struct wpa_ctrl *ctrl); - - -/** - * wpa_ctrl_get_fd - Get file descriptor used by the control interface - * @ctrl: Control interface data from wpa_ctrl_open() - * Returns: File descriptor used for the connection - * - * This function can be used to get the file descriptor that is used for the - * control interface connection. The returned value can be used, e.g., with - * select() while waiting for multiple events. - * - * The returned file descriptor must not be used directly for sending or - * receiving packets; instead, the library functions wpa_ctrl_request() and - * wpa_ctrl_recv() must be used for this. - */ -int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl); - -#ifdef CONFIG_CTRL_IFACE_UDP -#define WPA_CTRL_IFACE_PORT 9877 -#define WPA_GLOBAL_CTRL_IFACE_PORT 9878 -#endif /* CONFIG_CTRL_IFACE_UDP */ - - -#ifdef __cplusplus -} -#endif - -#endif /* WPA_CTRL_H */