2006-02-28 Dan Williams <dcbw@redhat.com>

* src/nm-device-802-11-wireless.c
		- Move all the wpa_supplicant-related management stuff into its
			own struct, just for oranization's sake
		- (supplicant_exec): when exec-ing wpa_supplicant, connect its stdout
			to a GIOChannel/GSource
		- (supplicant_log_stdout): new function; grab output from the
			wpa_supplicant stdout pipe and write it to our logs.


git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@1519 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
This commit is contained in:
Dan Williams
2006-02-28 20:13:56 +00:00
parent 42d5ee0eeb
commit c624a36ee8
2 changed files with 163 additions and 47 deletions

View File

@@ -1,3 +1,13 @@
2006-02-28 Dan Williams <dcbw@redhat.com>
* src/nm-device-802-11-wireless.c
- Move all the wpa_supplicant-related management stuff into its
own struct, just for oranization's sake
- (supplicant_exec): when exec-ing wpa_supplicant, connect its stdout
to a GIOChannel/GSource
- (supplicant_log_stdout): new function; grab output from the
wpa_supplicant stdout pipe and write it to our logs.
2006-02-27 Christopher Aillon <caillon@redhat.com> 2006-02-27 Christopher Aillon <caillon@redhat.com>
* src/nm-device-802-11-wireless.c: * src/nm-device-802-11-wireless.c:

View File

