NetworkManager r3238 - in branches/NETWORKMANAGER_0_6_0_RELEASE: . src



Author: tambeti
Date: Wed Jan 16 16:51:06 2008
New Revision: 3238
URL: http://svn.gnome.org/viewvc/NetworkManager?rev=3238&view=rev

Log:
2008-01-16  Tambet Ingo  <tambet gmail com>

        Shuffle the code a bit in preparation for wired 802.1X
authentication.

        * src/nm-device-802-11-wireless.c: Remove the supplicant driving
        * code and use
        NMSuppicant instead.

        * src/nm-supplicant.[ch]: New files. The wpa_supplicant driving
        * code is moved
        here from nm-device-802-11-wireless.c and refactored a bit so it
can be shared
        by wired cards as well.



Added:
   branches/NETWORKMANAGER_0_6_0_RELEASE/src/nm-supplicant.c
   branches/NETWORKMANAGER_0_6_0_RELEASE/src/nm-supplicant.h
Modified:
   branches/NETWORKMANAGER_0_6_0_RELEASE/ChangeLog
   branches/NETWORKMANAGER_0_6_0_RELEASE/src/Makefile.am
   branches/NETWORKMANAGER_0_6_0_RELEASE/src/nm-device-802-11-wireless.c

Modified: branches/NETWORKMANAGER_0_6_0_RELEASE/src/Makefile.am
==============================================================================
--- branches/NETWORKMANAGER_0_6_0_RELEASE/src/Makefile.am	(original)
+++ branches/NETWORKMANAGER_0_6_0_RELEASE/src/Makefile.am	Wed Jan 16 16:51:06 2008
@@ -64,6 +64,8 @@
 		nm-ap-security-wpa-psk.h		\
 		nm-ap-security-leap.c   		\
 		nm-ap-security-leap.h   		\
+		nm-supplicant.h				\
+		nm-supplicant.c				\
 		nm-marshal-main.c			\
 		kernel-types.h				\
 		wpa.c					\

Modified: branches/NETWORKMANAGER_0_6_0_RELEASE/src/nm-device-802-11-wireless.c
==============================================================================
--- branches/NETWORKMANAGER_0_6_0_RELEASE/src/nm-device-802-11-wireless.c	(original)
+++ branches/NETWORKMANAGER_0_6_0_RELEASE/src/nm-device-802-11-wireless.c	Wed Jan 16 16:51:06 2008
@@ -1,3 +1,5 @@
+/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
+
 /* NetworkManager -- Network link manager
  *
  * Dan Williams <dcbw redhat com>
@@ -35,6 +37,7 @@
 #include "nm-device-private.h"
 #include "NetworkManagerAPList.h"
 #include "NetworkManagerDbus.h"
+#include "nm-supplicant.h"
 #include "nm-utils.h"
 #include "NetworkManagerUtils.h"
 #include "NetworkManagerPolicy.h"
@@ -47,15 +50,6 @@
 
 #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;
-};
-
 struct _NMDevice80211WirelessPrivate
 {
 	gboolean	dispose_has_run;
@@ -77,7 +71,7 @@
 	GSource *			scan_timeout;
 	GSource *			pending_scan;
 
-	struct _Supplicant	supplicant;
+	NMSupplicant *supplicant;
 
 	guint32			failed_link_count;
 	GSource *			link_timeout;
@@ -127,8 +121,6 @@
 								 NMAccessPoint *ap,
 								 gboolean default_link);
 
-static void		supplicant_cleanup (NMDevice80211Wireless *self);
-
 static void		remove_link_timeout (NMDevice80211Wireless *self);
 
 static void		nm_device_802_11_wireless_set_wep_enc_key (NMDevice80211Wireless *self,
@@ -380,8 +372,6 @@
 	self->priv = NM_DEVICE_802_11_WIRELESS_GET_PRIVATE (self);
 	self->priv->dispose_has_run = FALSE;
 	self->priv->is_initialized = FALSE;
-
-	self->priv->supplicant.pid = -1;
 }
 
 
@@ -621,7 +611,7 @@
 	NMDevice80211Wireless *	self = NM_DEVICE_802_11_WIRELESS (dev);
 
 	/* If the supplicant isn't running, we can't possibly have a link */
-	if (!self->priv->supplicant.pid)
+	if (!self->priv->supplicant)
 		nm_device_set_active_link (NM_DEVICE (self), FALSE);
 }
 
