static const struct supplicant_callbacks *callbacks_pointer;
+static dbus_bool_t system_available = FALSE;
+static dbus_bool_t system_ready = FALSE;
+
+static dbus_int32_t debug_level = 0;
+static dbus_bool_t debug_timestamp = FALSE;
+static dbus_bool_t debug_showkeys = FALSE;
+
static unsigned int eap_methods;
struct strvalmap {
{ }
};
-static struct strvalmap auth_capa_map[] = {
- { "open", SUPPLICANT_CAPABILITY_AUTH_OPEN },
- { "shared", SUPPLICANT_CAPABILITY_AUTH_SHARED },
- { "leap", SUPPLICANT_CAPABILITY_AUTH_LEAP },
+static struct strvalmap keymgmt_capa_map[] = {
+ { "none", SUPPLICANT_CAPABILITY_KEYMGMT_NONE },
+ { "ieee8021x", SUPPLICANT_CAPABILITY_KEYMGMT_IEEE8021X },
+ { "wpa-none", SUPPLICANT_CAPABILITY_KEYMGMT_WPA_NONE },
+ { "wpa-psk", SUPPLICANT_CAPABILITY_KEYMGMT_WPA_PSK },
+ { "wpa-eap", SUPPLICANT_CAPABILITY_KEYMGMT_WPA_EAP },
+ { "wps", SUPPLICANT_CAPABILITY_KEYMGMT_WPS },
+ { }
+};
+
+static struct strvalmap authalg_capa_map[] = {
+ { "open", SUPPLICANT_CAPABILITY_AUTHALG_OPEN },
+ { "shared", SUPPLICANT_CAPABILITY_AUTHALG_SHARED },
+ { "leap", SUPPLICANT_CAPABILITY_AUTHALG_LEAP },
+ { }
+};
+
+static struct strvalmap proto_capa_map[] = {
+ { "wpa", SUPPLICANT_CAPABILITY_PROTO_WPA },
+ { "rsn", SUPPLICANT_CAPABILITY_PROTO_RSN },
{ }
};
struct supplicant_interface {
char *path;
- unsigned int auth_capa;
+ unsigned int keymgmt_capa;
+ unsigned int authalg_capa;
+ unsigned int proto_capa;
unsigned int scan_capa;
unsigned int mode_capa;
enum supplicant_state state;
unsigned char bssid[6];
unsigned char ssid[32];
unsigned int ssid_len;
- unsigned int frequency;
+ dbus_uint16_t frequency;
enum supplicant_mode mode;
enum supplicant_security security;
dbus_bool_t privacy;
dbus_bool_t ieee8021x;
};
+static enum supplicant_mode string2mode(const char *mode)
+{
+ if (mode == NULL)
+ return SUPPLICANT_MODE_UNKNOWN;
+
+ if (g_str_equal(mode, "infrastructure") == TRUE)
+ return SUPPLICANT_MODE_INFRA;
+ else if (g_str_equal(mode, "ad-hoc") == TRUE)
+ return SUPPLICANT_MODE_IBSS;
+
+ return SUPPLICANT_MODE_UNKNOWN;
+}
+
static const char *mode2string(enum supplicant_mode mode)
{
switch (mode) {
return SUPPLICANT_STATE_UNKNOWN;
}
+static void callback_system_ready(void)
+{
+ if (system_ready == TRUE)
+ return;
+
+ system_ready = TRUE;
+
+ if (callbacks_pointer == NULL)
+ return;
+
+ if (callbacks_pointer->system_ready == NULL)
+ return;
+
+ callbacks_pointer->system_ready();
+}
+
+static void callback_system_killed(void)
+{
+ system_ready = FALSE;
+
+ if (callbacks_pointer == NULL)
+ return;
+
+ if (callbacks_pointer->system_killed == NULL)
+ return;
+
+ callbacks_pointer->system_killed();
+}
+
static void callback_interface_added(struct supplicant_interface *interface)
{
if (callbacks_pointer == NULL)
{
struct supplicant_interface *interface = data;
- callback_interface_removed(interface);
-
g_hash_table_destroy(interface->bss_mapping);
g_hash_table_destroy(interface->network_table);
+ callback_interface_removed(interface);
+
g_free(interface->path);
g_free(interface->ifname);
g_free(interface->driver);
}
}
-static void interface_capability_auth(DBusMessageIter *iter, void *user_data)
+static void interface_capability_keymgmt(DBusMessageIter *iter, void *user_data)
{
struct supplicant_interface *interface = user_data;
const char *str = NULL;
if (str == NULL)
return;
- for (i = 0; auth_capa_map[i].str != NULL; i++)
- if (strcmp(str, auth_capa_map[i].str) == 0) {
- interface->auth_capa |= auth_capa_map[i].val;
+ for (i = 0; keymgmt_capa_map[i].str != NULL; i++)
+ if (strcmp(str, keymgmt_capa_map[i].str) == 0) {
+ interface->keymgmt_capa |= keymgmt_capa_map[i].val;
+ break;
+ }
+}
+
+static void interface_capability_authalg(DBusMessageIter *iter, void *user_data)
+{
+ struct supplicant_interface *interface = user_data;
+ const char *str = NULL;
+ int i;
+
+ dbus_message_iter_get_basic(iter, &str);
+ if (str == NULL)
+ return;
+
+ for (i = 0; authalg_capa_map[i].str != NULL; i++)
+ if (strcmp(str, authalg_capa_map[i].str) == 0) {
+ interface->authalg_capa |= authalg_capa_map[i].val;
+ break;
+ }
+}
+
+static void interface_capability_proto(DBusMessageIter *iter, void *user_data)
+{
+ struct supplicant_interface *interface = user_data;
+ const char *str = NULL;
+ int i;
+
+ dbus_message_iter_get_basic(iter, &str);
+ if (str == NULL)
+ return;
+
+ for (i = 0; proto_capa_map[i].str != NULL; i++)
+ if (strcmp(str, proto_capa_map[i].str) == 0) {
+ interface->proto_capa |= proto_capa_map[i].val;
break;
}
}
if (key == NULL)
return;
- if (g_strcmp0(key, "AuthAlg") == 0)
- supplicant_dbus_array_foreach(iter, interface_capability_auth,
+ if (g_strcmp0(key, "KeyMgmt") == 0)
+ supplicant_dbus_array_foreach(iter,
+ interface_capability_keymgmt, interface);
+ else if (g_strcmp0(key, "AuthAlg") == 0)
+ supplicant_dbus_array_foreach(iter,
+ interface_capability_authalg, interface);
+ else if (g_strcmp0(key, "Protocol") == 0)
+ supplicant_dbus_array_foreach(iter, interface_capability_proto,
interface);
else if (g_strcmp0(key, "Scan") == 0)
supplicant_dbus_array_foreach(iter, interface_capability_scan,
if (path == NULL)
return;
+ if (g_strcmp0(path, "/") == 0)
+ return;
+
DBG("path %s", path);
supplicant_dbus_property_get_all(path,
if (capabilities & IEEE80211_CAP_PRIVACY)
bss->privacy = TRUE;
+ } else if (g_strcmp0(key, "Mode") == 0) {
+ const char *mode = NULL;
+
+ dbus_message_iter_get_basic(iter, &mode);
+ bss->mode = string2mode(mode);
} else if (g_strcmp0(key, "Frequency") == 0) {
- dbus_int32_t frequency = 0;
+ dbus_uint16_t frequency = 0;
dbus_message_iter_get_basic(iter, &frequency);
bss->frequency = frequency;
+ } else if (g_strcmp0(key, "Signal") == 0) {
+ dbus_int16_t signal = 0;
+
+ dbus_message_iter_get_basic(iter, &signal);
} else if (g_strcmp0(key, "Level") == 0) {
dbus_int32_t level = 0;
dbus_message_iter_get_basic(iter, &level);
} else if (g_strcmp0(key, "MaxRate") == 0) {
- dbus_int32_t maxrate = 0;
+ dbus_uint16_t maxrate = 0;
dbus_message_iter_get_basic(iter, &maxrate);
+ } else if (g_strcmp0(key, "Privacy") == 0) {
+ dbus_bool_t privacy = FALSE;
+
+ dbus_message_iter_get_basic(iter, &privacy);
+ bss->privacy = privacy;
} else if (g_strcmp0(key, "RSNIE") == 0) {
DBusMessageIter array;
unsigned char *ie;
if (path == NULL)
return;
+ if (g_strcmp0(path, "/") == 0)
+ return;
+
network = g_hash_table_lookup(interface->bss_mapping, path);
if (network != NULL) {
bss = g_hash_table_lookup(network->bss_table, path);
return;
if (key == NULL) {
- debug_strvalmap("Auth capability", auth_capa_map,
- interface->auth_capa);
+ debug_strvalmap("KeyMgmt capability", keymgmt_capa_map,
+ interface->keymgmt_capa);
+ debug_strvalmap("AuthAlg capability", authalg_capa_map,
+ interface->authalg_capa);
+ debug_strvalmap("Protocol capability", proto_capa_map,
+ interface->proto_capa);
debug_strvalmap("Scan capability", scan_capa_map,
interface->scan_capa);
debug_strvalmap("Mode capability", mode_capa_map,
interface->mode_capa);
- g_hash_table_replace(interface_table,
- interface->path, interface);
-
callback_interface_added(interface);
return;
}
key, dbus_message_iter_get_arg_type(iter));
}
+static struct supplicant_interface *interface_alloc(const char *path)
+{
+ struct supplicant_interface *interface;
+
+ interface = g_try_new0(struct supplicant_interface, 1);
+ if (interface == NULL)
+ return NULL;
+
+ interface->path = g_strdup(path);
+
+ interface->network_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, remove_network);
+
+ interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, NULL);
+
+ g_hash_table_replace(interface_table, interface->path, interface);
+
+ return interface;
+}
+
static void interface_added(DBusMessageIter *iter, void *user_data)
{
struct supplicant_interface *interface;
if (path == NULL)
return;
+ if (g_strcmp0(path, "/") == 0)
+ return;
+
interface = g_hash_table_lookup(interface_table, path);
if (interface != NULL)
return;
- interface = g_try_new0(struct supplicant_interface, 1);
+ interface = interface_alloc(path);
if (interface == NULL)
return;
- interface->path = g_strdup(path);
-
- interface->network_table = g_hash_table_new_full(g_str_hash, g_str_equal,
- NULL, remove_network);
-
- interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
- NULL, NULL);
-
supplicant_dbus_property_get_all(path,
SUPPLICANT_INTERFACE ".Interface",
interface_property, interface);
static void service_property(const char *key, DBusMessageIter *iter,
void *user_data)
{
- if (key == NULL)
+ if (key == NULL) {
+ callback_system_ready();
return;
+ }
- if (g_strcmp0(key, "Interfaces") == 0)
- supplicant_dbus_array_foreach(iter, interface_added, user_data);
- else if (g_strcmp0(key, "EapMethods") == 0) {
- supplicant_dbus_array_foreach(iter, eap_method, user_data);
+ 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);
+
+ 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);
+ DBG("Debug level %d", debug_level);
+ } 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) {
+ dbus_message_iter_get_basic(iter, &debug_showkeys);
+ DBG("Debug show keys %u", debug_showkeys);
+ } else if (g_strcmp0(key, "Interfaces") == 0) {
+ supplicant_dbus_array_foreach(iter, interface_added, NULL);
+ } else if (g_strcmp0(key, "EapMethods") == 0) {
+ supplicant_dbus_array_foreach(iter, eap_method, NULL);
debug_strvalmap("EAP method", eap_method_map, eap_methods);
- } else if (g_strcmp0(key, "DebugParams") == 0) {
- }
+ } else
+ DBG("key %s type %c",
+ key, dbus_message_iter_get_arg_type(iter));
}
static void supplicant_bootstrap(void)
if (old == NULL || new == NULL)
return;
- if (strlen(old) > 0 && strlen(new) == 0)
+ if (strlen(old) > 0 && strlen(new) == 0) {
+ system_available = FALSE;
g_hash_table_remove_all(interface_table);
+ callback_system_killed();
+ }
- if (strlen(new) > 0 && strlen(old) == 0)
+ if (strlen(new) > 0 && strlen(old) == 0) {
+ system_available = TRUE;
supplicant_bootstrap();
+ }
+}
+
+static void signal_properties_changed(const char *path, DBusMessageIter *iter)
+{
+ if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
+ return;
+
+ supplicant_dbus_property_foreach(iter, service_property, NULL);
}
static void signal_interface_added(const char *path, DBusMessageIter *iter)
const char *member;
void (*function) (const char *path, DBusMessageIter *iter);
} signal_map[] = {
- { DBUS_INTERFACE_DBUS, "NameOwnerChanged", signal_name_owner_changed },
+ { DBUS_INTERFACE_DBUS, "NameOwnerChanged", signal_name_owner_changed },
- { SUPPLICANT_INTERFACE, "InterfaceAdded", signal_interface_added },
- { SUPPLICANT_INTERFACE, "InterfaceCreated", signal_interface_added },
- { SUPPLICANT_INTERFACE, "InterfaceRemoved", signal_interface_removed },
+ { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed },
+ { SUPPLICANT_INTERFACE, "InterfaceAdded", signal_interface_added },
+ { SUPPLICANT_INTERFACE, "InterfaceCreated", signal_interface_added },
+ { SUPPLICANT_INTERFACE, "InterfaceRemoved", signal_interface_removed },
{ SUPPLICANT_INTERFACE ".Interface", "BSSAdded", signal_bss_added },
{ SUPPLICANT_INTERFACE ".Interface", "BSSRemoved", signal_bss_removed },
dbus_connection_flush(connection);
if (dbus_bus_name_has_owner(connection,
- SUPPLICANT_SERVICE, NULL) == TRUE)
+ SUPPLICANT_SERVICE, NULL) == TRUE) {
+ system_available = TRUE;
supplicant_bootstrap();
+ }
return 0;
}
interface_table = NULL;
}
+ if (system_available == TRUE)
+ callback_system_killed();
+
if (connection != NULL) {
dbus_connection_unref(connection);
connection = NULL;
callbacks_pointer = NULL;
eap_methods = 0;
}
+
+static void debug_level_result(const char *error,
+ DBusMessageIter *iter, void *user_data)
+{
+ if (error != NULL)
+ DBG("debug level failure: %s", error);
+}
+
+static void add_debug_level(DBusMessageIter *iter, void *user_data)
+{
+ dbus_int32_t level = GPOINTER_TO_UINT(user_data);
+ DBusMessageIter entry;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
+ NULL, &entry);
+
+ 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);
+
+ dbus_message_iter_close_container(iter, &entry);
+}
+
+void supplicant_set_debug_level(unsigned int level)
+{
+ if (system_available == FALSE)
+ return;
+
+ supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
+ "DebugParams", "(ibb)", add_debug_level,
+ debug_level_result, GUINT_TO_POINTER(level));
+}
+
+struct interface_create_data {
+ const char *ifname;
+ const char *driver;
+ struct supplicant_interface *interface;
+ supplicant_interface_create_callback callback;
+ void *user_data;
+};
+
+static void interface_create_property(const char *key, DBusMessageIter *iter,
+ void *user_data)
+{
+ struct interface_create_data *data = user_data;
+ struct supplicant_interface *interface = data->interface;
+
+ if (key == NULL) {
+ if (data->callback != NULL)
+ data->callback(0, data->interface, data->user_data);
+
+ dbus_free(data);
+ }
+
+ interface_property(key, iter, interface);
+}
+
+static void interface_create_result(const char *error,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct interface_create_data *data = user_data;
+ const char *path = NULL;
+ int err;
+
+ if (error != NULL) {
+ err = -EIO;
+ goto done;
+ }
+
+ dbus_message_iter_get_basic(iter, &path);
+ if (path == NULL) {
+ err = -EINVAL;
+ goto done;
+ }
+
+ if (system_available == FALSE) {
+ err = -EFAULT;
+ goto done;
+ }
+
+ data->interface = g_hash_table_lookup(interface_table, path);
+ if (data->interface == NULL) {
+ data->interface = interface_alloc(path);
+ if (data->interface == NULL) {
+ err = -ENOMEM;
+ goto done;
+ }
+ }
+
+ err = supplicant_dbus_property_get_all(path,
+ SUPPLICANT_INTERFACE ".Interface",
+ interface_create_property, data);
+ if (err == 0)
+ return;
+
+done:
+ if (data->callback != NULL)
+ data->callback(err, NULL, data->user_data);
+
+ dbus_free(data);
+}
+
+static void interface_create_params(DBusMessageIter *iter, void *user_data)
+{
+ struct interface_create_data *data = user_data;
+ DBusMessageIter dict;
+
+ supplicant_dbus_dict_open(iter, &dict);
+
+ supplicant_dbus_dict_append_basic(&dict, "Ifname",
+ DBUS_TYPE_STRING, &data->ifname);
+ supplicant_dbus_dict_append_basic(&dict, "Driver",
+ DBUS_TYPE_STRING, &data->driver);
+
+ supplicant_dbus_dict_close(iter, &dict);
+}
+
+static void interface_get_result(const char *error,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct interface_create_data *data = user_data;
+ struct supplicant_interface *interface;
+ const char *path = NULL;
+ int err;
+
+ if (error != NULL) {
+ err = -EIO;
+ goto create;
+ }
+
+ dbus_message_iter_get_basic(iter, &path);
+ if (path == NULL) {
+ err = -EINVAL;
+ goto done;
+ }
+
+ interface = g_hash_table_lookup(interface_table, path);
+ if (interface == NULL) {
+ err = -ENOENT;
+ goto done;
+ }
+
+ if (data->callback != NULL)
+ data->callback(0, interface, data->user_data);
+
+ dbus_free(data);
+
+ return;
+
+create:
+ if (system_available == FALSE) {
+ err = -EFAULT;
+ goto done;
+ }
+
+ err = supplicant_dbus_method_call(SUPPLICANT_PATH,
+ SUPPLICANT_INTERFACE,
+ "CreateInterface",
+ interface_create_params,
+ interface_create_result, data);
+ if (err == 0)
+ return;
+
+done:
+ if (data->callback != NULL)
+ data->callback(err, NULL, data->user_data);
+
+ dbus_free(data);
+}
+
+static void interface_get_params(DBusMessageIter *iter, void *user_data)
+{
+ struct interface_create_data *data = user_data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
+}
+
+int supplicant_interface_create(const char *ifname, const char *driver,
+ supplicant_interface_create_callback callback,
+ void *user_data)
+{
+ struct interface_create_data *data;
+
+ if (system_available == FALSE)
+ return -EFAULT;
+
+ data = dbus_malloc0(sizeof(*data));
+ if (data == NULL)
+ return -ENOMEM;
+
+ data->ifname = ifname;
+ data->driver = driver;
+ data->callback = callback;
+ data->user_data = user_data;
+
+ return supplicant_dbus_method_call(SUPPLICANT_PATH,
+ SUPPLICANT_INTERFACE,
+ "GetInterface",
+ interface_get_params,
+ interface_get_result, data);
+}
+
+int supplicant_interface_remove(struct supplicant_interface *interface,
+ supplicant_interface_remove_callback callback,
+ void *user_data)
+{
+ if (system_available == FALSE)
+ return -EFAULT;
+
+ return 0;
+}