2006-09-07 Dan Williams <dcbw@redhat.com>

* test/Makefile.am
	  test/libnm-util/Makefile.am
	  test/nm-supplicant-test.c
		- Add test program emulating the way NM drives wpa_supplicant
		to help debug supplicant issues


git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@2022 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
This commit is contained in:
Dan Williams 2006-09-07 19:17:20 +00:00
parent 5ce596672e
commit 49dfe63373
4 changed files with 845 additions and 6 deletions

View file

@ -1,3 +1,11 @@
2006-09-07 Dan Williams <dcbw@redhat.com>
* test/Makefile.am
test/libnm-util/Makefile.am
test/nm-supplicant-test.c
- Add test program emulating the way NM drives wpa_supplicant
to help debug supplicant issues
2006-08-24 Dan Williams <dcbw@redhat.com>
* configure.in

View file

@ -11,9 +11,16 @@ AM_CPPFLAGS = \
$(HAL_CFLAGS) \
-DDBUS_API_SUBJECT_TO_CHANGE \
-DBINDIR=\"$(bindir)\" \
-DWPA_SUPPLICANT_BIN=\"$(WPA_SUPPLICANT_BINARY_PATH)\" \
-DNM_RUN_DIR=\"$(rundir)\" \
-DDATADIR=\"$(datadir)\"
noinst_PROGRAMS = nm-tool nm-online nminfotest nmtestdevices libnm_glib_test
noinst_PROGRAMS = nm-tool \
nm-online \
nminfotest \
nmtestdevices \
libnm_glib_test \
nm-supplicant-test
nm_tool_SOURCES = nm-tool.c
nm_tool_LDADD = $(DBUS_LIBS) $(GTHREAD_LIBS) $(HAL_LIBS) \
@ -34,5 +41,7 @@ nmtestdevices_LDADD = $(DBUS_LIBS) $(GTHREAD_LIBS) \
libnm_glib_test_SOURCES = libnm_glib_test.c
libnm_glib_test_LDADD = $(DBUS_LIBS) $(GTHREAD_LIBS) \
$(top_builddir)/utils/libnmutils.la \
../gnome/libnm_glib/libnm_glib.la
$(top_builddir)/gnome/libnm_glib/libnm_glib.la
nm_supplicant_test_SOURCES = nm-supplicant-test.c
nm_supplicant_test_LDADD = $(GLIB_LIBS) $(GTHREAD_LIBS)

View file

@ -2,8 +2,8 @@ INCLUDES = -I${top_srcdir} \
-I${top_srcdir}/utils \
-I${top_srcdir}/include \
-I${top_srcdir}/libnm-util \
-I${top_srcdir}/test \
-I${top_srcdir}/test/test-common
-I${top_srcdir}/test \
-I${top_srcdir}/test/test-common
noinst_PROGRAMS = test-ciphers test-dbus-helpers test-dbus-dict-helpers
@ -19,8 +19,8 @@ test_ciphers_CPPFLAGS = \
test_ciphers_LDADD = \
$(DBUS_LIBS) \
$(GLIB_LIBS) \
$(top_builddir)/libnm-util/libnm-util.la \
$(top_builddir)/test/test-common/libtest-common.la
$(top_builddir)/libnm-util/libnm-util.la \
$(top_builddir)/test/test-common/libtest-common.la
test_dbus_helpers_SOURCES = test-dbus-helpers.c test-inputs.h

822
test/nm-supplicant-test.c Normal file
View file