@@ -47,6 +47,17 @@
#define NM_DEVICE_802_11_WIRELESS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_802_11_WIRELESS, NMDevice80211WirelessPrivate)) #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;
GSource * stdout;
};
struct _NMDevice80211WirelessPrivate struct _NMDevice80211WirelessPrivate
{ {
gboolean dispose_has_run; gboolean dispose_has_run;
@@ -67,12 +78,7 @@ struct _NMDevice80211WirelessPrivate
guint8 scan_interval; /* seconds */ guint8 scan_interval; /* seconds */
guint32 last_scan; guint32 last_scan;
/* Supplicant control */ struct _Supplicant supplicant;
GPid sup_pid;
GSource * sup_watch;
GSource * sup_status;
struct wpa_ctrl * sup_ctrl;
GSource * sup_timeout;
guint32 failed_link_count; guint32 failed_link_count;
GSource * link_timeout; GSource * link_timeout;
@@ -238,7 +244,7 @@ nm_device_802_11_wireless_init (NMDevice80211Wireless * self)
self->priv->dispose_has_run = FALSE; self->priv->dispose_has_run = FALSE;
memset (&(self->priv->hw_addr), 0, sizeof (struct ether_addr)); memset (&(self->priv->hw_addr), 0, sizeof (struct ether_addr));
self->priv->sup_pid = -1; self->priv->supplicant.pid = -1;
} }
static void static void
@@ -311,7 +317,7 @@ real_update_link (NMDevice *dev)
NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (dev); NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (dev);
/* If the supplicant isn't running, we can't possibly have a link */ /* If the supplicant isn't running, we can't possibly have a link */
if (!self->priv->sup_pid) if (!self->priv->supplicant.pid)
nm_device_set_active_link (NM_DEVICE (self), FALSE); nm_device_set_active_link (NM_DEVICE (self), FALSE);
} }
@@ -2050,10 +2056,10 @@ supplicant_remove_timeout (NMDevice80211Wireless *self)
g_return_if_fail (self != NULL); g_return_if_fail (self != NULL);
/* Remove any pending timeouts on the request */ /* Remove any pending timeouts on the request */
if (self->priv->sup_timeout != NULL) if (self->priv->supplicant.timeout != NULL)
{ {
g_source_destroy (self->priv->sup_timeout); g_source_destroy (self->priv->supplicant.timeout);
self->priv->sup_timeout = NULL; self->priv->supplicant.timeout = NULL;
} }
} }
@@ -2075,25 +2081,30 @@ supplicant_cleanup (NMDevice80211Wireless *self)
g_return_if_fail (self != NULL); g_return_if_fail (self != NULL);
if (self->priv->sup_pid > 0) if (self->priv->supplicant.pid > 0)
{ {
kill (self->priv->sup_pid, SIGTERM); kill (self->priv->supplicant.pid, SIGTERM);
self->priv->sup_pid = -1; self->priv->supplicant.pid = -1;
} }
if (self->priv->sup_watch) if (self->priv->supplicant.watch)
{ {
g_source_destroy (self->priv->sup_watch); g_source_destroy (self->priv->supplicant.watch);
self->priv->sup_watch = NULL; self->priv->supplicant.watch = NULL;
} }
if (self->priv->sup_status) if (self->priv->supplicant.status)
{ {
g_source_destroy (self->priv->sup_status); g_source_destroy (self->priv->supplicant.status);
self->priv->sup_status = NULL; self->priv->supplicant.status = NULL;
} }
if (self->priv->sup_ctrl) if (self->priv->supplicant.ctrl)
{ {
wpa_ctrl_close (self->priv->sup_ctrl); wpa_ctrl_close (self->priv->supplicant.ctrl);
self->priv->sup_ctrl = NULL; 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); supplicant_remove_timeout (self);
@@ -2163,7 +2174,7 @@ supplicant_status_cb (GIOChannel *source,
g_assert (self); g_assert (self);
ctrl = self->priv->sup_ctrl; ctrl = self->priv->supplicant.ctrl;
g_return_val_if_fail (ctrl != NULL, FALSE); g_return_val_if_fail (ctrl != NULL, FALSE);
req = nm_device_get_act_request (NM_DEVICE (self)); req = nm_device_get_act_request (NM_DEVICE (self));
@@ -2247,20 +2258,98 @@ supplicant_timeout_cb (gpointer user_data)
} }
/*
* 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;
}
static gboolean static gboolean
supplicant_exec (NMDevice80211Wireless *self) supplicant_exec (NMDevice80211Wireless *self)
{ {
gboolean success = FALSE; gboolean success = FALSE;
char * argv[4]; char * argv[5];
GError * error = NULL; GError * error = NULL;
GPid pid = -1; GPid pid = -1;
int sup_stdout;
argv[0] = WPA_SUPPLICANT_BIN; argv[0] = WPA_SUPPLICANT_BIN;
argv[1] = "-g"; argv[1] = "-dd";
argv[2] = WPA_SUPPLICANT_GLOBAL_SOCKET; argv[2] = "-g";
argv[3] = NULL; argv[3] = WPA_SUPPLICANT_GLOBAL_SOCKET;
argv[4] = NULL;
if (!(success = g_spawn_async ("/", argv, NULL, 0, NULL, NULL, &pid, &error))) success = g_spawn_async_with_pipes ("/", argv, NULL, 0, NULL, NULL,
&pid, NULL, &sup_stdout, NULL, &error);
if (!success)
{ {
if (error) if (error)
{ {
@@ -2273,13 +2362,30 @@ supplicant_exec (NMDevice80211Wireless *self)
} }
else 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_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);
/* Crackrock delay so we don't try to talk to wpa_supplicant to early */
/* FIXME: poll the global control socket instead of just sleeping */
g_usleep (G_USEC_PER_SEC); g_usleep (G_USEC_PER_SEC);
self->priv->sup_pid = pid;
if (self->priv->sup_watch) /* Monitor the child process so we know when it stops */
g_source_destroy (self->priv->sup_watch); self->priv->supplicant.pid = pid;
self->priv->sup_watch = g_child_watch_source_new (pid); if (self->priv->supplicant.watch)
g_source_set_callback (self->priv->sup_watch, (GSourceFunc) supplicant_watch_cb, self, NULL); g_source_destroy (self->priv->supplicant.watch);
g_source_attach (self->priv->sup_watch, nm_device_get_main_context (NM_DEVICE (self))); 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; return success;
@@ -2309,10 +2415,10 @@ supplicant_interface_init (NMDevice80211Wireless *self)
* in wpa_ctrl that sometimes collides with stale ones. * in wpa_ctrl that sometimes collides with stale ones.
*/ */
socket_path = supplicant_get_device_socket_path (self); socket_path = supplicant_get_device_socket_path (self);
while (!self->priv->sup_ctrl && (tries++ < 10)) while (!self->priv->supplicant.ctrl && (tries++ < 10))
self->priv->sup_ctrl = wpa_ctrl_open (socket_path, NM_RUN_DIR); self->priv->supplicant.ctrl = wpa_ctrl_open (socket_path, NM_RUN_DIR);
g_free (socket_path); g_free (socket_path);
if (!self->priv->sup_ctrl) if (!self->priv->supplicant.ctrl)
{ {
nm_info ("Error opening control interface to supplicant."); nm_info ("Error opening control interface to supplicant.");
goto exit; goto exit;
@@ -2344,7 +2450,7 @@ supplicant_send_network_config (NMDevice80211Wireless *self,
ap = nm_act_request_get_ap (req); ap = nm_act_request_get_ap (req);
g_assert (ap); g_assert (ap);
ctrl = self->priv->sup_ctrl; ctrl = self->priv->supplicant.ctrl;
g_assert (ctrl); g_assert (ctrl);
/* Ad-Hoc and non-broadcasting networks need AP_SCAN 2 */ /* Ad-Hoc and non-broadcasting networks need AP_SCAN 2 */
@@ -2428,22 +2534,22 @@ supplicant_monitor_start (NMDevice80211Wireless *self)
g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (self != NULL, FALSE);
/* register network event monitor */ /* register network event monitor */
if (wpa_ctrl_attach (self->priv->sup_ctrl) != 0) if (wpa_ctrl_attach (self->priv->supplicant.ctrl) != 0)
goto out; goto out;
if ((fd = wpa_ctrl_get_fd (self->priv->sup_ctrl)) < 0) if ((fd = wpa_ctrl_get_fd (self->priv->supplicant.ctrl)) < 0)
goto out; goto out;
context = nm_device_get_main_context (NM_DEVICE (self)); context = nm_device_get_main_context (NM_DEVICE (self));
channel = g_io_channel_unix_new (fd); channel = g_io_channel_unix_new (fd);
self->priv->sup_status = g_io_create_watch (channel, G_IO_IN); self->priv->supplicant.status = g_io_create_watch (channel, G_IO_IN);
g_source_set_callback (self->priv->sup_status, (GSourceFunc) supplicant_status_cb, self, NULL); g_source_set_callback (self->priv->supplicant.status, (GSourceFunc) supplicant_status_cb, self, NULL);
g_source_attach (self->priv->sup_status, context); g_source_attach (self->priv->supplicant.status, context);
/* Set up a timeout on the association to kill it after get_supplicant_time() seconds */ /* Set up a timeout on the association to kill it after get_supplicant_time() seconds */
self->priv->sup_timeout = g_timeout_source_new (get_supplicant_timeout (self) * 1000); self->priv->supplicant.timeout = g_timeout_source_new (get_supplicant_timeout (self) * 1000);
g_source_set_callback (self->priv->sup_timeout, supplicant_timeout_cb, self, NULL); g_source_set_callback (self->priv->supplicant.timeout, supplicant_timeout_cb, self, NULL);
g_source_attach (self->priv->sup_timeout, context); g_source_attach (self->priv->supplicant.timeout, context);
success = TRUE; success = TRUE;