From 2b1e2d01d040dceac55aa3efca707a7ce8521f9c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 31 Dec 2009 01:31:45 -0800 Subject: Add interface creation function to supplicant test program --- tools/supplicant-dbus.c | 143 ++++++++++++++++++++- tools/supplicant-dbus.h | 35 +++++ tools/supplicant-test.c | 27 ++-- tools/supplicant.c | 332 +++++++++++++++++++++++++++++++++++++++++++----- tools/supplicant.h | 29 ++++- 5 files changed, 525 insertions(+), 41 deletions(-) diff --git a/tools/supplicant-dbus.c b/tools/supplicant-dbus.c index e0e0432e..c95f2e77 100644 --- a/tools/supplicant-dbus.c +++ b/tools/supplicant-dbus.c @@ -32,7 +32,7 @@ #define TIMEOUT 5000 -static DBusConnection *connection; +static DBusConnection *connection = NULL; void supplicant_dbus_setup(DBusConnection *conn) { @@ -137,6 +137,9 @@ int supplicant_dbus_property_get_all(const char *path, const char *interface, DBusMessage *message; DBusPendingCall *call; + if (connection == NULL) + return -EINVAL; + if (path == NULL || interface == NULL) return -EINVAL; @@ -221,6 +224,9 @@ int supplicant_dbus_property_set(const char *path, const char *interface, DBusMessageIter iter, value; DBusPendingCall *call; + if (connection == NULL) + return -EINVAL; + if (path == NULL || interface == NULL) return -EINVAL; @@ -272,3 +278,138 @@ int supplicant_dbus_property_set(const char *path, const char *interface, return 0; } + +struct method_call_data { + supplicant_dbus_result_function function; + void *user_data; +}; + +static void method_call_reply(DBusPendingCall *call, void *user_data) +{ + struct method_call_data *data = user_data; + DBusMessage *reply; + DBusMessageIter iter; + const char *error; + + reply = dbus_pending_call_steal_reply(call); + if (reply == NULL) + return; + + if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) + error = dbus_message_get_error_name(reply); + else + error = NULL; + + if (dbus_message_iter_init(reply, &iter) == FALSE) + goto done; + + if (data->function != NULL) + data->function(error, &iter, data->user_data); + +done: + dbus_message_unref(reply); +} + +int supplicant_dbus_method_call(const char *path, + const char *interface, const char *method, + supplicant_dbus_setup_function setup, + supplicant_dbus_result_function function, + void *user_data) +{ + struct method_call_data *data; + DBusMessage *message; + DBusMessageIter iter; + DBusPendingCall *call; + + if (connection == NULL) + return -EINVAL; + + if (path == NULL || interface == NULL) + return -EINVAL; + + if (method == NULL || setup == NULL) + return -EINVAL; + + data = dbus_malloc0(sizeof(*data)); + if (data == NULL) + return -ENOMEM; + + message = dbus_message_new_method_call(SUPPLICANT_SERVICE, path, + interface, method); + if (message == NULL) { + dbus_free(data); + return -ENOMEM; + } + + dbus_message_set_auto_start(message, FALSE); + + dbus_message_iter_init_append(message, &iter); + setup(&iter, user_data); + + if (dbus_connection_send_with_reply(connection, message, + &call, TIMEOUT) == FALSE) { + dbus_message_unref(message); + dbus_free(data); + return -EIO; + } + + if (call == NULL) { + dbus_message_unref(message); + dbus_free(data); + return -EIO; + } + + data->function = function; + data->user_data = user_data; + + dbus_pending_call_set_notify(call, method_call_reply, + data, dbus_free); + + dbus_message_unref(message); + + return 0; +} + +void supplicant_dbus_property_append_basic(DBusMessageIter *iter, + const char *key, int type, void *val) +{ + DBusMessageIter value; + const char *signature; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key); + + switch (type) { + case DBUS_TYPE_BOOLEAN: + signature = DBUS_TYPE_BOOLEAN_AS_STRING; + break; + case DBUS_TYPE_STRING: + signature = DBUS_TYPE_STRING_AS_STRING; + break; + case DBUS_TYPE_BYTE: + signature = DBUS_TYPE_BYTE_AS_STRING; + break; + case DBUS_TYPE_UINT16: + signature = DBUS_TYPE_UINT16_AS_STRING; + break; + case DBUS_TYPE_INT16: + signature = DBUS_TYPE_INT16_AS_STRING; + break; + case DBUS_TYPE_UINT32: + signature = DBUS_TYPE_UINT32_AS_STRING; + break; + case DBUS_TYPE_INT32: + signature = DBUS_TYPE_INT32_AS_STRING; + break; + case DBUS_TYPE_OBJECT_PATH: + signature = DBUS_TYPE_OBJECT_PATH_AS_STRING; + break; + default: + signature = DBUS_TYPE_VARIANT_AS_STRING; + break; + } + + dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + signature, &value); + dbus_message_iter_append_basic(&value, type, val); + dbus_message_iter_close_container(iter, &value); +} diff --git a/tools/supplicant-dbus.h b/tools/supplicant-dbus.h index 162ec72e..8251504c 100644 --- a/tools/supplicant-dbus.h +++ b/tools/supplicant-dbus.h @@ -56,3 +56,38 @@ int supplicant_dbus_property_set(const char *path, const char *interface, supplicant_dbus_setup_function setup, supplicant_dbus_result_function function, void *user_data); + +int supplicant_dbus_method_call(const char *path, + const char *interface, const char *method, + supplicant_dbus_setup_function setup, + supplicant_dbus_result_function function, + void *user_data); + +void supplicant_dbus_property_append_basic(DBusMessageIter *iter, + const char *key, int type, void *val); + +static inline void supplicant_dbus_dict_open(DBusMessageIter *iter, + DBusMessageIter *dict) +{ + dbus_message_iter_open_container(iter, 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); +} + +static inline void supplicant_dbus_dict_close(DBusMessageIter *iter, + DBusMessageIter *dict) +{ + dbus_message_iter_close_container(iter, dict); +} + +static inline void supplicant_dbus_dict_append_basic(DBusMessageIter *dict, + const char *key, int type, void *val) +{ + DBusMessageIter entry; + + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, + NULL, &entry); + supplicant_dbus_property_append_basic(&entry, key, type, val); + dbus_message_iter_close_container(dict, &entry); +} diff --git a/tools/supplicant-test.c b/tools/supplicant-test.c index e7fa4d67..87dff6fe 100644 --- a/tools/supplicant-test.c +++ b/tools/supplicant-test.c @@ -37,46 +37,57 @@ syslog(LOG_DEBUG, "%s() " fmt, __FUNCTION__ , ## arg); \ } while (0) +static void create_callback(int result, struct supplicant_interface *interface, + void *user_data) +{ + DBG("* result %d ifname %s", result, + supplicant_interface_get_ifname(interface)); + + if (result < 0) + return; +} + static void system_ready(void) { - DBG(""); + DBG("*"); - //supplicant_set_debug_level(1); + supplicant_interface_create("wlan0", "nl80211", + create_callback, NULL); } static void system_killed(void) { - DBG(""); + DBG("*"); } static void interface_added(struct supplicant_interface *interface) { const char *ifname = supplicant_interface_get_ifname(interface); - DBG("ifname %s", ifname); + DBG("* ifname %s", ifname); } static void interface_removed(struct supplicant_interface *interface) { const char *ifname = supplicant_interface_get_ifname(interface); - DBG("ifname %s", ifname); + DBG("* ifname %s", ifname); } static void network_added(struct supplicant_network *network) { const char *name = supplicant_network_get_name(network); - DBG("name %s", name); + DBG("* name %s", name); - DBG("%s", supplicant_network_get_identifier(network)); + DBG("* %s", supplicant_network_get_identifier(network)); } static void network_removed(struct supplicant_network *network) { const char *name = supplicant_network_get_name(network); - DBG("name %s", name); + DBG("* name %s", name); } static const struct supplicant_callbacks callbacks = { diff --git a/tools/supplicant.c b/tools/supplicant.c index 8f23dc3f..c5757afc 100644 --- a/tools/supplicant.c +++ b/tools/supplicant.c @@ -49,6 +49,7 @@ static DBusConnection *connection; 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_show_timestamps = FALSE; @@ -73,10 +74,26 @@ static struct strvalmap eap_method_map[] = { { } }; -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 }, { } }; @@ -98,7 +115,9 @@ static GHashTable *interface_table; 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; @@ -196,6 +215,11 @@ static enum supplicant_state string2state(const char *state) static void callback_system_ready(void) { + if (system_ready == TRUE) + return; + + system_ready = TRUE; + if (callbacks_pointer == NULL) return; @@ -207,6 +231,8 @@ static void callback_system_ready(void) static void callback_system_killed(void) { + system_ready = FALSE; + if (callbacks_pointer == NULL) return; @@ -264,11 +290,11 @@ static void remove_interface(gpointer data) { 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); @@ -306,7 +332,24 @@ static void debug_strvalmap(const char *label, struct strvalmap *map, } } -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; + int i; + + dbus_message_iter_get_basic(iter, &str); + if (str == NULL) + return; + + 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; @@ -316,9 +359,26 @@ static void interface_capability_auth(DBusMessageIter *iter, void *user_data) 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; 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; } } @@ -365,8 +425,14 @@ static void interface_capability(const char *key, DBusMessageIter *iter, 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, @@ -436,6 +502,9 @@ static void interface_network_added(DBusMessageIter *iter, void *user_data) if (path == NULL) return; + if (g_strcmp0(path, "/") == 0) + return; + DBG("path %s", path); supplicant_dbus_property_get_all(path, @@ -728,6 +797,9 @@ static void interface_bss_added(DBusMessageIter *iter, void *user_data) 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); @@ -777,16 +849,17 @@ static void interface_property(const char *key, DBusMessageIter *iter, 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; } @@ -844,6 +917,27 @@ static void interface_property(const char *key, DBusMessageIter *iter, 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; @@ -853,22 +947,17 @@ static void interface_added(DBusMessageIter *iter, void *user_data) 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); @@ -924,9 +1013,9 @@ static void service_property(const char *key, DBusMessageIter *iter, DBG("Debug level %d (timestamps %u keys %u)", debug_level, debug_show_timestamps, debug_show_keys); } else if (g_strcmp0(key, "Interfaces") == 0) { - supplicant_dbus_array_foreach(iter, interface_added, user_data); + supplicant_dbus_array_foreach(iter, interface_added, NULL); } else if (g_strcmp0(key, "EapMethods") == 0) { - supplicant_dbus_array_foreach(iter, eap_method, user_data); + supplicant_dbus_array_foreach(iter, eap_method, NULL); debug_strvalmap("EAP method", eap_method_map, eap_methods); } } @@ -1203,6 +1292,9 @@ static void add_debug_level(DBusMessageIter *iter, void *user_data) 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)); @@ -1227,7 +1319,189 @@ static void add_show_timestamps(DBusMessageIter *iter, void *user_data) void supplicant_set_debug_show_timestamps(dbus_bool_t enabled) { + if (system_available == FALSE) + return; + supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE, "DebugParams", "(ibb)", add_show_timestamps, NULL, GUINT_TO_POINTER(enabled)); } + +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; +} diff --git a/tools/supplicant.h b/tools/supplicant.h index f4d01c6d..9fb1a90d 100644 --- a/tools/supplicant.h +++ b/tools/supplicant.h @@ -28,9 +28,19 @@ #define SUPPLICANT_EAP_METHOD_OTP (1 << 6) #define SUPPLICANT_EAP_METHOD_LEAP (1 << 7) -#define SUPPLICANT_CAPABILITY_AUTH_OPEN (1 << 0) -#define SUPPLICANT_CAPABILITY_AUTH_SHARED (1 << 1) -#define SUPPLICANT_CAPABILITY_AUTH_LEAP (1 << 2) +#define SUPPLICANT_CAPABILITY_KEYMGMT_NONE (1 << 0) +#define SUPPLICANT_CAPABILITY_KEYMGMT_IEEE8021X (1 << 1) +#define SUPPLICANT_CAPABILITY_KEYMGMT_WPA_NONE (1 << 2) +#define SUPPLICANT_CAPABILITY_KEYMGMT_WPA_PSK (1 << 3) +#define SUPPLICANT_CAPABILITY_KEYMGMT_WPA_EAP (1 << 4) +#define SUPPLICANT_CAPABILITY_KEYMGMT_WPS (1 << 5) + +#define SUPPLICANT_CAPABILITY_AUTHALG_OPEN (1 << 0) +#define SUPPLICANT_CAPABILITY_AUTHALG_SHARED (1 << 1) +#define SUPPLICANT_CAPABILITY_AUTHALG_LEAP (1 << 2) + +#define SUPPLICANT_CAPABILITY_PROTO_WPA (1 << 0) +#define SUPPLICANT_CAPABILITY_PROTO_RSN (1 << 1) #define SUPPLICANT_CAPABILITY_SCAN_ACTIVE (1 << 0) #define SUPPLICANT_CAPABILITY_SCAN_PASSIVE (1 << 1) @@ -69,6 +79,19 @@ enum supplicant_state { struct supplicant_interface; +typedef void (* supplicant_interface_create_callback) (int result, + struct supplicant_interface *interface, + void *user_data); +typedef void (* supplicant_interface_remove_callback) (int result, + void *user_data); + +int supplicant_interface_create(const char *ifname, const char *driver, + supplicant_interface_create_callback callback, + void *user_data); +int supplicant_interface_remove(struct supplicant_interface *interface, + supplicant_interface_remove_callback callback, + void *user_data); + const char *supplicant_interface_get_ifname(struct supplicant_interface *interface); struct supplicant_network; -- cgit v1.2.3