@@ -681,7 +671,11 @@
 {
 	NMDevice80211Wireless *	self = NM_DEVICE_802_11_WIRELESS (dev);
 
-	supplicant_cleanup (self);
+	if (self->priv->supplicant) {
+		g_object_unref (self->priv->supplicant);
+		self->priv->supplicant = NULL;
+	}
+
 	remove_link_timeout (self);
 }
 
@@ -2155,11 +2149,11 @@
 	 * the scan request rather than doing it ourselves.
 	 */
 	iface = nm_device_get_iface (NM_DEVICE (self));
-	if (self->priv->supplicant.ctrl)
+	if (self->priv->supplicant)
 	{
-		if (nm_utils_supplicant_request_with_check (self->priv->supplicant.ctrl,
-				"OK", __func__, NULL, "SCAN"))
-			success = TRUE;
+	  if (nm_utils_supplicant_request_with_check (nm_supplicant_get_ctrl (self->priv->supplicant),
+						      "OK", __func__, NULL, "SCAN"))
+	    success = TRUE;
 	}
 	else
 	{
@@ -2409,442 +2403,7 @@
 	return auth_required;
 }
 
-
 /****************************************************************************/
-/* WPA Supplicant control stuff
- *
- * Originally from:
- *
- *	wpa_supplicant wrapper
- *
- *	Copyright (C) 2005 Kay Sievers <kay sievers vrfy org>
- *
- *	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		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
-
-
-static void
-remove_link_timeout (NMDevice80211Wireless *self)
-{
-	g_return_if_fail (self != 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;
-	}
-
-	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_done (gpointer user_data)
-{
-	NMDevice80211Wireless *device = NM_DEVICE_802_11_WIRELESS (user_data);
-
-	device->priv->supplicant.watch = NULL;
-}
-
-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);
-}
-
-
-static void
-link_timeout_done (gpointer user_data)
-{
-	NMDevice80211Wireless *device = NM_DEVICE_802_11_WIRELESS (user_data);
-
-	device->priv->link_timeout = NULL;
-}
-
-
-/*
- * link_timeout_cb
- *
- * Called when the link to the access point has been down for a specified
- * period of time.
- */
-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);
- 	NMData *				data = nm_device_get_app_data (dev);
- 	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 (data->dbus_connection, req, TRUE);
- 	}
- 	else
- 	{
- 		nm_info ("%s: link timed out.", nm_device_get_iface (dev));
- 		nm_device_set_active_link (dev, FALSE);
- 	}
-
-	return FALSE;
-}
-
-
-static void
-supplicant_status_done (gpointer user_data)
-{
-	NMDevice80211Wireless *device = NM_DEVICE_802_11_WIRELESS (user_data);
-
-	device->priv->supplicant.status = NULL;
-}
-
-
-#define MESSAGE_LEN	2048
-
-static gboolean
-supplicant_status_cb (GIOChannel *source,
-                      GIOCondition condition,
-                      gpointer user_data)
-{
-	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;
-
-	g_assert (self);
-
-	/* 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))
-		return TRUE;
-
-	ctrl = self->priv->supplicant.ctrl;
-	g_return_val_if_fail (ctrl != NULL, FALSE);
-
-	req = nm_device_get_act_request (NM_DEVICE (self));
-
-	message = g_malloc (MESSAGE_LEN);
-	len = MESSAGE_LEN;
-	wpa_ctrl_recv (ctrl, message, &len);
-	message[len] = '\0';
-
-	if (strstr (message, WPA_EVENT_CONNECTED) != NULL)
-	{
-		remove_link_timeout (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);
-
-			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);
-			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))
-		{
-			/* 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 (8000);
-				g_source_set_callback (self->priv->link_timeout,
-									   link_timeout_cb,
-									   self,
-									   link_timeout_done);
-				g_source_attach (self->priv->link_timeout, context);
-				g_source_unref (self->priv->link_timeout);
-			}
-		}
-		else
-		{
-			nm_device_set_active_link (dev, FALSE);
-		}
-	}
-
-	g_free (message);
-
-	return TRUE;
-}
-
-
-#define NM_SUPPLICANT_TIMEOUT	20	/* how long we wait for wpa_supplicant to associate (in seconds) */
-
-static unsigned int
-get_supplicant_timeout (NMDevice80211Wireless *self)
-{
-	if (self->priv->num_freqs > 14)
-		return NM_SUPPLICANT_TIMEOUT * 2;
-	return NM_SUPPLICANT_TIMEOUT;
-}
-
-
-static void
-supplicant_timeout_done (gpointer user_data)
-{
-	NMDevice80211Wireless *device = NM_DEVICE_802_11_WIRELESS (user_data);
-
-	device->priv->supplicant.timeout = NULL;
-}
-
-
-/*
- * supplicant_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)
-{
-	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);
-	NMData *	data = nm_device_get_app_data (dev);
-	gboolean	has_key;
-
-	g_assert (self);
-		
-	/* 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)
-	{
-		/* 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_dbus_get_user_key_for_network (data->dbus_connection, 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))
-			nm_policy_schedule_activation_failed (nm_device_get_act_request (dev));
-	}
-
-	return FALSE;
-}
-
-/*
- * supplicant_child_setup
- *
- * Set the process group ID of the newly forked process
- *
- */
-static void
-supplicant_child_setup (gpointer user_data G_GNUC_UNUSED)
-{
-	/* We are in the child process at this point */
-	pid_t pid = getpid ();
-	setpgid (pid, pid);
-}
-
-static gboolean
-supplicant_exec (NMDevice80211Wireless *self)
-{
-	gboolean	success = FALSE;
-	char *	argv[4];
-	GError *	error = NULL;
-	GPid		pid = -1;
-
-	argv[0] = WPA_SUPPLICANT_BIN;
-	argv[1] = "-g";
-	argv[2] = WPA_SUPPLICANT_GLOBAL_SOCKET;
-	argv[3] = NULL;
-
-	success = g_spawn_async ("/", argv, NULL, 0, &supplicant_child_setup, NULL,
-	                         &pid, &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
-	{
-		/* 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,
-							   supplicant_watch_done);
-		g_source_attach (self->priv->supplicant.watch, nm_device_get_main_context (NM_DEVICE (self)));
-		g_source_unref (self->priv->supplicant.watch);
-	}
-
-	return success;
-}
-
-
-static gboolean
-supplicant_interface_init (NMDevice80211Wireless *self)
-{
-	struct wpa_ctrl *	ctrl = NULL;
-	char *			socket_path;
-	const char *		iface = nm_device_get_iface (NM_DEVICE (self));
-	gboolean			success = FALSE;
-	int				tries = 0;
-
-	/* 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 guint32
 find_supported_frequency (NMDevice80211Wireless *self, guint32 *freqs)
@@ -2862,7 +2421,6 @@
 	return 0;
 }
 
-
 static gboolean
 supplicant_send_network_config (NMDevice80211Wireless *self,
                                 NMActRequest *req)
@@ -2879,13 +2437,10 @@
 	guint32			caps;
 	gboolean			supports_wpa;
 
-	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->supplicant.ctrl;
+	ctrl = nm_supplicant_get_ctrl (self->priv->supplicant);
 	g_assert (ctrl);
 
 	/* Assume that drivers that don't support WPA pretty much suck,
@@ -2985,52 +2540,157 @@
 	return success;
 }
 
+#define NM_SUPPLICANT_TIMEOUT	20	/* how long we wait for wpa_supplicant to associate (in seconds) */
+
+static unsigned int
+get_supplicant_timeout (NMDevice80211Wireless *self)
+{
+	if (self->priv->num_freqs > 14)
+		return NM_SUPPLICANT_TIMEOUT * 2;
+	return NM_SUPPLICANT_TIMEOUT;
+}
 
 static gboolean
-supplicant_monitor_start (NMDevice80211Wireless *self)
+supplicant_timed_out (gpointer user_data)
 {
-	gboolean		success = FALSE;
-	int			fd = -1;
-	GIOChannel *	channel;
-	GMainContext *	context;
+	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);
+	NMData *data = nm_device_get_app_data (dev);
+	gboolean has_key;
 
-	g_return_val_if_fail (self != NULL, FALSE);
+	/* 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) {
+		/* 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_dbus_get_user_key_for_network (data->dbus_connection, 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))
+			nm_policy_schedule_activation_failed (nm_device_get_act_request (dev));
+	}
 
-	/* register network event monitor */
-	if (wpa_ctrl_attach (self->priv->supplicant.ctrl) != 0)
-		goto out;
+	return FALSE;
+}
 
-	if ((fd = wpa_ctrl_get_fd (self->priv->supplicant.ctrl)) < 0)
-		goto out;
+static void
+remove_link_timeout (NMDevice80211Wireless *self)
+{
+	g_return_if_fail (self != NULL);
 
-	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_io_channel_unref (channel);
-	g_source_set_callback (self->priv->supplicant.status,
-						   (GSourceFunc) supplicant_status_cb,
-						   self,
-						   supplicant_status_done);
-	g_source_attach (self->priv->supplicant.status, context);
-	g_source_unref (self->priv->supplicant.status);
-
-	/* 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,
-						   supplicant_timeout_done);
-	g_source_attach (self->priv->supplicant.timeout, context);
-	g_source_unref (self->priv->supplicant.timeout);
+	if (self->priv->link_timeout != NULL)
+	{
+		g_source_destroy (self->priv->link_timeout);
+		self->priv->link_timeout = NULL;
+	}
+}
 
-	success = TRUE;
+static void
+link_timeout_done (gpointer user_data)
+{
+	NMDevice80211Wireless *device = NM_DEVICE_802_11_WIRELESS (user_data);
 
-out:
-	return success;
+	device->priv->link_timeout = NULL;
+}
+
+/*
+ * link_timeout_cb
+ *
+ * Called when the link to the access point has been down for a specified
+ * period of time.
+ */
+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);
+ 	NMData *				data = nm_device_get_app_data (dev);
+ 	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));
+ 		nm_supplicant_remove_timeout (self->priv->supplicant);
+ 		nm_dbus_get_user_key_for_network (data->dbus_connection, req, TRUE);
+ 	}
+ 	else
+ 	{
+ 		nm_info ("%s: link timed out.", nm_device_get_iface (dev));
+ 		nm_device_set_active_link (dev, FALSE);
+ 	}
+
+	return FALSE;
 }
 
