From cdaa2829f53e2476bab667fd2330cde19bdfb7b4 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 1 Jan 2008 05:22:46 +0100 Subject: [PATCH] Add experimental supplicant support --- plugins/supplicant.c | 233 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 230 insertions(+), 3 deletions(-) diff --git a/plugins/supplicant.c b/plugins/supplicant.c index b83f290..ec0b7e7 100644 --- a/plugins/supplicant.c +++ b/plugins/supplicant.c @@ -24,26 +24,253 @@ #endif #include +#include +#include +#include +#include +#include +#include +#include +#include + +#include #include "supplicant.h" +struct supplicant_task { + GPid pid; + int ifindex; + char *ifname; + struct connman_iface *iface; + int socket; + GIOChannel *channel; +}; + +static GSList *tasks = NULL; + +static struct supplicant_task *find_task(int ifindex) +{ + GSList *list; + + for (list = tasks; list; list = list->next) { + struct supplicant_task *task = list->data; + + if (task->ifindex == ifindex) + return task; + } + + return NULL; +} + +static int exec_cmd(struct supplicant_task *task, char *cmd) +{ + write(task->socket, cmd, strlen(cmd)); + + return 0; +} + +static gboolean control_event(GIOChannel *chan, + GIOCondition cond, gpointer data) +{ + struct supplicant_task *task = data; + char buf[256]; + gsize len; + GIOError err; + + if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) { + g_io_channel_unref(chan); + return FALSE; + } + + memset(buf, 0, sizeof(buf)); + + err = g_io_channel_read(chan, buf, sizeof(buf), &len); + if (err) { + if (err == G_IO_ERROR_AGAIN) + return TRUE; + g_io_channel_unref(chan); + return FALSE; + } + + if (buf[0] != '<') + return TRUE; + + printf("[SUPPLICANT] %s\n", buf + 3); + + if (g_str_has_prefix(buf + 3, "CTRL-EVENT-CONNECTED") == TRUE) { + printf("[SUPPLICANT] connected\n"); + connman_iface_update(task->iface, + CONNMAN_IFACE_STATE_CONNECTED); + } + + if (g_str_has_prefix(buf + 3, "CTRL-EVENT-DISCONNECTED") == TRUE) { + printf("[SUPPLICANT] disconnected\n"); + } + + if (g_str_has_prefix(buf + 3, "CTRL-EVENT-TERMINATING") == TRUE) { + printf("[SUPPLICANT] terminating\n"); + } + + return TRUE; +} + +static int open_control(struct supplicant_task *task) +{ + struct sockaddr_un addr; + int sk; + + printf("[SUPPLICANT] open control for %s\n", task->ifname); + + sk = socket(PF_UNIX, SOCK_DGRAM, 0); + if (sk < 0) + return -1; + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, sizeof(addr.sun_path), + "%s/%s.cli", STATEDIR, task->ifname); + //unlink(addr.sun_path); + + if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + close(sk); + return -1; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, sizeof(addr.sun_path), + "%s/%s", STATEDIR, task->ifname); + + if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + close(sk); + return -1; + } + + task->socket = sk; + + task->channel = g_io_channel_unix_new(sk); + g_io_channel_set_close_on_unref(task->channel, TRUE); + + g_io_add_watch(task->channel, + G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR, + control_event, task); + + exec_cmd(task, "ATTACH"); + exec_cmd(task, "ADD_NETWORK"); + + g_io_channel_unref(task->channel); + + return 0; +} + int __supplicant_start(struct connman_iface *iface) { - printf("[SUPPLICANT] start for index %d\n", iface->index); + struct ifreq ifr; + struct supplicant_task *task; + char *argv[9]; + int sk, err; + + sk = socket(PF_INET, SOCK_DGRAM, 0); + if (sk < 0) + return -EIO; + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_ifindex = iface->index; + + err = ioctl(sk, SIOCGIFNAME, &ifr); + + close(sk); + + if (err < 0) + return -EIO; + + printf("[SUPPLICANT] start %s\n", ifr.ifr_name); + + task = g_try_new0(struct supplicant_task, 1); + if (task == NULL) + return -ENOMEM; + + task->ifindex = iface->index; + task->ifname = strdup(ifr.ifr_name); + task->iface = iface; + + if (task->ifname == NULL) { + g_free(task); + return -ENOMEM; + } + + argv[0] = "/sbin/wpa_supplicant"; + argv[1] = "-qq"; + argv[2] = "-C"; + argv[3] = STATEDIR; + argv[4] = "-D"; + argv[5] = "wext"; + argv[6] = "-i"; + argv[7] = task->ifname; + argv[8] = NULL; + + if (g_spawn_async(NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, + NULL, NULL, &task->pid, NULL) == FALSE) { + printf("Failed to spawn wpa_supplicant\n"); + return -1; + } + + tasks = g_slist_append(tasks, task); + + printf("[SUPPLICANT] executed with pid %d\n", task->pid); + + sleep(1); + + task->socket = -1; + + if (open_control(task) < 0) + printf("[SUPPLICANT] control failed\n"); return 0; } int __supplicant_stop(struct connman_iface *iface) { - printf("[SUPPLICANT] stop for index %d\n", iface->index); + struct supplicant_task *task; + char pathname[PATH_MAX]; + + task = find_task(iface->index); + if (task == NULL) + return -ENODEV; + + printf("[SUPPLICANT] stop %s\n", task->ifname); + + tasks = g_slist_remove(tasks, task); + + exec_cmd(task, "DETACH"); + + //close(task->socket); + g_io_channel_unref(task->channel); + + snprintf(pathname, sizeof(pathname), + "%s/%s.cli", STATEDIR, task->ifname); + unlink(pathname); + + kill(task->pid, SIGTERM); + + free(task->ifname); + + g_free(task); return 0; } int __supplicant_connect(struct connman_iface *iface) { - printf("[SUPPLICANT] connect for index %d\n", iface->index); + struct supplicant_task *task; + + task = find_task(iface->index); + if (task == NULL) + return -ENODEV; + + printf("[SUPPLICANT] connect %s\n", task->ifname); + + exec_cmd(task, "DISABLE_NETWORK 0"); return 0; } -- 2.7.4