diff --git a/ChangeLog b/ChangeLog index 83147b49d..816efbe9f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,32 @@ +2006-01-04 Dan Williams + + First dump of wpa_supplicant-related code. It's not hooked up to + anything yet though. Thanks to Kay Sievers for + wpa_supplicant_wrapper.c, which formed the basis for this work, + and to Jouni Malinen for writing wpa_ctrl.c and wpa_ctrl.h. + + * src/Makefile.am + src/wpa_ctrl.[ch] + - Add wpa_ctrl stuff from wpa_supplicant so we can talk to it + + * src/NetworkManagerUtils.[ch] + - (nm_utils_supplicant_request, nm_utils_supplicant_request_with_check): + Add convenience functions for talking to wpa_supplicant + + * src/nm-ap-security.[ch] + src/nm-ap-security-wep.c + src/nm-ap-security-wpa-psk.[ch] + - Update and implement real_write_supplicant_config functions + in all security types + - (nm_ap_security_wpa_psk_new_from_ap): implement in + nm-ap-security-wpa-psk.c + + * src/nm-device-802-11-wireless.c + - (supplicant_cleanup, supplicant_watch_cb, supplicant_monitor_status_cb, + wpa_supplicant_start, wpa_supplicant_interface_init, + wpa_supplicant_send_network_config): add functions to talk to + wpa_supplicant and write network config to it + 2006-01-04 Robert Love * src/NetworkManagerDialup.h: add 'type' field and NM_DIALUP_TYPE diff --git a/src/Makefile.am b/src/Makefile.am index 0c8a5a198..eb69a6c8c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -59,7 +59,9 @@ NetworkManager_SOURCES = \ nm-ap-security-wpa-psk.c \ nm-ap-security-wpa-psk.h \ wpa.c \ - wpa.h + wpa.h \ + wpa_ctrl.c \ + wpa_ctrl.h NetworkManager_CPPFLAGS = \ $(DBUS_CFLAGS) \ diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 79ecf8dff..ed9523b3b 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -39,6 +39,7 @@ #include "nm-device.h" #include "nm-device-802-11-wireless.h" #include "nm-device-802-3-ethernet.h" +#include "wpa_ctrl.h" #include #include @@ -698,3 +699,84 @@ int nm_utils_ip4_netmask_to_prefix (guint32 ip4_netmask) return (32 - (i-1)); } + +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 (2048); + wpa_ctrl_request (ctrl, command, strlen (command), response, &len, NULL); + g_free (command); + response[len] = '\0'; + 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 (2048); + wpa_ctrl_request (ctrl, command, strlen (command), response, &len, NULL); + response[len] = '\0'; + + if (response) + { + if (strncmp (response, expected, strlen (expected)) == 0) + success = TRUE; + else + { + 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 0ab55baeb..be9380438 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -106,4 +106,15 @@ 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-wep.c b/src/nm-ap-security-wep.c index 514639dbc..f84016e3b 100644 --- a/src/nm-ap-security-wep.c +++ b/src/nm-ap-security-wep.c @@ -29,6 +29,8 @@ #include "nm-ap-security-private.h" #include "dbus-helpers.h" #include "nm-device-802-11-wireless.h" +#include "nm-utils.h" +#include "NetworkManagerUtils.h" #define NM_AP_SECURITY_WEP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AP_SECURITY_WEP, NMAPSecurityWEPPrivate)) @@ -105,10 +107,38 @@ real_serialize (NMAPSecurity *instance, DBusMessageIter *iter) return 0; } -static void -real_write_wpa_supplicant_config (NMAPSecurity *instance, int fd) +static gboolean +real_write_supplicant_config (NMAPSecurity *instance, + struct wpa_ctrl *ctrl, + int nwid) { - NMAPSecurityWEP * self = NM_AP_SECURITY_WEP (instance); + NMAPSecurityWEP * self = NM_AP_SECURITY_WEP (instance); + gboolean success = FALSE; + char * msg = NULL; + const char * key = nm_ap_security_get_key (instance); + + /* WEP network setup */ + if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, + "SET_NETWORK %i key_mgmt NONE", nwid)) + 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); + goto out; + } + g_free (msg); + + if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, + "SET_NETWORK %i wep_tx_keyidx 0", nwid)) + goto out; + + success = TRUE; + +out: + return success; } static int @@ -147,7 +177,7 @@ nm_ap_security_wep_class_init (NMAPSecurityWEPClass *klass) par_class->copy_constructor_func = real_copy_constructor; par_class->serialize_func = real_serialize; - par_class->write_wpa_supplicant_config_func = real_write_wpa_supplicant_config; + par_class->write_supplicant_config_func = real_write_supplicant_config; par_class->device_setup_func = real_device_setup; g_type_class_add_private (object_class, sizeof (NMAPSecurityWEPPrivate)); diff --git a/src/nm-ap-security-wpa-psk.c b/src/nm-ap-security-wpa-psk.c index ba01a4161..762b62659 100644 --- a/src/nm-ap-security-wpa-psk.c +++ b/src/nm-ap-security-wpa-psk.c @@ -29,6 +29,7 @@ #include "nm-ap-security-private.h" #include "dbus-helpers.h" #include "nm-device-802-11-wireless.h" +#include "NetworkManagerUtils.h" #define NM_AP_SECURITY_WPA_PSK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AP_SECURITY_WPA_PSK, NMAPSecurityWPA_PSKPrivate)) @@ -38,6 +39,16 @@ struct _NMAPSecurityWPA_PSKPrivate int key_mgt; }; +static void set_description (NMAPSecurityWPA_PSK *security) +{ + NMAPSecurity * parent = NM_AP_SECURITY (security); + + if (nm_ap_security_get_we_cipher (parent) == IW_AUTH_CIPHER_TKIP) + nm_ap_security_set_description (parent, _("WPA TKIP")); + else + nm_ap_security_set_description (parent, _("WPA CCMP")); +} + NMAPSecurityWPA_PSK * nm_ap_security_wpa_psk_new_deserialize (DBusMessageIter *iter, int we_cipher) { @@ -61,15 +72,36 @@ nm_ap_security_wpa_psk_new_deserialize (DBusMessageIter *iter, int we_cipher) security->priv->wpa_version = wpa_version; security->priv->key_mgt = key_mgt; - if (we_cipher == IW_AUTH_CIPHER_TKIP) - nm_ap_security_set_description (NM_AP_SECURITY (security), _("WPA TKIP")); - else - nm_ap_security_set_description (NM_AP_SECURITY (security), _("WPA CCMP")); + set_description (security); out: return security; } +NMAPSecurityWPA_PSK * +nm_ap_security_wpa_psk_new_from_ap (NMAccessPoint *ap, int we_cipher) +{ + NMAPSecurityWPA_PSK * security = NULL; + guint32 caps; + + g_return_val_if_fail (ap != NULL, NULL); + g_return_val_if_fail (we_cipher == IW_AUTH_CIPHER_TKIP || (we_cipher == IW_AUTH_CIPHER_CCMP), NULL); + + security = g_object_new (NM_TYPE_AP_SECURITY_WPA_PSK, NULL); + nm_ap_security_set_we_cipher (NM_AP_SECURITY (security), we_cipher); + + caps = nm_ap_get_capabilities (ap); + if (caps & NM_802_11_CAP_PROTO_WPA2) + security->priv->wpa_version = IW_AUTH_WPA_VERSION_WPA2; + else if (caps & NM_802_11_CAP_PROTO_WPA) + security->priv->wpa_version = IW_AUTH_WPA_VERSION_WPA; + security->priv->key_mgt = IW_AUTH_KEY_MGMT_PSK; + + set_description (security); + + return security; +} + static int real_serialize (NMAPSecurity *instance, DBusMessageIter *iter) { @@ -83,10 +115,71 @@ real_serialize (NMAPSecurity *instance, DBusMessageIter *iter) return 0; } -static void -real_write_wpa_supplicant_config (NMAPSecurity *instance, int fd) +static gboolean +real_write_supplicant_config (NMAPSecurity *instance, + struct wpa_ctrl *ctrl, + int nwid) { 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); + + /* WPA-PSK network setup */ + + /* wpa_cli -ieth1 set_network 0 key_mgmt WPA-PSK */ + if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, + "SET_NETWORK %i key_mgmt WPA-PSK", nwid)) + 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); + goto out; + } + g_free (msg); + + if (cipher == IW_AUTH_CIPHER_TKIP) + { + if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, + "SET_NETWORK %i pairwise TKIP", nwid)) + goto out; + + if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, + "SET_NETWORK %i group TKIP", nwid)) + goto out; + } + else + { + if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, + "SET_NETWORK %i pairwise CCMP", nwid)) + goto out; + + if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, + "SET_NETWORK %i group CCMP", nwid)) + goto out; + } + + 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)) + 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)) + goto out; + } + + success = TRUE; + +out: + return success; } static int @@ -124,7 +217,7 @@ nm_ap_security_wpa_psk_class_init (NMAPSecurityWPA_PSKClass *klass) par_class->copy_constructor_func = real_copy_constructor; par_class->serialize_func = real_serialize; - par_class->write_wpa_supplicant_config_func = real_write_wpa_supplicant_config; + par_class->write_supplicant_config_func = real_write_supplicant_config; par_class->device_setup_func = real_device_setup; g_type_class_add_private (object_class, sizeof (NMAPSecurityWPA_PSKPrivate)); diff --git a/src/nm-ap-security-wpa-psk.h b/src/nm-ap-security-wpa-psk.h index f8c146e27..005d0ac6a 100644 --- a/src/nm-ap-security-wpa-psk.h +++ b/src/nm-ap-security-wpa-psk.h @@ -55,4 +55,7 @@ GType nm_ap_security_wpa_psk_get_type (void); NMAPSecurityWPA_PSK * nm_ap_security_wpa_psk_new_deserialize (DBusMessageIter *iter, int we_cipher); +struct NMAccessPoint; +NMAPSecurityWPA_PSK * nm_ap_security_wpa_psk_new_from_ap (struct NMAccessPoint *ap, int we_cipher); + #endif /* NM_AP_SECURITY_WPA_PSK_H */ diff --git a/src/nm-ap-security.c b/src/nm-ap-security.c index 66e92bac1..634c87be4 100644 --- a/src/nm-ap-security.c +++ b/src/nm-ap-security.c @@ -29,6 +29,9 @@ #include "nm-ap-security-wep.h" #include "nm-ap-security-wpa-psk.h" #include "nm-device-802-11-wireless.h" +#include "wpa_ctrl.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)) @@ -112,17 +115,11 @@ nm_ap_security_new_from_ap (NMAccessPoint *ap) /* Deteremine best encryption algorithm to use */ caps = nm_ap_get_capabilities (ap); - -/* if (caps & WPA2_CCMP_PSK) - stuff - else if (caps & WPA2_TKIP_PSK) - stuff - else if (caps & WPA_TKIP_PSK) - stuff - else -*/ - if (caps & WEP_WEP104) + security = NM_AP_SECURITY (nm_ap_security_wpa_psk_new_from_ap (ap, IW_AUTH_CIPHER_CCMP)); + else if ((caps & WPA_TKIP_PSK) || (caps & WPA2_TKIP_PSK)) + security = NM_AP_SECURITY (nm_ap_security_wpa_psk_new_from_ap (ap, IW_AUTH_CIPHER_TKIP)); + else if (caps & WEP_WEP104) security = NM_AP_SECURITY (nm_ap_security_wep_new_from_ap (ap, IW_AUTH_CIPHER_WEP104)); else if (caps & WEP_WEP40) security = NM_AP_SECURITY (nm_ap_security_wep_new_from_ap (ap, IW_AUTH_CIPHER_WEP40)); @@ -132,16 +129,20 @@ nm_ap_security_new_from_ap (NMAccessPoint *ap) return security; } -void -nm_ap_security_write_wpa_supplicant_config (NMAPSecurity *self, int fd) + +gboolean +nm_ap_security_write_supplicant_config (NMAPSecurity *self, + struct wpa_ctrl *ctrl, + int nwid) { - g_return_if_fail (self != NULL); - g_return_if_fail (fd >= 0); + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (ctrl != NULL, FALSE); + g_return_val_if_fail (nwid >= 0, FALSE); if (self->priv->dispose_has_run) - return; + return FALSE; - NM_AP_SECURITY_GET_CLASS (self)->write_wpa_supplicant_config_func (self, fd); + return NM_AP_SECURITY_GET_CLASS (self)->write_supplicant_config_func (self, ctrl, nwid); } void @@ -189,9 +190,17 @@ real_serialize (NMAPSecurity *self, DBusMessageIter *iter) return 0; } -static void -real_write_wpa_supplicant_config (NMAPSecurity *self, int fd) +static gboolean +real_write_supplicant_config (NMAPSecurity *self, + struct wpa_ctrl *ctrl, + int nwid) { + /* Unencrypted network setup */ + if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, + "SET_NETWORK %i key_mgmt NONE", nwid)) + return FALSE; + + return TRUE; } static int @@ -352,7 +361,7 @@ nm_ap_security_class_init (NMAPSecurityClass *klass) klass->copy_constructor_func = real_copy_constructor; klass->serialize_func = real_serialize; - klass->write_wpa_supplicant_config_func = real_write_wpa_supplicant_config; + klass->write_supplicant_config_func = real_write_supplicant_config; klass->device_setup_func = real_device_setup; g_type_class_add_private (object_class, sizeof (NMAPSecurityPrivate)); diff --git a/src/nm-ap-security.h b/src/nm-ap-security.h index dbfb8224d..f9fd53fab 100644 --- a/src/nm-ap-security.h +++ b/src/nm-ap-security.h @@ -53,6 +53,7 @@ struct _NMAPSecurity }; struct NMAccessPoint; +struct wpa_ctrl; struct _NMAPSecurityClass { @@ -63,7 +64,7 @@ struct _NMAPSecurityClass int (*serialize_func) (NMAPSecurity *self, DBusMessageIter *iter); - void (*write_wpa_supplicant_config_func)(NMAPSecurity *self, int fd); + gboolean (*write_supplicant_config_func)(NMAPSecurity *self, struct wpa_ctrl *ctrl, int nwid); int (*device_setup_func) (NMAPSecurity *self, NMDevice80211Wireless * dev); }; @@ -83,7 +84,7 @@ const char * nm_ap_security_get_key (NMAPSecurity *self); int nm_ap_security_serialize (NMAPSecurity *self, DBusMessageIter *iter); -void nm_ap_security_write_wpa_supplicant_config (NMAPSecurity *self, int fd); +gboolean nm_ap_security_write_supplicant_config (NMAPSecurity *self, struct wpa_ctrl *ctrl, int nwid); int nm_ap_security_device_setup (NMAPSecurity *self, NMDevice80211Wireless *dev); diff --git a/src/nm-device-802-11-wireless.c b/src/nm-device-802-11-wireless.c index 0663401fa..ea51c010d 100644 --- a/src/nm-device-802-11-wireless.c +++ b/src/nm-device-802-11-wireless.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include "nm-device.h" #include "nm-device-802-11-wireless.h" @@ -37,6 +39,7 @@ #include "NetworkManagerPolicy.h" #include "nm-activation-request.h" #include "nm-dbus-nmi.h" +#include "wpa_ctrl.h" /* #define IW_QUAL_DEBUG */ @@ -64,6 +67,12 @@ struct _NMDevice80211WirelessPrivate guint8 scan_interval; /* seconds */ guint32 last_scan; + /* Supplicant control */ + GPid sup_pid; + GSource * sup_watch; + GSource * sup_status; + struct wpa_ctrl * sup_ctrl; + /* Static options from driver */ guint8 we_version; guint32 capabilities; @@ -207,6 +216,7 @@ nm_device_802_11_wireless_init (NMDevice80211Wireless * self) self->priv->dispose_has_run = FALSE; memset (&(self->priv->hw_addr), 0, sizeof (struct ether_addr)); + self->priv->sup_pid = -1; } static void @@ -2335,6 +2345,224 @@ wireless_configure_infra (NMDevice80211Wireless *self, } +/****************************************************************************/ +/* 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. + */ + +#define WPA_SUPPLICANT_GLOBAL_SOCKET "/var/run/wpa_supplicant-global" +#define WPA_SUPPLICANT_CONTROL_SOCKET "/var/run/wpa_supplicant" +#define WPA_SUPPLICANT_BINARY "/usr/sbin/wpa_supplicant" + +static void +supplicant_cleanup (NMDevice80211Wireless *self) +{ + g_return_if_fail (self != NULL); + + self->priv->sup_pid = -1; + if (self->priv->sup_watch) + { + g_source_destroy (self->priv->sup_watch); + self->priv->sup_watch = NULL; + } + if (self->priv->sup_status) + { + g_source_destroy (self->priv->sup_status); + self->priv->sup_status = NULL; + } + if (self->priv->sup_ctrl) + { + wpa_ctrl_close (self->priv->sup_ctrl); + self->priv->sup_ctrl = NULL; + } +} + +static void +supplicant_watch_cb (GPid pid, + gint status, + gpointer 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); + + /* FIXME: deal with disconnection; device no longer has a link */ +} + +static gboolean +supplicant_monitor_status_cb (GIOChannel *source, + GIOCondition condition, + gpointer user_data) +{ + NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (user_data); + char message[2048]; + size_t message_len; + struct wpa_ctrl * ctrl; + + g_assert (self); + + ctrl = self->priv->sup_ctrl; + g_return_val_if_fail (ctrl != NULL, FALSE); + + message_len = sizeof (message); + wpa_ctrl_recv (ctrl, message, &message_len); + message[message_len] = '\0'; + if (strstr (message, WPA_EVENT_CONNECTED) != NULL) + printf("UP\n"); + else if (strstr (message, WPA_EVENT_DISCONNECTED) != NULL) + printf("DOWN\n"); + + return TRUE; +} + +static gboolean +wpa_supplicant_start (NMDevice80211Wireless *self) +{ + gboolean success = FALSE; + char * argv[4]; + GError * error; + GPid pid = -1; + + argv[0] = WPA_SUPPLICANT_BINARY; + argv[1] = "-g"; + argv[2] = WPA_SUPPLICANT_GLOBAL_SOCKET; + argv[4] = NULL; + + if (!(success = g_spawn_async ("/", argv, NULL, 0, NULL, NULL, &pid, &error))) + { + 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 + { + if (self->priv->sup_watch) + g_source_destroy (self->priv->sup_watch); + self->priv->sup_watch = g_child_watch_source_new (pid); + g_source_set_callback (self->priv->sup_watch, (GSourceFunc) supplicant_watch_cb, self, NULL); + g_source_attach (self->priv->sup_watch, nm_device_get_main_context (NM_DEVICE (self))); + } + + return success; +} + + +static gboolean +wpa_supplicant_interface_init (NMDevice80211Wireless *self) +{ + struct wpa_ctrl * ctrl; + struct wpa_ctrl * ctrl_if = NULL; + char * socket_path; + const char * iface = nm_device_get_iface (NM_DEVICE (self)); + gboolean success = FALSE; + + if (!(ctrl = wpa_ctrl_open (WPA_SUPPLICANT_GLOBAL_SOCKET))) + 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); + + /* attach to interface socket */ + if (!(socket_path = g_strdup_printf (WPA_SUPPLICANT_CONTROL_SOCKET "/%s", iface))) + goto exit; + self->priv->sup_ctrl = wpa_ctrl_open (socket_path); + g_free (socket_path); + success = TRUE; + +exit: + return success; +} + + +static gboolean +wpa_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; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (req != NULL, FALSE); + + ap = nm_act_request_get_ap (req); + g_assert (ap); + + ctrl = self->priv->sup_ctrl; + g_assert (ctrl); + + /* Standard network setup info */ + if (!(response = nm_utils_supplicant_request (ctrl, "ADD_NETWORK"))) + { + nm_warning ("Supplicant error for ADD_NETWORK.\n"); + goto out; + } + 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_essid (ap); + if (!nm_utils_supplicant_request_with_check (ctrl, "OK", __func__, NULL, + "SET_NETWORK %i ssid \"%s\"", nwid, essid)) + goto out; + + 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)) + 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 NMActStageReturn real_act_stage2_config (NMDevice *dev, NMActRequest *req) diff --git a/src/wpa_ctrl.c b/src/wpa_ctrl.c new file mode 100644 index 000000000..eb598c1fc --- /dev/null +++ b/src/wpa_ctrl.c @@ -0,0 +1,240 @@ +/* + * 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) +{ + 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), + "/tmp/wpa_ctrl_%d-%d", 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 new file mode 100644 index 000000000..c8fa48d69 --- /dev/null +++ b/src/wpa_ctrl.h @@ -0,0 +1,185 @@ +/* + * 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); + + +/** + * 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 */