+static void
+supplicant_state_changed (NMSupplicant *supplicant,
+					 gboolean connected,
+					 gpointer user_data)
+{
+	NMDevice80211Wireless *self = NM_DEVICE_802_11_WIRELESS (user_data);
+	NMDevice *dev = NM_DEVICE (self);
+	NMActRequest *req = nm_device_get_act_request (NM_DEVICE (self));
+
+	if (connected) {
+		remove_link_timeout (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);
+
+			nm_info ("Activation (%s/wireless) Stage 2 of 5 (Device Configure) "
+				    "successful.  Connected to access point '%s'.",
+				    nm_device_get_iface (dev),
+				    nm_ap_get_essid (ap) ? nm_ap_get_essid (ap) : "(none)");
+			nm_supplicant_remove_timeout (self->priv->supplicant);
+			nm_device_activate_schedule_stage3_ip_config_start (req);
+		}
+	} else {
+		if (nm_device_is_activated (dev) || nm_device_is_activating (dev)) {
+			/* Start the link timeout so we allow some time for reauthentication */
+			if ((self->priv->link_timeout == NULL) && !self->priv->scanning) {
+				self->priv->link_timeout = g_timeout_source_new (8000);
+				g_source_set_callback (self->priv->link_timeout,
+								   link_timeout_cb,
+								   self,
+								   link_timeout_done);
+				g_source_attach (self->priv->link_timeout, nm_device_get_main_context (dev));
+				g_source_unref (self->priv->link_timeout);
+			}
+		} else
+			nm_device_set_active_link (dev, FALSE);
+	}
+}
 
