summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2008-03-12 14:51:59 +0100
committerMarcel Holtmann <marcel@holtmann.org>2008-03-12 14:51:59 +0100
commit451d80c342f0ed95363b7056221544207323bbaa (patch)
tree9de5339bc5c8c3676ab7b12c85cc3d9ccdfe7f16
parentc1fdd4bf06398f2b277bd5d8e5a11cadba6508b8 (diff)
downloadconnman-451d80c342f0ed95363b7056221544207323bbaa.tar.gz
connman-451d80c342f0ed95363b7056221544207323bbaa.tar.bz2
connman-451d80c342f0ed95363b7056221544207323bbaa.zip
Change 802.11 plugin to use D-Bus interface of supplicant
-rw-r--r--plugins/80211.c432
-rw-r--r--plugins/supplicant.c903
-rw-r--r--plugins/supplicant.h6
3 files changed, 792 insertions, 549 deletions
diff --git a/plugins/80211.c b/plugins/80211.c
index 1bada4fc..d21eec64 100644
--- a/plugins/80211.c
+++ b/plugins/80211.c
@@ -43,156 +43,10 @@
#include "supplicant.h"
-#ifndef IW_EV_LCP_PK_LEN
-#define IW_EV_LCP_PK_LEN (4)
-#endif
-
-struct station_data {
- char *address;
- char *name;
- int mode;
- int qual;
- int noise;
- int level;
-
- unsigned char wpa_ie[40];
- int wpa_ie_len;
- unsigned char rsn_ie[40];
- int rsn_ie_len;
-
- int has_wep;
- int has_wpa;
- int has_rsn;
-};
-
struct iface_data {
char ifname[IFNAMSIZ];
- GSList *stations;
-
- gchar *network;
- gchar *passphrase;
};
-static void report_station(struct connman_iface *iface,
- struct station_data *station)
-{
- int security = 0;
-
- if (station == NULL)
- return;
-
- if (station->name == NULL)
- return;
-
- if (station->has_wep)
- security |= 0x01;
- if (station->has_wpa)
- security |= 0x02;
- if (station->has_rsn)
- security |= 0x04;
-
- connman_iface_indicate_station(iface, station->name,
- station->qual, security);
-}
-
-static struct station_data *create_station(struct iface_data *iface,
- const char *address)
-{
- struct station_data *station;
- GSList *list;
-
- for (list = iface->stations; list; list = list->next) {
- station = list->data;
-
- if (g_ascii_strcasecmp(station->address, address) == 0)
- return station;
- }
-
- station = g_try_new0(struct station_data, 1);
- if (station == NULL)
- return NULL;
-
- station->address = g_strdup(address);
- if (station->address == NULL) {
- g_free(station);
- return NULL;
- }
-
- iface->stations = g_slist_append(iface->stations, station);
-
- return station;
-}
-
-static void load_stations(struct iface_data *iface)
-{
- GKeyFile *keyfile;
- gchar **groups, **group;
- gsize length;
-
- keyfile = g_key_file_new();
-
- if (g_key_file_load_from_file(keyfile, "/tmp/stations.list",
- G_KEY_FILE_KEEP_COMMENTS, NULL) == FALSE)
- goto done;
-
- groups = g_key_file_get_groups(keyfile, &length);
-
- for (group = groups; *group; group++) {
- struct station_data *station;
-
- station = create_station(iface, *group);
- if (station == NULL)
- continue;
-
- station->name = g_key_file_get_string(keyfile,
- *group, "Name", NULL);
-
- station->mode = g_key_file_get_integer(keyfile,
- *group, "Mode", NULL);
- }
-
- g_strfreev(groups);
-
-done:
- g_key_file_free(keyfile);
-
- printf("[802.11] loaded %d stations\n",
- g_slist_length(iface->stations));
-}
-
-static void print_stations(struct iface_data *iface)
-{
- GKeyFile *keyfile;
- gchar *data;
- gsize length;
- GSList *list;
-
- keyfile = g_key_file_new();
-
- for (list = iface->stations; list; list = list->next) {
- struct station_data *station = list->data;
-
- //printf("Address:%s Mode:%d ESSID:\"%s\" Quality:%d/100\n",
- // station->address, station->mode,
- // station->name, station->qual);
-
- if (station->name == NULL)
- continue;
-
- g_key_file_set_string(keyfile, station->address,
- "Name", station->name);
-
- g_key_file_set_integer(keyfile, station->address,
- "Mode", station->mode);
- }
-
- data = g_key_file_to_data(keyfile, &length, NULL);
-
- g_file_set_contents("/tmp/stations.list", data, length, NULL);
-
- g_key_file_free(keyfile);
-}
-
static int wifi_probe(struct connman_iface *iface)
{
struct iface_data *data;
@@ -231,8 +85,6 @@ static int wifi_probe(struct connman_iface *iface)
connman_iface_set_data(iface, data);
- load_stations(data);
-
return 0;
}
@@ -246,9 +98,6 @@ static void wifi_remove(struct connman_iface *iface)
connman_iface_set_data(iface, NULL);
- g_free(data->network);
- g_free(data->passphrase);
-
free(data);
}
@@ -277,36 +126,12 @@ static int wifi_stop(struct connman_iface *iface)
static int wifi_scan(struct connman_iface *iface)
{
struct iface_data *data = connman_iface_get_data(iface);
- struct iwreq iwr;
- struct iw_scan_req iws;
- int sk, err;
DBG("iface %p %s", iface, data->ifname);
- sk = socket(PF_INET, SOCK_DGRAM, 0);
- if (sk < 0)
- return -EIO;
-
- memset(&iws, 0, sizeof(iws));
- iws.scan_type = IW_SCAN_TYPE_PASSIVE;
- //iws.scan_type = IW_SCAN_TYPE_ACTIVE;
-
- memset(&iwr, 0, sizeof(iwr));
- strncpy(iwr.ifr_name, data->ifname, IFNAMSIZ);
+ __supplicant_scan(iface);
- iwr.u.data.pointer = (caddr_t ) &iws;
- iwr.u.data.length = sizeof(iws);
- iwr.u.data.flags = IW_SCAN_DEFAULT;
-
- err = ioctl(sk, SIOCSIWSCAN, &iwr);
-
- close(sk);
-
- if (err < 0)
- connman_error("%s: scan initiate error %d",
- data->ifname, errno);
-
- return err;
+ return 0;
}
static int wifi_connect(struct connman_iface *iface,
@@ -316,8 +141,7 @@ static int wifi_connect(struct connman_iface *iface,
DBG("iface %p %s", iface, data->ifname);
- if (data->network != NULL)
- __supplicant_connect(iface, data->network, data->passphrase);
+ __supplicant_connect(iface, network->identifier, network->passphrase);
return 0;
}
@@ -328,256 +152,11 @@ static int wifi_disconnect(struct connman_iface *iface)
DBG("iface %p %s", iface, data->ifname);
- if (data->network != NULL)
- __supplicant_disconnect(iface);
+ __supplicant_disconnect(iface);
return 0;
}
-static void wifi_set_network(struct connman_iface *iface,
- const char *network)
-{
- struct iface_data *data = connman_iface_get_data(iface);
-
- DBG("iface %p %s", iface, data->ifname);
-
- g_free(data->network);
-
- data->network = g_strdup(network);
-}
-
-static void wifi_set_passphrase(struct connman_iface *iface,
- const char *passphrase)
-{
- struct iface_data *data = connman_iface_get_data(iface);
-
- DBG("iface %p %s", iface, data->ifname);
-
- g_free(data->passphrase);
-
- data->passphrase = g_strdup(passphrase);
-}
-
-static void parse_genie(struct station_data *station,
- unsigned char *data, int len)
-{
- int offset = 0;
-
- while (offset <= len - 2) {
- //int i;
-
- switch (data[offset]) {
- case 0xdd: /* WPA1 (and other) */
- station->has_wpa = 1;
- break;
- case 0x30: /* WPA2 (RSN) */
- station->has_rsn = 1;
- break;
- default:
- break;
- }
-
- //for (i = 0; i < len; i++)
- // printf(" %02x", data[i]);
- //printf("\n");
-
- offset += data[offset + 1] + 2;
- }
-}
-
-static void parse_scan_results(struct connman_iface *iface,
- unsigned char *data, int len)
-{
- unsigned char *ptr = data;
- struct station_data *station = NULL;
- struct ether_addr *eth;
- char addr[18];
- int num = 0;
-
- while (len > IW_EV_LCP_PK_LEN) {
- struct iw_event *event = (void *) ptr;
-
- switch (event->cmd) {
- case SIOCGIWAP:
- report_station(iface, station);
- eth = (void *) &event->u.ap_addr.sa_data;
- sprintf(addr, "%02X:%02X:%02X:%02X:%02X:%02X",
- eth->ether_addr_octet[0],
- eth->ether_addr_octet[1],
- eth->ether_addr_octet[2],
- eth->ether_addr_octet[3],
- eth->ether_addr_octet[4],
- eth->ether_addr_octet[5]);
- station = create_station(connman_iface_get_data(iface),
- addr);
- num++;
- break;
- case SIOCGIWESSID:
- if (station != NULL) {
- station->name = malloc(event->len - IW_EV_POINT_LEN + 1);
- if (station->name != NULL) {
- memset(station->name, 0,
- event->len - IW_EV_POINT_LEN + 1);
- memcpy(station->name, ptr + IW_EV_POINT_LEN,
- event->len - IW_EV_POINT_LEN);
- }
- }
- break;
- case SIOCGIWNAME:
- break;
- case SIOCGIWMODE:
- if (station != NULL)
- station->mode = event->u.mode;
- break;
- case SIOCGIWFREQ:
- break;
- case SIOCGIWENCODE:
- if (station != NULL) {
- if (!event->u.data.pointer)
- event->u.data.flags |= IW_ENCODE_NOKEY;
-
- if (!(event->u.data.flags & IW_ENCODE_DISABLED))
- station->has_wep = 1;
- }
- break;
- case SIOCGIWRATE:
- break;
- case IWEVQUAL:
- if (station != NULL) {
- station->qual = event->u.qual.qual;
- station->noise = event->u.qual.noise;
- station->level = event->u.qual.level;
- }
- break;
- case IWEVGENIE:
- if (station != NULL)
- parse_genie(station, ptr + 8, event->len - 8);
- break;
- case IWEVCUSTOM:
- break;
- default:
- printf("[802.11] scan element 0x%04x (len %d)\n",
- event->cmd, event->len);
- if (event->len == 0)
- len = 0;
- break;
- }
-
- ptr += event->len;
- len -= event->len;
- }
-
- report_station(iface, station);
-
- printf("[802.11] found %d networks\n", num);
-}
-
-static void scan_results(struct connman_iface *iface)
-{
- struct iface_data *data = connman_iface_get_data(iface);
- struct iwreq iwr;
- void *buf;
- size_t size;
- int sk, err, done = 0;
-
- if (data == NULL)
- return;
-
- memset(&iwr, 0, sizeof(iwr));
- memcpy(iwr.ifr_name, data->ifname, IFNAMSIZ);
-
- sk = socket(PF_INET, SOCK_DGRAM, 0);
- if (sk < 0)
- return;
-
- buf = NULL;
- size = 1024;
-
- while (!done) {
- void *newbuf;
-
- newbuf = g_realloc(buf, size);
- if (newbuf == NULL) {
- close(sk);
- return;
- }
-
- buf = newbuf;
- iwr.u.data.pointer = buf;
- iwr.u.data.length = size;
- iwr.u.data.flags = 0;
-
- err = ioctl(sk, SIOCGIWSCAN, &iwr);
- if (err < 0) {
- if (errno == E2BIG)
- size *= 2;
- else
- done = 1;
- } else {
- parse_scan_results(iface, iwr.u.data.pointer,
- iwr.u.data.length);
- done = 1;
- }
- }
-
- g_free(buf);
-
- close(sk);
-
- print_stations(data);
-}
-
-static void wifi_wireless(struct connman_iface *iface,
- void *data, unsigned short len)
-{
- struct iw_event *event = data;
- struct iw_point point;
- struct ether_addr *eth;
- char addr[18];
-
- switch (event->cmd) {
- case SIOCSIWFREQ:
- printf("[802.11] Set Frequency (flags %d)\n",
- event->u.freq.flags);
- break;
- case SIOCSIWMODE:
- printf("[802.11] Set Mode (mode %d)\n", event->u.mode);
- break;
- case SIOCSIWESSID:
- memcpy(&point, data + IW_EV_LCP_LEN -
- IW_EV_POINT_OFF, sizeof(point));
- point.pointer = data + IW_EV_LCP_LEN +
- sizeof(point) - IW_EV_POINT_OFF;
- printf("[802.11] Set ESSID (length %d flags %d) \"%s\"\n",
- point.length, point.flags,
- (char *) point.pointer);
- break;
- case SIOCSIWENCODE:
- printf("[802.11] Set Encryption key (flags %d)\n",
- event->u.data.flags);
- break;
-
- case SIOCGIWAP:
- eth = (void *) &event->u.ap_addr.sa_data;
- sprintf(addr, "%02X:%02X:%02X:%02X:%02X:%02X",
- eth->ether_addr_octet[0],
- eth->ether_addr_octet[1],
- eth->ether_addr_octet[2],
- eth->ether_addr_octet[3],
- eth->ether_addr_octet[4],
- eth->ether_addr_octet[5]);
- printf("[802.11] New Access Point %s\n", addr);
- break;
- case SIOCGIWSCAN:
- scan_results(iface);
- break;
- default:
- printf("[802.11] Wireless event (cmd 0x%04x len %d)\n",
- event->cmd, event->len);
- break;
- }
-}
-
static struct connman_iface_driver wifi_driver = {
.name = "80211",
.capability = "net.80211",
@@ -588,9 +167,6 @@ static struct connman_iface_driver wifi_driver = {
.scan = wifi_scan,
.connect = wifi_connect,
.disconnect = wifi_disconnect,
- .set_network = wifi_set_network,
- .set_passphrase = wifi_set_passphrase,
- .rtnl_wireless = wifi_wireless,
};
static int wifi_init(void)
diff --git a/plugins/supplicant.c b/plugins/supplicant.c
index b30b16cb..c8853e12 100644
--- a/plugins/supplicant.c
+++ b/plugins/supplicant.c
@@ -33,21 +33,62 @@
#include <sys/un.h>
#include <net/if.h>
-#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus.h>
+
+#include <connman/log.h>
#include "supplicant.h"
+enum supplicant_state {
+ STATE_INACTIVE,
+ STATE_SCANNING,
+ STATE_ASSOCIATING,
+ STATE_ASSOCIATED,
+ STATE_4WAY_HANDSHAKE,
+ STATE_GROUP_HANDSHAKE,
+ STATE_COMPLETED,
+ STATE_DISCONNECTED,
+};
+
+// COMPLETED ==> ASSOCIATING
+// ASSOCIATED ==> DISCONNECTED
+// DISCONNECTED ==> INACTIVE
+
+// DISCONNECTED ==> SCANNING
+// SCANNING ==> ASSOCIATED
+
+// ASSOCIATING ==> ASSOCIATED
+// ASSOCIATED ==> 4WAY_HANDSHAKE
+// 4WAY_HANDSHAKE ==> GROUP_HANDSHAKE
+// GROUP_HANDSHAKE ==> COMPLETED
+
struct supplicant_task {
- GPid pid;
+ DBusConnection *conn;
int ifindex;
- char *ifname;
+ gchar *ifname;
struct connman_iface *iface;
- int socket;
- GIOChannel *channel;
+ gchar *path;
+ gboolean created;
+ gchar *network;
+ enum supplicant_state state;
};
static GSList *tasks = NULL;
+struct supplicant_ap {
+ gchar *identifier;
+ GByteArray *ssid;
+ guint capabilities;
+ gboolean has_wep;
+ gboolean has_wpa;
+ gboolean has_rsn;
+};
+
+#define IEEE80211_CAP_ESS 0x0001
+#define IEEE80211_CAP_IBSS 0x0002
+#define IEEE80211_CAP_PRIVACY 0x0010
+
static struct supplicant_task *find_task(int ifindex)
{
GSList *list;
@@ -62,95 +103,715 @@ static struct supplicant_task *find_task(int ifindex)
return NULL;
}
-static int exec_cmd(struct supplicant_task *task, char *cmd)
+static int get_interface(struct supplicant_task *task)
{
- return write(task->socket, cmd, strlen(cmd));
+ DBusMessage *message, *reply;
+ DBusError error;
+ const char *path;
+
+ DBG("task %p", task);
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
+ SUPPLICANT_INTF, "getInterface");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_message_append_args(message, DBUS_TYPE_STRING, &task->ifname,
+ DBUS_TYPE_INVALID);
+
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(task->conn,
+ message, -1, &error);
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to get interface");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_message_unref(message);
+
+ dbus_error_init(&error);
+
+ if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID) == FALSE) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Wrong arguments for interface");
+ dbus_message_unref(reply);
+ return -EIO;
+ }
+
+ DBG("path %s", path);
+
+ task->path = g_strdup(path);
+ task->created = FALSE;
+
+ dbus_message_unref(reply);
+
+ return 0;
}
-static gboolean control_event(GIOChannel *chan,
- GIOCondition cond, gpointer data)
+static int add_interface(struct supplicant_task *task)
{
- struct supplicant_task *task = data;
- char buf[256];
- gsize len;
- GIOError err;
+ DBusMessage *message, *reply;
+ DBusError error;
+ const char *path;
+
+ DBG("task %p", task);
- if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
- return FALSE;
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, SUPPLICANT_PATH,
+ SUPPLICANT_INTF, "addInterface");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_error_init(&error);
- memset(buf, 0, sizeof(buf));
+ dbus_message_append_args(message, DBUS_TYPE_STRING, &task->ifname,
+ DBUS_TYPE_INVALID);
- err = g_io_channel_read(chan, buf, sizeof(buf), &len);
- if (err) {
- if (err == G_IO_ERROR_AGAIN)
- return TRUE;
- return FALSE;
+ reply = dbus_connection_send_with_reply_and_block(task->conn,
+ message, -1, &error);
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to add interface");
+ dbus_message_unref(message);
+ return -EIO;
}
- if (buf[0] != '<')
- return TRUE;
+ dbus_message_unref(message);
- printf("[SUPPLICANT] %s\n", buf + 3);
+ dbus_error_init(&error);
- if (g_str_has_prefix(buf + 3, "CTRL-EVENT-CONNECTED") == TRUE) {
- printf("[SUPPLICANT] connected\n");
- connman_iface_indicate_connected(task->iface);
+ if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID) == FALSE) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Wrong arguments for interface");
+ dbus_message_unref(reply);
+ return -EIO;
}
- if (g_str_has_prefix(buf + 3, "CTRL-EVENT-DISCONNECTED") == TRUE) {
- printf("[SUPPLICANT] disconnected\n");
+ DBG("path %s", path);
+
+ task->path = g_strdup(path);
+ task->created = TRUE;
+
+ dbus_message_unref(reply);
+
+ return 0;
+}
+
+static int add_network(struct supplicant_task *task)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
+ const char *path;
+
+ DBG("task %p", task);
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
+ SUPPLICANT_INTF ".Interface", "addNetwork");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(task->conn,
+ message, -1, &error);
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to add network");
+ dbus_message_unref(message);
+ return -EIO;
}
- if (g_str_has_prefix(buf + 3, "CTRL-EVENT-TERMINATING") == TRUE) {
- printf("[SUPPLICANT] terminating\n");
+ dbus_message_unref(message);
+
+ dbus_error_init(&error);
+
+ if (dbus_message_get_args(reply, &error, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID) == FALSE) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Wrong arguments for network");
+ dbus_message_unref(reply);
+ return -EIO;
}
- return TRUE;
+ DBG("path %s", path);
+
+ task->network = g_strdup(path);
+
+ dbus_message_unref(reply);
+
+ return 0;
}
-static int open_control(struct supplicant_task *task)
+static int remove_network(struct supplicant_task *task)
{
- struct sockaddr_un addr;
- int sk;
+ DBusMessage *message, *reply;
+ DBusError error;
- printf("[SUPPLICANT] open control for %s\n", task->ifname);
+ DBG("task %p", task);
- sk = socket(PF_UNIX, SOCK_DGRAM, 0);
- if (sk < 0)
- return -1;
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
+ SUPPLICANT_INTF ".Interface", "removeNetwork");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->network,
+ DBUS_TYPE_INVALID);
+
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(task->conn,
+ message, -1, &error);
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to remove network");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_message_unref(message);
+
+ dbus_message_unref(reply);
+
+ return 0;
+}
+
+static int select_network(struct supplicant_task *task)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
- 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);
+ DBG("task %p", task);
- if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- close(sk);
- return -1;
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
+ SUPPLICANT_INTF ".Interface", "selectNetwork");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->network,
+ DBUS_TYPE_INVALID);
+
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(task->conn,
+ message, -1, &error);
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to select network");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_message_unref(message);
+
+ dbus_message_unref(reply);
+
+ return 0;
+}
+
+static int enable_network(struct supplicant_task *task)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
+
+ DBG("task %p", task);
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, task->network,
+ SUPPLICANT_INTF ".Network", "enable");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(task->conn,
+ message, -1, &error);
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to enable network");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_message_unref(message);
+
+ dbus_message_unref(reply);
+
+ return 0;
+}
+
+static int disable_network(struct supplicant_task *task)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
+
+ DBG("task %p", task);
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, task->network,
+ SUPPLICANT_INTF ".Network", "disable");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(task->conn,
+ message, -1, &error);
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to disable network");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_message_unref(message);
+
+ dbus_message_unref(reply);
+
+ return 0;
+}
+
+static void append_entry(DBusMessageIter *dict,
+ const char *key, int type, void *val)
+{
+ DBusMessageIter entry, value;
+ const char *signature;
+
+ dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+ switch (type) {
+ case DBUS_TYPE_STRING:
+ signature = DBUS_TYPE_STRING_AS_STRING;
+ break;
+ case DBUS_TYPE_UINT16:
+ signature = DBUS_TYPE_UINT16_AS_STRING;
+ break;
+ default:
+ signature = DBUS_TYPE_VARIANT_AS_STRING;
+ break;
}
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- snprintf(addr.sun_path, sizeof(addr.sun_path),
- "%s/%s", STATEDIR, task->ifname);
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+ signature, &value);
+ dbus_message_iter_append_basic(&value, type, val);
+ dbus_message_iter_close_container(&entry, &value);
+
+ dbus_message_iter_close_container(dict, &entry);
+}
- if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- close(sk);
- return -1;
+static int set_network(struct supplicant_task *task, const char *network,
+ const char *passphrase)
+{
+ DBusMessage *message, *reply;
+ DBusMessageIter array, dict;
+ DBusError error;
+
+ DBG("task %p", task);
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, task->network,
+ SUPPLICANT_INTF ".Network", "set");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_message_iter_init_append(message, &array);
+
+ dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ append_entry(&dict, "ssid", DBUS_TYPE_STRING, &network);
+
+ if (passphrase && strlen(passphrase) > 0) {
+ //exec_cmd(task, "SET_NETWORK 0 proto RSN WPA");
+ //exec_cmd(task, "SET_NETWORK 0 key_mgmt WPA-PSK");
+
+ append_entry(&dict, "psk", DBUS_TYPE_STRING, &passphrase);
+ } else {
+ //exec_cmd(task, "SET_NETWORK 0 proto RSN WPA");
+ //exec_cmd(task, "SET_NETWORK 0 key_mgmt NONE");
}
- task->socket = sk;
+ dbus_message_iter_close_container(&array, &dict);
- task->channel = g_io_channel_unix_new(sk);
- g_io_channel_set_close_on_unref(task->channel, TRUE);
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(task->conn,
+ message, -1, &error);
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to set network options");
+ dbus_message_unref(message);
+ return -EIO;
+ }
- g_io_add_watch(task->channel,
- G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
- control_event, task);
+ dbus_message_unref(message);
- exec_cmd(task, "ATTACH");
- exec_cmd(task, "ADD_NETWORK");
+ dbus_message_unref(reply);
+
+ return 0;
+}
+
+static int initiate_scan(struct supplicant_task *task)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
+
+ DBG("task %p", task);
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
+ SUPPLICANT_INTF ".Interface", "scan");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(task->conn,
+ message, -1, &error);
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to initiate scan");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_message_unref(message);
+
+ dbus_message_unref(reply);
+
+ return 0;
+}
+
+static void extract_ssid(struct supplicant_ap *ap, DBusMessageIter *value)
+{
+ DBusMessageIter array;
+ unsigned char *ssid;
+ int ssid_len;
+
+ dbus_message_iter_recurse(value, &array);
+ dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
+
+ ap->identifier = g_strdup((char *) ssid);
+}
+
+static void extract_wpaie(struct supplicant_ap *ap, DBusMessageIter *value)
+{
+ DBusMessageIter array;
+ unsigned char *ie;
+ int ie_len;
+
+ dbus_message_iter_recurse(value, &array);
+ dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
+
+ if (ie_len > 0)
+ ap->has_wpa = TRUE;
+}
+
+static void extract_rsnie(struct supplicant_ap *ap, DBusMessageIter *value)
+{
+ DBusMessageIter array;
+ unsigned char *ie;
+ int ie_len;
+
+ dbus_message_iter_recurse(value, &array);
+ dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
+
+ if (ie_len > 0)
+ ap->has_rsn = TRUE;
+}
+
+static void extract_capabilites(struct supplicant_ap *ap,
+ DBusMessageIter *value)
+{
+ guint capabilities;
+
+ dbus_message_iter_get_basic(value, &capabilities);
+
+ ap->capabilities = capabilities;
+
+ if (capabilities & IEEE80211_CAP_PRIVACY)
+ ap->has_wep = TRUE;
+}
+
+static int parse_network_properties(struct supplicant_task *task,
+ DBusMessage *message)
+{
+ DBusMessageIter array, dict;
+ struct supplicant_ap *ap;
+ int security = 0;
+
+ DBG("task %p", task);
+
+ ap = g_try_new0(struct supplicant_ap, 1);
+ if (ap == NULL)
+ return -ENOMEM;
+
+ dbus_message_iter_init(message, &array);
+
+ dbus_message_iter_recurse(&array, &dict);
+
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+ const char *key;
+
+ dbus_message_iter_recurse(&dict, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+
+ dbus_message_iter_next(&entry);
+
+ dbus_message_iter_recurse(&entry, &value);
+
+ //type = dbus_message_iter_get_arg_type(&value);
+ //dbus_message_iter_get_basic(&value, &val);
+
+ if (g_str_equal(key, "ssid") == TRUE)
+ extract_ssid(ap, &value);
+ else if (g_str_equal(key, "wpaie") == TRUE)
+ extract_wpaie(ap, &value);
+ else if (g_str_equal(key, "rsnie") == TRUE)
+ extract_rsnie(ap, &value);
+ else if (g_str_equal(key, "capabilities") == TRUE)
+ extract_capabilites(ap, &value);
+
+ dbus_message_iter_next(&dict);
+ }
+
+ DBG("SSID %s", ap->identifier);
+
+ if (ap->has_wep)
+ security |= 0x01;
+ if (ap->has_wpa)
+ security |= 0x02;
+ if (ap->has_rsn)
+ security |= 0x04;
+
+ connman_iface_indicate_station(task->iface,
+ ap->identifier, 25, security);
+
+ g_free(ap);
+
+ return 0;
+}
+
+static int get_network_properties(struct supplicant_task *task,
+ const char *path)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
+
+ DBG("task %p", task);
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, path,
+ SUPPLICANT_INTF ".BSSID",
+ "properties");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(task->conn,
+ message, -1, &error);
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to get network properties");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_message_unref(message);
+
+ parse_network_properties(task, reply);
+
+ dbus_message_unref(reply);
+
+ return 0;
+}
+
+static int scan_results_available(struct supplicant_task *task)
+{
+ DBusMessage *message, *reply;
+ DBusError error;
+ char **results;
+ int i, num_results;
+
+ DBG("task %p", task);
+
+ message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path,
+ SUPPLICANT_INTF ".Interface",
+ "scanResults");
+ if (message == NULL)
+ return -ENOMEM;
+
+ dbus_error_init(&error);
+
+ reply = dbus_connection_send_with_reply_and_block(task->conn,
+ message, -1, &error);
+ if (reply == NULL) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Failed to request scan result");
+ dbus_message_unref(message);
+ return -EIO;
+ }
+
+ dbus_message_unref(message);
+
+ dbus_error_init(&error);
+
+ if (dbus_message_get_args(reply, &error,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
+ &results, &num_results,
+ DBUS_TYPE_INVALID) == FALSE) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Wrong arguments for scan result");
+ dbus_message_unref(reply);
+ return -EIO;
+ }
+
+ for (i = 0; i < num_results; i++)
+ get_network_properties(task, results[i]);
+
+ g_strfreev(results);
+
+ dbus_message_unref(reply);
+
+ return 0;
+}
+
+static void state_change(struct supplicant_task *task, DBusMessage *msg)
+{
+ DBusError error;
+ const char *state, *previous;
+
+ dbus_error_init(&error);
+
+ if (dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &state,
+ DBUS_TYPE_STRING, &previous,
+ DBUS_TYPE_INVALID) == FALSE) {
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("%s", error.message);
+ dbus_error_free(&error);
+ } else
+ connman_error("Wrong arguments for state change");
+ return;
+ }
+
+ DBG("state %s ==> %s", previous, state);
+
+ if (g_str_equal(state, "INACTIVE") == TRUE)
+ task->state = STATE_INACTIVE;
+ else if (g_str_equal(state, "SCANNING") == TRUE)
+ task->state = STATE_SCANNING;
+ else if (g_str_equal(state, "ASSOCIATING") == TRUE)
+ task->state = STATE_ASSOCIATING;
+ else if (g_str_equal(state, "ASSOCIATED") == TRUE)
+ task->state = STATE_ASSOCIATED;
+ else if (g_str_equal(state, "GROUP_HANDSHAKE") == TRUE)
+ task->state = STATE_4WAY_HANDSHAKE;
+ else if (g_str_equal(state, "4WAY_HANDSHAKE") == TRUE)
+ task->state = STATE_4WAY_HANDSHAKE;
+ else if (g_str_equal(state, "COMPLETED") == TRUE)
+ task->state = STATE_COMPLETED;
+ else if (g_str_equal(state, "DISCONNECTED") == TRUE)
+ task->state = STATE_DISCONNECTED;
+}
+
+static DBusHandlerResult supplicant_filter(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct supplicant_task *task = data;
+ const char *member;
+
+ if (dbus_message_has_interface(msg,
+ SUPPLICANT_INTF ".Interface") == FALSE)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ member = dbus_message_get_member(msg);
+ if (member == NULL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ DBG("task %p member %s", task, member);
+
+ if (g_str_equal(member, "ScanResultsAvailable") == TRUE)
+ scan_results_available(task);
+ else if (g_str_equal(member, "StateChange") == TRUE)
+ state_change(task, msg);
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static int add_filter(struct supplicant_task *task)
+{
+ DBusError error;
+ gchar *filter;
+
+ if (dbus_connection_add_filter(task->conn,
+ supplicant_filter, task, NULL) == FALSE)
+ return -EIO;
+
+ filter = g_strdup_printf("type=signal,interface=%s.Interface,path=%s",
+ SUPPLICANT_INTF, task->path);
+
+ DBG("filter %s", filter);
+
+ dbus_error_init(&error);
+
+ dbus_bus_add_match(task->conn, filter, &error);
+
+ g_free(filter);
+
+ if (dbus_error_is_set(&error) == TRUE) {
+ connman_error("Can't add match: %s", error.message);
+ dbus_error_free(&error);
+ }
return 0;
}
@@ -159,7 +820,6 @@ int __supplicant_start(struct connman_iface *iface)
{
struct ifreq ifr;
struct supplicant_task *task;
- char *argv[9];
int sk, err;
sk = socket(PF_INET, SOCK_DGRAM, 0);
@@ -176,14 +836,14 @@ int __supplicant_start(struct connman_iface *iface)
if (err < 0)
return -EIO;
- printf("[SUPPLICANT] start %s\n", ifr.ifr_name);
+ DBG("interface %s", 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->ifname = g_strdup(ifr.ifr_name);
task->iface = iface;
if (task->ifname == NULL) {
@@ -191,32 +851,33 @@ int __supplicant_start(struct connman_iface *iface)
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;
+ task->conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+ if (task->conn == NULL) {
+ g_free(task);
+ return -EIO;
+ }
+
+ task->created = FALSE;
+
+ err = get_interface(task);
+ if (err < 0) {
+ err = add_interface(task);
+ if (err < 0) {
+ g_free(task);
+ return err;
+ }
}
- tasks = g_slist_append(tasks, task);
+ task->state = STATE_INACTIVE;
- printf("[SUPPLICANT] executed with pid %d\n", task->pid);
+ tasks = g_slist_append(tasks, task);
- sleep(1);
+ add_filter(task);
- task->socket = -1;
+ add_network(task);
- if (open_control(task) < 0)
- printf("[SUPPLICANT] control failed\n");
+ select_network(task);
+ disable_network(task);
return 0;
}
@@ -224,33 +885,51 @@ int __supplicant_start(struct connman_iface *iface)
int __supplicant_stop(struct connman_iface *iface)
{
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);
+ DBG("interface %s", task->ifname);
tasks = g_slist_remove(tasks, task);
- exec_cmd(task, "DISABLE_NETWORK 0");
- exec_cmd(task, "DETACH");
+ remove_network(task);
- sleep(1);
+ dbus_connection_unref(task->conn);
+
+ g_free(task->ifname);
+ g_free(task->network);
+ g_free(task->path);
+ g_free(task);
- kill(task->pid, SIGTERM);
+ return 0;
+}
- g_io_channel_shutdown(task->channel, TRUE, NULL);
- g_io_channel_unref(task->channel);
+int __supplicant_scan(struct connman_iface *iface)
+{
+ struct supplicant_task *task;
+ int err;
- snprintf(pathname, sizeof(pathname),
- "%s/%s.cli", STATEDIR, task->ifname);
- unlink(pathname);
+ task = find_task(iface->index);
+ if (task == NULL)
+ return -ENODEV;
- free(task->ifname);
+ DBG("interface %s", task->ifname);
+
+ switch (task->state) {
+ case STATE_SCANNING:
+ return -EALREADY;
+ case STATE_ASSOCIATING:
+ case STATE_ASSOCIATED:
+ case STATE_4WAY_HANDSHAKE:
+ case STATE_GROUP_HANDSHAKE:
+ return -EBUSY;
+ default:
+ break;
+ }
- g_free(task);
+ err = initiate_scan(task);
return 0;
}
@@ -259,34 +938,16 @@ int __supplicant_connect(struct connman_iface *iface,
const char *network, const char *passphrase)
{
struct supplicant_task *task;
- char cmd[128];
task = find_task(iface->index);
if (task == NULL)
return -ENODEV;
- printf("[SUPPLICANT] connect %s\n", task->ifname);
-
- exec_cmd(task, "DISABLE_NETWORK 0");
-
- if (network == NULL)
- return 0;
-
- sprintf(cmd, "SET_NETWORK 0 ssid \"%s\"", network);
- exec_cmd(task, cmd);
+ DBG("interface %s", task->ifname);
- if (passphrase && strlen(passphrase) > 0) {
- exec_cmd(task, "SET_NETWORK 0 proto RSN WPA");
- exec_cmd(task, "SET_NETWORK 0 key_mgmt WPA-PSK");
-
- sprintf(cmd, "SET_NETWORK 0 psk \"%s\"", passphrase);
- exec_cmd(task, cmd);
- } else {
- exec_cmd(task, "SET_NETWORK 0 proto RSN WPA");
- exec_cmd(task, "SET_NETWORK 0 key_mgmt NONE");
- }
+ set_network(task, network, passphrase);
- exec_cmd(task, "ENABLE_NETWORK 0");
+ enable_network(task);
return 0;
}
@@ -299,9 +960,9 @@ int __supplicant_disconnect(struct connman_iface *iface)
if (task == NULL)
return -ENODEV;
- printf("[SUPPLICANT] disconnect %s\n", task->ifname);
+ DBG("interface %s", task->ifname);
- exec_cmd(task, "DISABLE_NETWORK 0");
+ disable_network(task);
return 0;
}
diff --git a/plugins/supplicant.h b/plugins/supplicant.h
index dc015ed7..59e4dfe9 100644
--- a/plugins/supplicant.h
+++ b/plugins/supplicant.h
@@ -21,9 +21,15 @@
#include <connman/iface.h>
+#define SUPPLICANT_NAME "fi.epitest.hostap.WPASupplicant"
+#define SUPPLICANT_INTF "fi.epitest.hostap.WPASupplicant"
+#define SUPPLICANT_PATH "/fi/epitest/hostap/WPASupplicant"
+
int __supplicant_start(struct connman_iface *iface);
int __supplicant_stop(struct connman_iface *iface);
+int __supplicant_scan(struct connman_iface *iface);
+
int __supplicant_connect(struct connman_iface *iface,
const char *network, const char *passphrase);
int __supplicant_disconnect(struct connman_iface *iface);