@ -0,0 +1,822 @@
/* supplicant test utility
*
* Dan Williams <dcbw@redhat.com>
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* (C) Copyright 2006 Red Hat, Inc.
*/
#include <glib.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "../src/wpa_ctrl.h"
#include "../src/wpa_ctrl.c"
#define nm_info(fmt, args...) fprintf(stdout, fmt "\n", ##args)
#define nm_warning(fmt, args...) fprintf(stdout, fmt "\n", ##args)
#define nm_warning_str(fmt_str, args...) fprintf(stdout, "%s\n", fmt_str, ##args)
struct opt {
char *key;
char *value;
};
#define STATE_DISCONNECTED 0
#define STATE_DEVICE_CONFIG 1
#define STATE_CONNECTED 2
struct supplicant {
GMainLoop * loop;
GPid pid;
GSource * watch;
GSource * status;
struct wpa_ctrl * ctrl;
GSource * timeout;
GSource * stdout;
GSource * link_timeout;
char * iface;
guint32 ap_scan;
GSList * options;
guint32 state;
const char * ssid;
};
#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;
}
static 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;
nm_info ("SUP: sending command '%s'", command);
wpa_ctrl_request (ctrl, command, strlen (command), response, &len, NULL);
g_free (command);
response[len] = '\0';
{
response = kill_newline (response, &len);
nm_info ("SUP: response was '%s'", response);
}
return response;
}
static 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;
nm_info ("SUP: sending command '%s'", err_msg_cmd ? err_msg_cmd : command);
wpa_ctrl_request (ctrl, command, strlen (command), response, &len, NULL);
response[len] = '\0';
{
response = kill_newline (response, &len);
nm_info ("SUP: response was '%s'", response);
}
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;
}
/****************************************************************************/
/* 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 "/var/run/wpa_supplicant-global"
#define WPA_SUPPLICANT_CONTROL_SOCKET "/var/run/wpa_supplicant"
#define WPA_SUPPLICANT_NUM_RETRIES 20
#define WPA_SUPPLICANT_RETRY_TIME_US 100*1000
static void
remove_link_timeout (struct supplicant *sup)
{
if (sup->link_timeout != NULL)
{
g_source_destroy (sup->link_timeout);
sup->link_timeout = NULL;
}
}
static void
supplicant_remove_timeout (struct supplicant *sup)
{
/* Remove any pending timeouts on the request */
if (sup->timeout != NULL)
{
g_source_destroy (sup->timeout);
sup->timeout = NULL;
}
}
static char *
supplicant_get_device_socket_path (struct supplicant *sup)
{
return g_strdup_printf (WPA_SUPPLICANT_CONTROL_SOCKET "/%s", sup->iface);
}
static void
supplicant_cleanup (struct supplicant *sup)
{
char * sock_path;
if (sup->pid > 0)
{
kill (sup->pid, SIGTERM);
sup->pid = -1;
}
if (sup->watch)
{
g_source_destroy (sup->watch);
sup->watch = NULL;
}
if (sup->status)
{
g_source_destroy (sup->status);
sup->status = NULL;
}
if (sup->ctrl)
{
wpa_ctrl_close (sup->ctrl);
sup->ctrl = NULL;
}
if (sup->stdout)
{
g_source_destroy (sup->stdout);
sup->stdout = NULL;
}
supplicant_remove_timeout (sup);
remove_link_timeout (sup);
/* 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 (sup);
unlink (sock_path);
g_free (sock_path);
}
static void
supplicant_watch_cb (GPid pid,
gint status,
gpointer user_data)
{
struct supplicant *sup = (struct 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");
supplicant_cleanup (sup);
}
/*
* 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)
{
struct supplicant * sup = (struct supplicant *) user_data;
#if 0
/* 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
#endif
{
nm_info ("%s: link timed out.", sup->iface);
sup->state = STATE_DISCONNECTED;
}
return FALSE;
}
#define MESSAGE_LEN 2048
static gboolean
supplicant_status_cb (GIOChannel *source,
GIOCondition condition,
gpointer user_data)
{
struct supplicant * sup = (struct supplicant *) user_data;
char * message;
size_t len;
message = g_malloc (MESSAGE_LEN);
len = MESSAGE_LEN;
wpa_ctrl_recv (sup->ctrl, message, &len);
message[len] = '\0';
if (strstr (message, WPA_EVENT_CONNECTED) != NULL)
{
remove_link_timeout (sup);
/* If this is the initial association during device activation,
* schedule the next activation stage.
*/
if (sup->state == STATE_DEVICE_CONFIG)
{
nm_info ("Activation (%s/wireless) Stage 2 of 5 (Device Configure) "
"successful. Connected to access point '%s'.",
sup->iface, sup->ssid);
supplicant_remove_timeout (sup);
sup->state = STATE_CONNECTED;
}
}
else if (strstr (message, WPA_EVENT_DISCONNECTED) != NULL)
{
if (sup->state == STATE_CONNECTED || sup->state == STATE_DEVICE_CONFIG)
{
/* Start the link timeout so we allow some time for reauthentication */
if (sup->link_timeout == NULL)
{
sup->link_timeout = g_timeout_source_new (8000);
g_source_set_callback (sup->link_timeout, link_timeout_cb, sup, NULL);
g_source_attach (sup->link_timeout, NULL);
}
}
}
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 (struct supplicant *sup)
{
#if 0
if (self->priv->num_freqs > 14)
return NM_SUPPLICANT_TIMEOUT * 2;
#endif
return NM_SUPPLICANT_TIMEOUT;
}
/*
* 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)
{
struct supplicant * sup = (struct supplicant *) user_data;
#if 0
/* 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
#endif
{
nm_info ("Activation (%s/wireless): association took too long (>%us), failing activation.",
sup->iface, get_supplicant_timeout (sup));
if (sup->state == STATE_DEVICE_CONFIG)
sup->state = STATE_DISCONNECTED;
}
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)
{
struct supplicant *sup = (struct supplicant *) 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", sup->pid, start);
start = end + 1;
}
end++;
}
}
g_free (buf);
return retval;
}
static gboolean
supplicant_exec (struct supplicant *sup)
{
gboolean success = FALSE;
char * argv[5];
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] = "-dd";
argv[4] = NULL;
success = g_spawn_async_with_pipes ("/", argv, NULL, 0, NULL, NULL,
&pid, NULL, &sup_stdout, NULL, &error);
if (!success)
{
nm_warning ("Couldn't start wpa_supplicant. Error: (%d) %s", error->code, error->message);
g_error_free (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);
sup->stdout = g_io_create_watch (channel, G_IO_IN | G_IO_ERR);
g_source_set_priority (sup->stdout, G_PRIORITY_LOW);
g_source_set_callback (sup->stdout, (GSourceFunc) supplicant_log_stdout, sup, NULL);
g_source_attach (sup->stdout, NULL);
g_io_channel_unref (channel);
/* Monitor the child process so we know when it stops */
sup->pid = pid;
if (sup->watch)
g_source_destroy (sup->watch);
sup->watch = g_child_watch_source_new (pid);
g_source_set_callback (sup->watch, (GSourceFunc) supplicant_watch_cb, sup, NULL);
g_source_attach (sup->watch, NULL);
}
return success;
}
static gboolean
supplicant_interface_init (struct supplicant *sup)
{
struct wpa_ctrl * ctrl = NULL;
char * socket_path;
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", sup->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 (sup);
while (!sup->ctrl && (tries++ < 10))
sup->ctrl = wpa_ctrl_open (socket_path, NM_RUN_DIR);
g_free (socket_path);
if (!sup->ctrl)
{
nm_info ("Error opening control interface to supplicant.");
goto exit;
}
success = TRUE;
exit:
return success;
}
static gboolean
supplicant_send_network_config (struct supplicant *sup)
{
gboolean success = FALSE;
char * response = NULL;
int nwid;
GSList * elt;
g_assert (sup->ctrl);
/* Tell wpa_supplicant that we'll do the scanning */
if (!nm_utils_supplicant_request_with_check (sup->ctrl, "OK", __func__, NULL, "AP_SCAN %d",
sup->ap_scan))
goto out;
/* Standard network setup info */
if (!(response = nm_utils_supplicant_request (sup->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);
for (elt = sup->options; elt; elt = g_slist_next (elt)) {
struct opt * item = (struct opt *)(elt->data);
if (!nm_utils_supplicant_request_with_check (sup->ctrl, "OK", __func__, NULL,
"SET_NETWORK %i %s %s", nwid, item->key, item->value))
goto out;
}
if (!nm_utils_supplicant_request_with_check (sup->ctrl, "OK", __func__, NULL,
"ENABLE_NETWORK %i", nwid))
goto out;
success = TRUE;
out:
return success;
}
static gboolean
supplicant_monitor_start (struct supplicant *sup)
{
gboolean success = FALSE;
int fd = -1;
GIOChannel * channel;
/* register network event monitor */
if (wpa_ctrl_attach (sup->ctrl) != 0)
goto out;
if ((fd = wpa_ctrl_get_fd (sup->ctrl)) < 0)
goto out;
channel = g_io_channel_unix_new (fd);
sup->status = g_io_create_watch (channel, G_IO_IN);
g_source_set_callback (sup->status, (GSourceFunc) supplicant_status_cb, sup, NULL);
g_source_attach (sup->status, NULL);
/* Set up a timeout on the association to kill it after get_supplicant_time() seconds */
sup->timeout = g_timeout_source_new (get_supplicant_timeout (sup) * 1000);
g_source_set_callback (sup->timeout, supplicant_timeout_cb, sup, NULL);
g_source_attach (sup->timeout, NULL);
success = TRUE;
out:
return success;
}
static gboolean
handle_connect (gpointer user_data)
{
struct supplicant *sup = (struct supplicant *) user_data;
sup->state = STATE_DEVICE_CONFIG;
if (!supplicant_exec (sup))
{
nm_warning ("Activation (%s/wireless): couldn't start the supplicant.",
sup->iface);
g_main_loop_quit (sup->loop);
goto out;
}
if (!supplicant_interface_init (sup))
{
nm_warning ("Activation (%s/wireless): couldn't connect to the supplicant.",
sup->iface);
g_main_loop_quit (sup->loop);
goto out;
}
if (!supplicant_send_network_config (sup))
{
nm_warning ("Activation (%s/wireless): couldn't send wireless configuration"
" to the supplicant.", sup->iface);
g_main_loop_quit (sup->loop);
goto out;
}
if (!supplicant_monitor_start (sup))
{
nm_warning ("Activation (%s/wireless): couldn't monitor the supplicant.",
sup->iface);
g_main_loop_quit (sup->loop);
goto out;
}
out:
return FALSE;
}
static void
parse_config(struct supplicant *sup, const char *file)
{
gboolean success;
GError *err = NULL;
gsize len;
gchar *contents;
gchar **config_lines;
gchar **line;
gboolean in_network = FALSE;
success = g_file_get_contents (file, &contents, &len, &err);
if (!success) {
nm_warning ("Error opening config %s: %s\n", file, err->message);
g_error_free (err);
exit (1);
}
config_lines = g_strsplit (contents, "\n", -1);
g_free (contents);
if (!config_lines) {
nm_warning ("Error reading file contents.\n");
exit (1);
}
for (line = config_lines; *line; line++) {
struct opt * item;
char **vals;
if (!strlen (*line))
continue;
g_strstrip (*line);
/* Ignore comments */
if (*line[0] == '#')
continue;
/* End of first network block; we're done */
if (*line[0] == '}')
break;
vals = g_strsplit (*line, "=", 2);
/* Only accept two values */
if (!vals || !vals[0] || !vals[1] || vals[2]) {
nm_warning ("Bad config line %s.\n", *line);
exit (1);
}
vals[0] = g_strstrip (vals[0]);
vals[1] = g_strstrip (vals[1]);
if ((strcmp (vals[0], "network") == 0) && (strcmp (vals[1], "{") == 0)) {
in_network = TRUE;
} else if (!in_network) {
if (strcmp (vals[0], "ap_scan") == 0) {
sup->ap_scan = atoi (vals[1]);
if (sup->ap_scan < 0 || sup->ap_scan > 2) {
nm_warning ("Bad ap_scan value (not between 0 and 2 inclusive)\n");
exit (1);
}
}
} else {
item = g_malloc0 (sizeof (struct opt));
item->key = g_strdup (vals[0]);
item->value = g_strdup (vals[1]);
if (strcmp (item->key, "ssid") == 0)
sup->ssid = item->value;
sup->options = g_slist_append (sup->options, item);
}
g_strfreev (vals);
}
g_strfreev (config_lines);
{
GSList *elt;
fprintf (stderr, "ap_scan: %d\n", sup->ap_scan);
for (elt = sup->options; elt; elt = g_slist_next (elt)) {
struct opt *item = (struct opt *)(elt->data);
fprintf (stdout, "Key: %s, Value: %s\n", item->key, item->value);
}
}
}
static void
print_usage(const char *prog)
{
gchar *base = g_filename_display_basename (prog);
fprintf (stdout, "Usage: %s <iface> <configfile>\n\n", base);
g_free (base);
}
int
main (int argc, char **argv)
{
struct supplicant *sup;
if (argc != 3) {
print_usage(argv[0]);
exit(1);
}
sup = g_malloc0 (sizeof (struct supplicant));
sup->ap_scan = 2;
sup->loop = g_main_loop_new (NULL, FALSE);
sup->iface = g_strdup (argv[1]);
sup->state = STATE_DISCONNECTED;
parse_config (sup, argv[2]);
g_idle_add (handle_connect, sup);
g_main_loop_run (sup->loop);
supplicant_cleanup (sup);
g_free (sup->iface);
g_free (sup);
return 0;
}