+static void
+supplicant_down (NMSupplicant *supplicant,
+			  gpointer user_data)
+{
+	NMDevice80211Wireless *self = NM_DEVICE_802_11_WIRELESS (user_data);
 
+	remove_link_timeout (self);
+}
 
 /****************************************************************************/
 
@@ -3040,15 +2700,13 @@
 {
 	NMDevice80211Wireless *	self = NM_DEVICE_802_11_WIRELESS (dev);
 	NMAccessPoint *		ap = nm_act_request_get_ap (req);
-	NMActStageReturn		ret = NM_ACT_STAGE_RETURN_FAILURE;
 	NMData *				data = nm_act_request_get_data (req);
 	const char *			iface;
 	gboolean				ask_user = FALSE;
+	GMainContext *ctx;
 
 	g_assert (ap);
 
-	supplicant_cleanup (self);
-
 	/* If we need an encryption key, get one */
 	if (ap_need_key (self, ap, &ask_user))
 	{
@@ -3060,22 +2718,32 @@
 	sleep (1);
 
 	iface = nm_device_get_iface (dev);
-	if (!supplicant_exec (self))
+	ctx = nm_device_get_main_context (dev);
+
+	self->priv->supplicant = nm_supplicant_new ();
+	g_signal_connect (self->priv->supplicant, "state-changed",
+			  G_CALLBACK (supplicant_state_changed),
+			  self);
+
+	g_signal_connect (self->priv->supplicant, "down",
+			  G_CALLBACK (supplicant_down),
+			  self);
+
+	if (!nm_supplicant_exec (self->priv->supplicant, ctx))
 	{
-		nm_warning ("Activation (%s/wireless): couldn't start the supplicant.",
-			iface);
+		nm_warning ("Activation (%s/wireless): couldn't start the supplicant.", iface);
 		goto out;
 	}
-	if (!supplicant_interface_init (self))
+	if (!nm_supplicant_interface_init (self->priv->supplicant, iface, "wext"))
 	{
-		nm_warning ("Activation (%s/wireless): couldn't connect to the supplicant.",
-			iface);
+		nm_warning ("Activation (%s/wireless): couldn't connect to the supplicant.", iface);
 		goto out;
 	}
-	if (!supplicant_monitor_start (self))
+	if (!nm_supplicant_monitor_start (self->priv->supplicant, ctx,
+					  get_supplicant_timeout (self),
+					  supplicant_timed_out, self))
 	{
-		nm_warning ("Activation (%s/wireless): couldn't monitor the supplicant.",
-			iface);
+		nm_warning ("Activation (%s/wireless): couldn't monitor the supplicant.", iface);
 		goto out;
 	}
 	if (!supplicant_send_network_config (self, req))
@@ -3086,10 +2754,13 @@
 	}
 
 	/* We'll get stage3 started when the supplicant connects */
-	ret = NM_ACT_STAGE_RETURN_POSTPONE;
+	return NM_ACT_STAGE_RETURN_POSTPONE;
 
 out:
-	return ret;
+	g_object_unref (self->priv->supplicant);
+	self->priv->supplicant = NULL;
+
+	return NM_ACT_STAGE_RETURN_FAILURE;
 }
 
 

