static dbus_bool_t debug_timestamp = FALSE;
static dbus_bool_t debug_showkeys = FALSE;
+static const char *debug_strings[] = {
+ "msgdump", "debug", "info", "warning", "error", NULL
+};
+
static unsigned int eap_methods;
struct strvalmap {
};
static GHashTable *interface_table;
+static GHashTable *bss_mapping;
struct supplicant_interface {
char *path;
unsigned int pairwise_capa;
unsigned int scan_capa;
unsigned int mode_capa;
+ dbus_bool_t ready;
enum supplicant_state state;
dbus_bool_t scanning;
+ supplicant_interface_scan_callback scan_callback;
+ void *scan_data;
int apscan;
char *ifname;
char *driver;
char *bridge;
GHashTable *network_table;
+ GHashTable *net_mapping;
GHashTable *bss_mapping;
};
struct supplicant_network {
struct supplicant_interface *interface;
+ char *path;
char *group;
char *name;
enum supplicant_mode mode;
GHashTable *bss_table;
+ GHashTable *config_table;
};
struct supplicant_bss {
unsigned char ssid[32];
unsigned int ssid_len;
dbus_uint16_t frequency;
+ dbus_uint32_t maxrate;
enum supplicant_mode mode;
enum supplicant_security security;
dbus_bool_t privacy;
struct supplicant_interface *interface = data;
g_hash_table_destroy(interface->bss_mapping);
+ g_hash_table_destroy(interface->net_mapping);
g_hash_table_destroy(interface->network_table);
callback_interface_removed(interface);
{
struct supplicant_network *network = data;
+ g_hash_table_destroy(network->bss_table);
+
callback_network_removed(network);
+ g_hash_table_destroy(network->config_table);
+
g_free(network->group);
g_free(network->name);
g_free(network);
return network->mode;
}
+static void merge_network(struct supplicant_network *network)
+{
+ GString *str;
+ const char *ssid, *mode, *key_mgmt;
+ unsigned int i, ssid_len;
+ char *group;
+
+ ssid = g_hash_table_lookup(network->config_table, "ssid");
+ mode = g_hash_table_lookup(network->config_table, "mode");
+ key_mgmt = g_hash_table_lookup(network->config_table, "key_mgmt");
+
+ DBG("ssid %s mode %s", ssid, mode);
+
+ if (ssid != NULL)
+ ssid_len = strlen(ssid);
+ else
+ ssid_len = 0;
+
+ str = g_string_sized_new((ssid_len * 2) + 24);
+ if (str == NULL)
+ return;
+
+ for (i = 0; i < ssid_len; i++)
+ g_string_append_printf(str, "%02x", ssid[i]);
+
+ if (g_strcmp0(mode, "0") == 0)
+ g_string_append_printf(str, "_infra");
+ else if (g_strcmp0(mode, "1") == 0)
+ g_string_append_printf(str, "_adhoc");
+
+ if (g_strcmp0(key_mgmt, "WPA-PSK") == 0)
+ g_string_append_printf(str, "_psk");
+
+ group = g_string_free(str, FALSE);
+
+ DBG("%s", group);
+
+ g_free(group);
+
+ g_hash_table_destroy(network->config_table);
+
+ g_free(network->path);
+ g_free(network);
+}
+
static void network_property(const char *key, DBusMessageIter *iter,
void *user_data)
{
- if (key == NULL)
+ struct supplicant_network *network = user_data;
+
+ if (network->interface == NULL)
+ return;
+
+ if (key == NULL) {
+ merge_network(network);
return;
+ }
+
+ if (g_strcmp0(key, "Enabled") == 0) {
+ dbus_bool_t enabled = FALSE;
+
+ dbus_message_iter_get_basic(iter, &enabled);
+ } else if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
+ const char *str = NULL;
- //DBG("key %s type %c", key, dbus_message_iter_get_arg_type(iter));
+ dbus_message_iter_get_basic(iter, &str);
+ if (str != NULL)
+ g_hash_table_replace(network->config_table,
+ g_strdup(key), g_strdup(str));
+ } else
+ DBG("key %s type %c",
+ key, dbus_message_iter_get_arg_type(iter));
}
static void interface_network_added(DBusMessageIter *iter, void *user_data)
{
- //struct supplicant_interface *interface = user_data;
+ struct supplicant_interface *interface = user_data;
+ struct supplicant_network *network;
const char *path = NULL;
dbus_message_iter_get_basic(iter, &path);
if (g_strcmp0(path, "/") == 0)
return;
+ network = g_hash_table_lookup(interface->net_mapping, path);
+ if (network != NULL)
+ return;
+
+ network = g_try_new0(struct supplicant_network, 1);
+ if (network == NULL)
+ return;
+
+ network->interface = interface;
+ network->path = g_strdup(path);
+
+ network->config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, g_free);
+
dbus_message_iter_next(iter);
if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
- supplicant_dbus_property_foreach(iter, network_property, NULL);
- network_property(NULL, NULL, NULL);
+ supplicant_dbus_property_foreach(iter, network_property,
+ network);
+ network_property(NULL, NULL, network);
return;
}
- DBG("path %s", path);
-
supplicant_dbus_property_get_all(path,
SUPPLICANT_INTERFACE ".Interface.Network",
- network_property, NULL);
+ network_property, network);
}
static void interface_network_removed(DBusMessageIter *iter, void *user_data)
{
+ struct supplicant_interface *interface = user_data;
+ struct supplicant_network *network;
const char *path = NULL;
dbus_message_iter_get_basic(iter, &path);
if (path == NULL)
return;
- DBG("path %s", path);
+ network = g_hash_table_lookup(interface->net_mapping, path);
+ if (network == NULL)
+ return;
+
+ g_hash_table_remove(interface->net_mapping, path);
}
static char *create_name(unsigned char *ssid, int ssid_len)
network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, remove_bss);
+ network->config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, g_free);
+
g_hash_table_replace(interface->network_table,
network->group, network);
done:
g_hash_table_replace(interface->bss_mapping, bss->path, network);
g_hash_table_replace(network->bss_table, bss->path, bss);
+
+ g_hash_table_replace(bss_mapping, bss->path, interface);
}
static unsigned char wifi_oui[3] = { 0x00, 0x50, 0xf2 };
len -= 2 + (count * 4);
}
+static void bss_rates(DBusMessageIter *iter, void *user_data)
+{
+ struct supplicant_bss *bss = user_data;
+ dbus_uint32_t rate = 0;
+
+ dbus_message_iter_get_basic(iter, &rate);
+ if (rate == 0)
+ return;
+
+ if (rate > bss->maxrate)
+ bss->maxrate = rate;
+}
+
static void bss_property(const char *key, DBusMessageIter *iter,
void *user_data)
{
dbus_int32_t level = 0;
dbus_message_iter_get_basic(iter, &level);
+ } else if (g_strcmp0(key, "Rates") == 0) {
+ supplicant_dbus_array_foreach(iter, bss_rates, bss);
} else if (g_strcmp0(key, "MaxRate") == 0) {
- dbus_uint16_t maxrate = 0;
+ dbus_uint32_t maxrate = 0;
dbus_message_iter_get_basic(iter, &maxrate);
+ if (maxrate != 0)
+ bss->maxrate =maxrate;
} else if (g_strcmp0(key, "Privacy") == 0) {
dbus_bool_t privacy = FALSE;
if (network == NULL)
return;
+ g_hash_table_remove(bss_mapping, path);
+
g_hash_table_remove(interface->bss_mapping, path);
g_hash_table_remove(network->bss_table, path);
debug_strvalmap("Mode capability", mode_capa_map,
interface->mode_capa);
+ interface->ready = TRUE;
callback_interface_added(interface);
return;
}
dbus_message_iter_get_basic(iter, &str);
if (str != NULL)
interface->state = string2state(str);
+
+ DBG("state %s (%d)", str, interface->state);
} else if (g_strcmp0(key, "Scanning") == 0) {
dbus_bool_t scanning = FALSE;
dbus_message_iter_get_basic(iter, &scanning);
interface->scanning = scanning;
- DBG("scanning %u", interface->scanning);
-
- if (interface->scanning == TRUE)
- callback_scan_started(interface);
+ if (interface->ready == TRUE) {
+ if (interface->scanning == TRUE)
+ callback_scan_started(interface);
+ else
+ callback_scan_finished(interface);
+ }
} else if (g_strcmp0(key, "ApScan") == 0) {
int apscan = 1;
interface->network_table = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, remove_network);
+ interface->net_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, NULL);
interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, NULL);
return;
}
- if (g_strcmp0(key, "DebugParams") == 0) {
- DBusMessageIter list;
-
- dbus_message_iter_recurse(iter, &list);
- dbus_message_iter_get_basic(&list, &debug_level);
-
- dbus_message_iter_next(&list);
- dbus_message_iter_get_basic(&list, &debug_timestamp);
-
- dbus_message_iter_next(&list);
- dbus_message_iter_get_basic(&list, &debug_showkeys);
+ if (g_strcmp0(key, "DebugLevel") == 0) {
+ const char *str = NULL;
+ int i;
- DBG("Debug level %d (timestamp %u show keys %u)",
- debug_level, debug_timestamp, debug_showkeys);
- } else if (g_strcmp0(key, "DebugLevel") == 0) {
- dbus_message_iter_get_basic(iter, &debug_level);
+ dbus_message_iter_get_basic(iter, &str);
+ for (i = 0; debug_strings[i] != NULL; i++)
+ if (g_strcmp0(debug_strings[i], str) == 0) {
+ debug_level = i;
+ break;
+ }
DBG("Debug level %d", debug_level);
- } else if (g_strcmp0(key, "DebugTimeStamp") == 0) {
+ } else if (g_strcmp0(key, "DebugTimestamp") == 0) {
dbus_message_iter_get_basic(iter, &debug_timestamp);
DBG("Debug timestamp %u", debug_timestamp);
} else if (g_strcmp0(key, "DebugShowKeys") == 0) {
if (strlen(old) > 0 && strlen(new) == 0) {
system_available = FALSE;
+ g_hash_table_remove_all(bss_mapping);
g_hash_table_remove_all(interface_table);
callback_system_killed();
}
interface_removed(iter, NULL);
}
+static void signal_interface_changed(const char *path, DBusMessageIter *iter)
+{
+ struct supplicant_interface *interface;
+
+ interface = g_hash_table_lookup(interface_table, path);
+ if (interface == NULL)
+ return;
+
+ supplicant_dbus_property_foreach(iter, interface_property, interface);
+}
+
static void signal_scan_done(const char *path, DBusMessageIter *iter)
{
struct supplicant_interface *interface;
dbus_message_iter_get_basic(iter, &success);
- callback_scan_finished(interface);
+ if (interface->scan_callback != NULL) {
+ int result = 0;
+
+ if (success == FALSE)
+ result = -EIO;
+
+ interface->scan_callback(result, interface->scan_data);
+ }
+
+ interface->scan_callback = NULL;
+ interface->scan_data = NULL;
}
static void signal_bss_added(const char *path, DBusMessageIter *iter)
interface_network_removed(iter, interface);
}
+static void signal_bss_changed(const char *path, DBusMessageIter *iter)
+{
+ struct supplicant_interface *interface;
+ struct supplicant_network *network;
+ struct supplicant_bss *bss;
+
+ interface = g_hash_table_lookup(bss_mapping, path);
+ if (interface == NULL)
+ return;
+
+ network = g_hash_table_lookup(interface->bss_mapping, path);
+ if (network == NULL)
+ return;
+
+ bss = g_hash_table_lookup(network->bss_table, path);
+ if (bss == NULL)
+ return;
+
+ supplicant_dbus_property_foreach(iter, bss_property, bss);
+}
+
static struct {
const char *interface;
const char *member;
{ SUPPLICANT_INTERFACE, "InterfaceCreated", signal_interface_added },
{ SUPPLICANT_INTERFACE, "InterfaceRemoved", signal_interface_removed },
- { SUPPLICANT_INTERFACE ".Interface", "ScanDone", signal_scan_done },
- { SUPPLICANT_INTERFACE ".Interface", "BSSAdded", signal_bss_added },
- { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved", signal_bss_removed },
- { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded", signal_network_added },
- { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved", signal_network_removed },
+ { SUPPLICANT_INTERFACE ".Interface", "PropertiesChanged", signal_interface_changed },
+ { SUPPLICANT_INTERFACE ".Interface", "ScanDone", signal_scan_done },
+ { SUPPLICANT_INTERFACE ".Interface", "BSSAdded", signal_bss_added },
+ { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved", signal_bss_removed },
+ { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded", signal_network_added },
+ { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved", signal_network_removed },
+
+ { SUPPLICANT_INTERFACE ".Interface.BSS", "PropertiesChanged", signal_bss_changed },
{ }
};
interface_table = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, remove_interface);
+ bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, NULL);
+
supplicant_dbus_setup(connection);
dbus_bus_add_match(connection, supplicant_rule0, NULL);
supplicant_filter, NULL);
}
+ if (bss_mapping != NULL) {
+ g_hash_table_destroy(bss_mapping);
+ bss_mapping = NULL;
+ }
+
if (interface_table != NULL) {
g_hash_table_destroy(interface_table);
interface_table = NULL;
DBG("debug level failure: %s", error);
}
-static void add_debug_level(DBusMessageIter *iter, void *user_data)
+static void debug_level_params(DBusMessageIter *iter, void *user_data)
{
- dbus_int32_t level = GPOINTER_TO_UINT(user_data);
- DBusMessageIter entry;
+ guint level = GPOINTER_TO_UINT(user_data);
+ const char *str;
- dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
- NULL, &entry);
+ if (level > 4)
+ level = 4;
- dbus_message_iter_append_basic(&entry, DBUS_TYPE_INT32, &level);
- dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
- &debug_timestamp);
- dbus_message_iter_append_basic(&entry, DBUS_TYPE_BOOLEAN,
- &debug_showkeys);
+ str = debug_strings[level];
- dbus_message_iter_close_container(iter, &entry);
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
}
void supplicant_set_debug_level(unsigned int level)
return;
supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
- "DebugParams", "(ibb)", add_debug_level,
- debug_level_result, GUINT_TO_POINTER(level));
+ "DebugLevel", DBUS_TYPE_STRING_AS_STRING,
+ debug_level_params, debug_level_result,
+ GUINT_TO_POINTER(level));
}
struct interface_create_data {
supplicant_dbus_dict_append_basic(&dict, "Ifname",
DBUS_TYPE_STRING, &data->ifname);
- supplicant_dbus_dict_append_basic(&dict, "Driver",
+
+ if (data->driver != NULL)
+ supplicant_dbus_dict_append_basic(&dict, "Driver",
DBUS_TYPE_STRING, &data->driver);
supplicant_dbus_dict_close(iter, &dict);
{
struct interface_create_data *data;
+ if (ifname == NULL)
+ return -EINVAL;
+
if (system_available == FALSE)
return -EFAULT;
supplicant_interface_remove_callback callback,
void *user_data)
{
+ if (interface == NULL)
+ return -EINVAL;
+
if (system_available == FALSE)
return -EFAULT;
return 0;
}
+struct interface_scan_data {
+ struct supplicant_interface *interface;
+ supplicant_interface_scan_callback callback;
+ void *user_data;
+};
+
static void interface_scan_result(const char *error,
DBusMessageIter *iter, void *user_data)
{
- DBG("error %s", error);
+ struct interface_scan_data *data = user_data;
+
+ if (error != NULL) {
+ if (data->callback != NULL)
+ data->callback(-EIO, data->user_data);
+ } else {
+ data->interface->scan_callback = data->callback;
+ data->interface->scan_data = data->user_data;
+ }
+
+ dbus_free(data);
}
static void interface_scan_params(DBusMessageIter *iter, void *user_data)
DBusMessageIter dict;
const char *type = "passive";
- DBG("");
-
supplicant_dbus_dict_open(iter, &dict);
supplicant_dbus_dict_append_basic(&dict, "Type",
supplicant_dbus_dict_close(iter, &dict);
}
-int supplicant_interface_scan(struct supplicant_interface *interface)
+int supplicant_interface_scan(struct supplicant_interface *interface,
+ supplicant_interface_scan_callback callback,
+ void *user_data)
{
+ struct interface_scan_data *data;
+
+ if (interface == NULL)
+ return -EINVAL;
+
if (system_available == FALSE)
return -EFAULT;
+ if (interface->scanning == TRUE)
+ return -EALREADY;
+
+ data = dbus_malloc0(sizeof(*data));
+ if (data == NULL)
+ return -ENOMEM;
+
+ data->interface = interface;
+ data->callback = callback;
+ data->user_data = user_data;
+
return supplicant_dbus_method_call(interface->path,
SUPPLICANT_INTERFACE ".Interface", "Scan",
- interface_scan_params, interface_scan_result, NULL);
+ interface_scan_params, interface_scan_result, data);
}
+struct interface_disconnect_data {
+ supplicant_interface_disconnect_callback callback;
+ void *user_data;
+};
+
static void interface_disconnect_result(const char *error,
DBusMessageIter *iter, void *user_data)
{
- DBG("error %s", error);
+ struct interface_disconnect_data *data = user_data;
+ int result = 0;
+
+ if (error != NULL)
+ result = -EIO;
+
+ if (data->callback != NULL)
+ data->callback(result, data->user_data);
+
+ dbus_free(data);
}
-int supplicant_interface_disconnect(struct supplicant_interface *interface)
+int supplicant_interface_disconnect(struct supplicant_interface *interface,
+ supplicant_interface_disconnect_callback callback,
+ void *user_data)
{
+ struct interface_disconnect_data *data;
+
+ if (interface == NULL)
+ return -EINVAL;
+
if (system_available == FALSE)
return -EFAULT;
+ data = dbus_malloc0(sizeof(*data));
+ if (data == NULL)
+ return -ENOMEM;
+
+ data->callback = callback;
+ data->user_data = user_data;
+
return supplicant_dbus_method_call(interface->path,
SUPPLICANT_INTERFACE ".Interface", "Disconnect",
- NULL, interface_disconnect_result, NULL);
+ NULL, interface_disconnect_result, data);
}