Added: branches/NETWORKMANAGER_0_6_0_RELEASE/src/nm-supplicant.c
==============================================================================
--- (empty file)
+++ branches/NETWORKMANAGER_0_6_0_RELEASE/src/nm-supplicant.c	Wed Jan 16 16:51:06 2008
@@ -0,0 +1,419 @@
+/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
+
+#include <signal.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "nm-supplicant.h"
+#include "NetworkManagerUtils.h"
+#include "nm-utils.h"
+#include "wpa_ctrl.h"
+
+
+/****************************************************************************/
+/* WPA Supplicant control stuff
+ *
+ * Originally from:
+ *
+ *	wpa_supplicant wrapper
+ *
+ *	Copyright (C) 2005 Kay Sievers <kay sievers vrfy org>
+ *
+ *	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		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
+
+G_DEFINE_TYPE (NMSupplicant, nm_supplicant, G_TYPE_OBJECT)
+
+#define NM_SUPPLICANT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SUPPLICANT, NMSupplicantPrivate))
+
+typedef struct {
+	GPid pid;
+	GSource *watch;
+	GSource *status;
+	GSource *timeout;
+	struct wpa_ctrl *ctrl;
+
+	char *socket_path;
+	char *message;
+} NMSupplicantPrivate;
+
+enum {
+	STATE_CHANGED,
+	DOWN,
+
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+NMSupplicant *
+nm_supplicant_new (void)
+{
+	return (NMSupplicant *) g_object_new (NM_TYPE_SUPPLICANT, NULL);
+}
+
+void
+nm_supplicant_remove_timeout (NMSupplicant *self)
+{
+	NMSupplicantPrivate *priv = NM_SUPPLICANT_GET_PRIVATE (self);
+
+	/* Remove any pending timeouts on the request */
+	if (priv->timeout != NULL) {
+		g_source_destroy (priv->timeout);
+		priv->timeout = NULL;
+	}
+}
+
+void
+nm_supplicant_down (NMSupplicant *self)
+{
+	NMSupplicantPrivate *priv;
+
+	g_return_if_fail (NM_IS_SUPPLICANT (self));
+
+	priv = NM_SUPPLICANT_GET_PRIVATE (self);
+
+	if (priv->pid > 0) {
+		kill (priv->pid, SIGTERM);
+		priv->pid = -1;
+	}
+
+	if (priv->watch) {
+		g_source_destroy (priv->watch);
+		priv->watch = NULL;
+	}
+
+	if (priv->status) {
+		g_source_destroy (priv->status);
+		priv->status = NULL;
+	}
+
+	if (priv->ctrl) {
+		wpa_ctrl_close (priv->ctrl);
+		priv->ctrl = NULL;
+	}
+
+	nm_supplicant_remove_timeout (self);
+
+	/* HACK: should be fixed in wpa_supplicant.  Will likely
+	 * require accomodations for selinux.
+	 */
+	unlink (WPA_SUPPLICANT_GLOBAL_SOCKET);
+	unlink (priv->socket_path);
+
+	g_signal_emit (self, signals[DOWN], 0);
+}
+
+static void
+supplicant_watch_done (gpointer user_data)
+{
+	NMSupplicantPrivate *priv = NM_SUPPLICANT_GET_PRIVATE (user_data);
+
+	priv->watch = NULL;
+}
+
+static void
+supplicant_watch_cb (GPid pid,
+                     gint status,
+                     gpointer user_data)
+{
+	NMSupplicant *self = NM_SUPPLICANT (user_data);
+
+	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");
+
+	nm_supplicant_down (self);
+}
+
+/*
+ * supplicant_child_setup
+ *
+ * Set the process group ID of the newly forked process
+ *
+ */
+static void
+supplicant_child_setup (gpointer user_data G_GNUC_UNUSED)
+{
+	/* We are in the child process at this point */
+	pid_t pid = getpid ();
+	setpgid (pid, pid);
+}
+
+gboolean
+nm_supplicant_exec (NMSupplicant *self,
+				GMainContext *ctx)
+{
+	gboolean success;
+	char *argv[4];
+	GPid pid;
+	GError *err = NULL;
+
+	g_return_val_if_fail (NM_IS_SUPPLICANT (self), FALSE);
+
+	argv[0] = WPA_SUPPLICANT_BIN;
+	argv[1] = "-g";
+	argv[2] = WPA_SUPPLICANT_GLOBAL_SOCKET;
+	argv[3] = NULL;
+
+	success = g_spawn_async ("/", argv, NULL, 0, &supplicant_child_setup, NULL, &pid, &err);
+	if (!success) {
+		if (err) {
+			nm_warning ("Couldn't start wpa_supplicant. Error: (%d) %s", err->code, err->message);
+			g_error_free (err);
+		} else
+			nm_warning ("Couldn't start wpa_supplicant due to an unknown error.");
+	} else {
+		NMSupplicantPrivate *priv = NM_SUPPLICANT_GET_PRIVATE (self);
+
+		/* Monitor the child process so we know when it stops */
+		priv->pid = pid;
+		if (priv->watch)
+			g_source_destroy (priv->watch);
+
+		priv->watch = g_child_watch_source_new (pid);
+		g_source_set_callback (priv->watch,
+						   (GSourceFunc) supplicant_watch_cb,
+						   self,
+						   supplicant_watch_done);
+		g_source_attach (priv->watch, ctx);
+		g_source_unref (priv->watch);
+	}
+
+	return success;
+}
+
+gboolean
+nm_supplicant_interface_init (NMSupplicant *self, 
+						const char *iface,
+						const char *supplicant_driver)
+{
+	NMSupplicantPrivate *priv;
+	struct wpa_ctrl *ctrl = NULL;
+	int tries;
+
+	g_return_val_if_fail (NM_IS_SUPPLICANT (self), FALSE);
+	g_return_val_if_fail (iface != NULL, FALSE);
+
+	/* 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.");
+		return FALSE;
+	}
+
+	/* 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\t%s\t" WPA_SUPPLICANT_CONTROL_SOCKET "\t",
+										iface, supplicant_driver)) {
+		wpa_ctrl_close (ctrl);
+		return FALSE;
+	}
+
+	wpa_ctrl_close (ctrl);
+
+	priv = NM_SUPPLICANT_GET_PRIVATE (self);
+
+	/* 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.
+	 */
+	priv->socket_path = g_strdup_printf (WPA_SUPPLICANT_CONTROL_SOCKET "/%s", iface);
+
+	while (!priv->ctrl && (tries++ < 10))
+		priv->ctrl = wpa_ctrl_open (priv->socket_path, NM_RUN_DIR);
+
+	if (!priv->ctrl)
+		nm_info ("Error opening control interface to supplicant.");
+
+	return priv->ctrl != NULL;
+}
+
+static void
+supplicant_status_done (gpointer user_data)
+{
+	NMSupplicantPrivate *priv = NM_SUPPLICANT_GET_PRIVATE (user_data);
+
+	priv->status = NULL;
+}
+
+static void
+supplicant_state_changed (NMSupplicant *self, gboolean up)
+{
+	g_signal_emit (self, signals[STATE_CHANGED], 0, up);
+}
+
+#define MESSAGE_LEN	2048
+
+static gboolean
+supplicant_status_cb (GIOChannel *source,
+                      GIOCondition condition,
+                      gpointer user_data)
+{
+	NMSupplicant *self = NM_SUPPLICANT (user_data);
+	NMSupplicantPrivate *priv = NM_SUPPLICANT_GET_PRIVATE (self);
+	size_t len = MESSAGE_LEN;
+
+	wpa_ctrl_recv (priv->ctrl, priv->message, &len);
+	priv->message[len] = '\0';
+
+	if (strstr (priv->message, WPA_EVENT_CONNECTED) != NULL)
+		supplicant_state_changed (self, TRUE);
+	else if (strstr (priv->message, WPA_EVENT_DISCONNECTED) != NULL)
+		supplicant_state_changed (self, FALSE);
+
+	return TRUE;
+}
+
+typedef struct {
+	NMSupplicant *supplicant;
+	GSourceFunc callback;
+	gpointer user_data;
+} TimeoutInfo;
+
+static void
+supplicant_timeout_done (gpointer user_data)
+{
+	TimeoutInfo *info = (TimeoutInfo *) user_data;
+
+	NM_SUPPLICANT_GET_PRIVATE (info->supplicant)->timeout = NULL;
+
+	g_free (info);
+}
+
+static void
+supplicant_timeout_cb (gpointer user_data)
+{
+	TimeoutInfo *info = (TimeoutInfo *) user_data;
+
+	info->callback (info->user_data);
+}
+
+gboolean
+nm_supplicant_monitor_start (NMSupplicant *self,
+					    GMainContext *context,
+					    guint32 timeout,
+					    GSourceFunc timeout_cb,
+					    gpointer user_data)
+{
+	NMSupplicantPrivate *priv;
+	int fd;
+	GIOChannel *channel;
+
+	g_return_val_if_fail (NM_IS_SUPPLICANT (self), FALSE);
+
+	priv = NM_SUPPLICANT_GET_PRIVATE (self);
+
+	/* register network event monitor */
+	if (wpa_ctrl_attach (priv->ctrl) != 0)
+		return FALSE;
+
+	if ((fd = wpa_ctrl_get_fd (priv->ctrl)) < 0)
+		return FALSE;
+
+	channel = g_io_channel_unix_new (fd);
+	priv->status = g_io_create_watch (channel, G_IO_IN);
+	g_io_channel_unref (channel);
+	g_source_set_callback (priv->status,
+					   (GSourceFunc) supplicant_status_cb,
+					   self,
+					   supplicant_status_done);
+	g_source_attach (priv->status, context);
+	g_source_unref (priv->status);
+
+	if (timeout_cb) {
+		TimeoutInfo *info;
+
+		info = g_new (TimeoutInfo, 1);
+		info->supplicant = self;
+		info->callback = timeout_cb;
+		info->user_data = user_data;
+
+		priv->timeout = g_timeout_source_new (timeout * 1000);
+		g_source_set_callback (priv->timeout,
+						   (GSourceFunc) supplicant_timeout_cb,
+						   info,
+						   supplicant_timeout_done);
+		g_source_attach (priv->timeout, context);
+		g_source_unref (priv->timeout);
+	}
+
+	return TRUE;
+}
+
+struct wpa_ctrl *
+nm_supplicant_get_ctrl (NMSupplicant *self)
+{
+	g_return_val_if_fail (NM_IS_SUPPLICANT (self), NULL);
+
+	return NM_SUPPLICANT_GET_PRIVATE (self)->ctrl;
+}
+
+/*****************************************************************************/
+
+static void
+nm_supplicant_init (NMSupplicant *supplicant)
+{
+	NMSupplicantPrivate *priv = NM_SUPPLICANT_GET_PRIVATE (supplicant);
+
+	priv->message = g_malloc (MESSAGE_LEN);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMSupplicantPrivate *priv = NM_SUPPLICANT_GET_PRIVATE (object);
+
+	nm_supplicant_down (NM_SUPPLICANT (object));
+
+	g_free (priv->socket_path);
+	g_free (priv->message);
+
+	G_OBJECT_CLASS (nm_supplicant_parent_class)->finalize (object);
+}
+
+static void
+nm_supplicant_class_init (NMSupplicantClass *supplicant_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (supplicant_class);
+
+	g_type_class_add_private (supplicant_class, sizeof (NMSupplicantPrivate));
+
+	object_class->finalize = finalize;
+
+	/* signals */
+	signals[STATE_CHANGED] =
+		g_signal_new ("state-changed",
+				    G_OBJECT_CLASS_TYPE (object_class),
+				    G_SIGNAL_RUN_FIRST,
+				    G_STRUCT_OFFSET (NMSupplicantClass, state_changed),
+				    NULL, NULL,
+				    g_cclosure_marshal_VOID__BOOLEAN,
+				    G_TYPE_NONE, 1,
+				    G_TYPE_BOOLEAN);
+
+	signals[DOWN] =
+		g_signal_new ("down",
+				    G_OBJECT_CLASS_TYPE (object_class),
+				    G_SIGNAL_RUN_FIRST,
+				    G_STRUCT_OFFSET (NMSupplicantClass, down),
+				    NULL, NULL,
+				    g_cclosure_marshal_VOID__VOID,
+				    G_TYPE_NONE, 0);
+}

Added: branches/NETWORKMANAGER_0_6_0_RELEASE/src/nm-supplicant.h
==============================================================================
--- (empty file)
+++ branches/NETWORKMANAGER_0_6_0_RELEASE/src/nm-supplicant.h	Wed Jan 16 16:51:06 2008
@@ -0,0 +1,53 @@
+/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
+
+#ifndef NM_SUPPLICANT_H
+#define NM_SUPPLICANT_H 1
+
+#include <glib/gtypes.h>
+#include <glib-object.h>
+
+#define NM_TYPE_SUPPLICANT            (nm_supplicant_get_type ())
+#define NM_SUPPLICANT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SUPPLICANT, NMSupplicant))
+#define NM_SUPPLICANT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SUPPLICANT, NMSupplicantClass))
+#define NM_IS_SUPPLICANT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SUPPLICANT))
+#define NM_IS_SUPPLICANT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_SUPPLICANT))
+#define NM_SUPPLICANT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SUPPLICANT, NMSupplicantClass))
+
+typedef struct {
+	GObject parent;
+} NMSupplicant;
+
+typedef struct {
+	GObjectClass parent;
+
+	/* Signals */
+	void (*state_changed) (NMSupplicant *supplicant,
+					   gboolean connected);
+
+	void (*down) (NMSupplicant *supplicant);
+} NMSupplicantClass;
+
+GType nm_supplicant_get_type (void);
+
+NMSupplicant *nm_supplicant_new (void);
+gboolean      nm_supplicant_exec (NMSupplicant *self,
+						    GMainContext *ctx);
+
+gboolean      nm_supplicant_interface_init (NMSupplicant *self, 
+								    const char *iface,
+								    const char *supplicant_driver);
+
+gboolean      nm_supplicant_monitor_start  (NMSupplicant *self,
+								    GMainContext *context,
+								    guint32 timeout,
+								    GSourceFunc timeout_cb,
+								    gpointer user_data);
+
+void          nm_supplicant_remove_timeout (NMSupplicant *self);
+
+void          nm_supplicant_down           (NMSupplicant *self);
+
+struct wpa_ctrl *nm_supplicant_get_ctrl     (NMSupplicant *self);
+
+
+#endif /* NM_SUPPLICANT_H */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]