X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gsupplicant%2Fsupplicant.c;h=977c0fb39142965382d29fefe11c377433aa80d8;hb=eeb5fc8986c779a26e88182534b092e45e7ff443;hp=7a3fd4c70608f5005974d8713739504a22edcc7b;hpb=9005c12b628c4e8b3a2580b68be6b6b333b912f5;p=platform%2Fupstream%2Fconnman.git diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c index 7a3fd4c..977c0fb 100644 --- a/gsupplicant/supplicant.c +++ b/gsupplicant/supplicant.c @@ -2,7 +2,7 @@ * * WPA supplicant library with GLib integration * - * Copyright (C) 2010 Intel Corporation. All rights reserved. + * Copyright (C) 2012 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -152,6 +153,7 @@ struct _GSupplicantInterface { unsigned int pairwise_capa; unsigned int scan_capa; unsigned int mode_capa; + unsigned int max_scan_ssids; dbus_bool_t ready; GSupplicantState state; dbus_bool_t scanning; @@ -169,21 +171,6 @@ struct _GSupplicantInterface { void *data; }; -struct _GSupplicantNetwork { - GSupplicantInterface *interface; - char *path; - char *group; - char *name; - unsigned char ssid[32]; - unsigned int ssid_len; - dbus_int16_t signal; - GSupplicantMode mode; - GSupplicantSecurity security; - dbus_bool_t wps; - GHashTable *bss_table; - GHashTable *config_table; -}; - struct g_supplicant_bss { GSupplicantInterface *interface; char *path; @@ -201,6 +188,25 @@ struct g_supplicant_bss { dbus_bool_t privacy; dbus_bool_t psk; dbus_bool_t ieee8021x; + unsigned int wps_capabilities; +}; + +struct _GSupplicantNetwork { + GSupplicantInterface *interface; + char *path; + char *group; + char *name; + unsigned char ssid[32]; + unsigned int ssid_len; + dbus_int16_t signal; + dbus_uint16_t frequency; + struct g_supplicant_bss *best_bss; + GSupplicantMode mode; + GSupplicantSecurity security; + dbus_bool_t wps; + unsigned int wps_capabilities; + GHashTable *bss_table; + GHashTable *config_table; }; static inline void debug(const char *format, ...) @@ -406,6 +412,18 @@ static void callback_network_removed(GSupplicantNetwork *network) callbacks_pointer->network_removed(network); } +static void callback_network_changed(GSupplicantNetwork *network, + const char *property) +{ + if (callbacks_pointer == NULL) + return; + + if (callbacks_pointer->network_changed == NULL) + return; + + callbacks_pointer->network_changed(network, property); +} + static void remove_interface(gpointer data) { GSupplicantInterface *interface = data; @@ -609,7 +627,13 @@ static void interface_capability(const char *key, DBusMessageIter *iter, else if (g_strcmp0(key, "Modes") == 0) supplicant_dbus_array_foreach(iter, interface_capability_mode, interface); - else + else if (g_strcmp0(key, "MaxScanSSID") == 0) { + dbus_int32_t max_scan_ssid; + + dbus_message_iter_get_basic(iter, &max_scan_ssid); + interface->max_scan_ssids = max_scan_ssid; + + } else SUPPLICANT_DBG("key %s type %c", key, dbus_message_iter_get_arg_type(iter)); } @@ -712,6 +736,49 @@ unsigned int g_supplicant_interface_get_mode(GSupplicantInterface *interface) return interface->mode_capa; } +unsigned int g_supplicant_interface_get_max_scan_ssids( + GSupplicantInterface *interface) +{ + if (interface == NULL) + return 0; + + if (interface->max_scan_ssids == 0) + return WPAS_MAX_SCAN_SSIDS; + + return interface->max_scan_ssids; +} + +static void set_network_enabled(DBusMessageIter *iter, void *user_data) +{ + dbus_bool_t enable = *(dbus_bool_t *)user_data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &enable); +} + +int g_supplicant_interface_enable_selected_network(GSupplicantInterface *interface, + dbus_bool_t enable) +{ + if (interface == NULL) + return -1; + + if (interface->network_path == NULL) + return -1; + + SUPPLICANT_DBG(" "); + return supplicant_dbus_property_set(interface->network_path, + SUPPLICANT_INTERFACE ".Network", + "Enabled", DBUS_TYPE_BOOLEAN_AS_STRING, + set_network_enabled, NULL, &enable); +} + +dbus_bool_t g_supplicant_interface_get_ready(GSupplicantInterface *interface) +{ + if (interface == NULL) + return FALSE; + + return interface->ready; +} + GSupplicantInterface *g_supplicant_network_get_interface( GSupplicantNetwork *network) { @@ -781,6 +848,14 @@ dbus_int16_t g_supplicant_network_get_signal(GSupplicantNetwork *network) return network->signal; } +dbus_uint16_t g_supplicant_network_get_frequency(GSupplicantNetwork *network) +{ + if (network == NULL) + return 0; + + return network->frequency; +} + dbus_bool_t g_supplicant_network_get_wps(GSupplicantNetwork *network) { if (network == NULL) @@ -789,6 +864,39 @@ dbus_bool_t g_supplicant_network_get_wps(GSupplicantNetwork *network) return network->wps; } +dbus_bool_t g_supplicant_network_is_wps_active(GSupplicantNetwork *network) +{ + if (network == NULL) + return FALSE; + + if (network->wps_capabilities & G_SUPPLICANT_WPS_CONFIGURED) + return TRUE; + + return FALSE; +} + +dbus_bool_t g_supplicant_network_is_wps_pbc(GSupplicantNetwork *network) +{ + if (network == NULL) + return FALSE; + + if (network->wps_capabilities & G_SUPPLICANT_WPS_PBC) + return TRUE; + + return FALSE; +} + +dbus_bool_t g_supplicant_network_is_wps_advertizing(GSupplicantNetwork *network) +{ + if (network == NULL) + return FALSE; + + if (network->wps_capabilities & G_SUPPLICANT_WPS_REGISTRAR) + return TRUE; + + return FALSE; +} + static void merge_network(GSupplicantNetwork *network) { GString *str; @@ -925,25 +1033,43 @@ static void interface_network_removed(DBusMessageIter *iter, void *user_data) static char *create_name(unsigned char *ssid, int ssid_len) { - char *name; - int i; + GString *string; + const gchar *remainder, *invalid; + int valid_bytes, remaining_bytes; if (ssid_len < 1 || ssid[0] == '\0') - name = NULL; - else - name = g_try_malloc0(ssid_len + 1); - - if (name == NULL) return g_strdup(""); - for (i = 0; i < ssid_len; i++) { - if (g_ascii_isprint(ssid[i])) - name[i] = ssid[i]; - else - name[i] = ' '; + string = NULL; + remainder = (const gchar *)ssid; + remaining_bytes = ssid_len; + + while (remaining_bytes != 0) { + if (g_utf8_validate(remainder, remaining_bytes, + &invalid) == TRUE) { + break; + } + + valid_bytes = invalid - remainder; + + if (string == NULL) + string = g_string_sized_new(remaining_bytes); + + g_string_append_len(string, remainder, valid_bytes); + + /* append U+FFFD REPLACEMENT CHARACTER */ + g_string_append(string, "\357\277\275"); + + remaining_bytes -= valid_bytes + 1; + remainder = invalid + 1; } - return name; + if (string == NULL) + return g_strndup((const gchar *)ssid, ssid_len + 1); + + g_string_append(string, remainder); + + return g_string_free(string, FALSE); } static char *create_group(struct g_supplicant_bss *bss) @@ -973,19 +1099,23 @@ static char *create_group(struct g_supplicant_bss *bss) return g_string_free(str, FALSE); } -static void add_bss_to_network(struct g_supplicant_bss *bss) +static void add_or_replace_bss_to_network(struct g_supplicant_bss *bss) { GSupplicantInterface *interface = bss->interface; GSupplicantNetwork *network; char *group; group = create_group(bss); + SUPPLICANT_DBG("New group created: %s", group); + if (group == NULL) return; network = g_hash_table_lookup(interface->network_table, group); if (network != NULL) { g_free(group); + SUPPLICANT_DBG("Network %s already exist", network->name); + goto done; } @@ -1005,11 +1135,18 @@ static void add_bss_to_network(struct g_supplicant_bss *bss) network->ssid_len = bss->ssid_len; memcpy(network->ssid, bss->ssid, bss->ssid_len); network->signal = bss->signal; + network->frequency = bss->frequency; + network->best_bss = bss; network->wps = FALSE; - if ((bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPS) != 0) + if ((bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPS) != 0) { network->wps = TRUE; + network->wps_capabilities |= bss->wps_capabilities; + } + + SUPPLICANT_DBG("New network %s created", network->name); + network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, remove_bss); @@ -1022,6 +1159,12 @@ static void add_bss_to_network(struct g_supplicant_bss *bss) callback_network_added(network); done: + if (bss->signal > network->signal) { + network->signal = bss->signal; + network->best_bss = bss; + callback_network_changed(network, "Signal"); + } + g_hash_table_replace(interface->bss_mapping, bss->path, network); g_hash_table_replace(network->bss_table, bss->path, bss); @@ -1152,13 +1295,19 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data) const unsigned char WPS_OUI[] = { 0x00, 0x50, 0xf2, 0x04 }; unsigned char *ie, *ie_end; DBusMessageIter array; + unsigned int value; int ie_len; #define WMM_WPA1_WPS_INFO 221 #define WPS_INFO_MIN_LEN 6 #define WPS_VERSION_TLV 0x104A #define WPS_STATE_TLV 0x1044 +#define WPS_METHODS_TLV 0x1012 +#define WPS_REGISTRAR_TLV 0x1041 #define WPS_VERSION 0x10 +#define WPS_PBC 0x04 +#define WPS_PIN 0x00 +#define WPS_CONFIGURED 0x02 dbus_message_iter_recurse(iter, &array); dbus_message_iter_get_fixed_array(&array, &ie, &ie_len); @@ -1166,21 +1315,58 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data) if (ie == NULL || ie_len < 2) return; - for (ie_end = ie+ie_len; ie+ie[1]+1 <= ie_end; ie += ie[1]+2) { + for (ie_end = ie + ie_len; ie < ie_end && ie + ie[1] + 1 <= ie_end; + ie += ie[1] + 2) { + if (ie[0] != WMM_WPA1_WPS_INFO || ie[1] < WPS_INFO_MIN_LEN || memcmp(ie+2, WPS_OUI, sizeof(WPS_OUI)) != 0) continue; SUPPLICANT_DBG("IE: match WPS_OUI"); - if (get_tlv(&ie[6], ie[1], - WPS_VERSION_TLV) == WPS_VERSION && - get_tlv(&ie[6], ie[1], - WPS_STATE_TLV) != 0) + value = get_tlv(&ie[6], ie[1], WPS_STATE_TLV); + if (get_tlv(&ie[6], ie[1], WPS_VERSION_TLV) == WPS_VERSION && + value != 0) { bss->keymgmt |= G_SUPPLICANT_KEYMGMT_WPS; + + if (value == WPS_CONFIGURED) + bss->wps_capabilities |= + G_SUPPLICANT_WPS_CONFIGURED; + } + + value = get_tlv(&ie[6], ie[1], WPS_METHODS_TLV); + if (value != 0) { + if (GUINT16_FROM_BE(value) == WPS_PBC) + bss->wps_capabilities |= G_SUPPLICANT_WPS_PBC; + if (GUINT16_FROM_BE(value) == WPS_PIN) + bss->wps_capabilities |= G_SUPPLICANT_WPS_PIN; + } else + bss->wps_capabilities |= + G_SUPPLICANT_WPS_PBC | G_SUPPLICANT_WPS_PIN; + + /* If the AP sends this it means it's advertizing + * as a registrar and the WPS process is launched + * on its side */ + if (get_tlv(&ie[6], ie[1], WPS_REGISTRAR_TLV) != 0) + bss->wps_capabilities |= G_SUPPLICANT_WPS_REGISTRAR; + + SUPPLICANT_DBG("WPS Methods 0x%x", bss->wps_capabilities); } } +static void bss_compute_security(struct g_supplicant_bss *bss) +{ + if (bss->ieee8021x == TRUE) + bss->security = G_SUPPLICANT_SECURITY_IEEE8021X; + else if (bss->psk == TRUE) + bss->security = G_SUPPLICANT_SECURITY_PSK; + else if (bss->privacy == TRUE) + bss->security = G_SUPPLICANT_SECURITY_WEP; + else + bss->security = G_SUPPLICANT_SECURITY_NONE; +} + + static void bss_property(const char *key, DBusMessageIter *iter, void *user_data) { @@ -1191,19 +1377,8 @@ static void bss_property(const char *key, DBusMessageIter *iter, SUPPLICANT_DBG("key %s", key); - if (key == NULL) { - if (bss->ieee8021x == TRUE) - bss->security = G_SUPPLICANT_SECURITY_IEEE8021X; - else if (bss->psk == TRUE) - bss->security = G_SUPPLICANT_SECURITY_PSK; - else if (bss->privacy == TRUE) - bss->security = G_SUPPLICANT_SECURITY_WEP; - else - bss->security = G_SUPPLICANT_SECURITY_NONE; - - add_bss_to_network(bss); + if (key == NULL) return; - } if (g_strcmp0(key, "BSSID") == 0) { DBusMessageIter array; @@ -1350,7 +1525,9 @@ static void interface_bss_added_with_keys(DBusMessageIter *iter, return; supplicant_dbus_property_foreach(iter, bss_property, bss); - bss_property(NULL, NULL, bss); + + bss_compute_security(bss); + add_or_replace_bss_to_network(bss); } static void interface_bss_added_without_keys(DBusMessageIter *iter, @@ -1367,6 +1544,32 @@ static void interface_bss_added_without_keys(DBusMessageIter *iter, supplicant_dbus_property_get_all(bss->path, SUPPLICANT_INTERFACE ".BSS", bss_property, bss); + + bss_compute_security(bss); + add_or_replace_bss_to_network(bss); +} + +static void update_signal(gpointer key, gpointer value, + gpointer user_data) +{ + struct g_supplicant_bss *bss = value; + GSupplicantNetwork *network = user_data; + + if (bss->signal > network->signal) { + network->signal = bss->signal; + network->best_bss = bss; + } +} + +static void update_network_signal(GSupplicantNetwork *network) +{ + if (g_hash_table_size(network->bss_table) <= 1) + return; + + g_hash_table_foreach(network->bss_table, + update_signal, network); + + SUPPLICANT_DBG("New network signal %d", network->signal); } static void interface_bss_removed(DBusMessageIter *iter, void *user_data) @@ -1388,6 +1591,8 @@ static void interface_bss_removed(DBusMessageIter *iter, void *user_data) g_hash_table_remove(interface->bss_mapping, path); g_hash_table_remove(network->bss_table, path); + update_network_signal(network); + if (g_hash_table_size(network->bss_table) == 0) g_hash_table_remove(interface->network_table, network->group); } @@ -1825,6 +2030,7 @@ static void signal_bss_changed(const char *path, DBusMessageIter *iter) { GSupplicantInterface *interface; GSupplicantNetwork *network; + GSupplicantSecurity old_security; struct g_supplicant_bss *bss; SUPPLICANT_DBG(""); @@ -1842,6 +2048,60 @@ static void signal_bss_changed(const char *path, DBusMessageIter *iter) return; supplicant_dbus_property_foreach(iter, bss_property, bss); + + old_security = network->security; + bss_compute_security(bss); + + if (old_security != bss->security) { + struct g_supplicant_bss *new_bss; + + SUPPLICANT_DBG("New network security for %s", bss->ssid); + + /* Security change policy: + * - we first copy the current bss into a new one with + * its own pointer (path) + * - we remove the current bss related nework which will + * tell the plugin about such removal. This is done due + * to the fact that a security change means a group change + * so a complete network change. + * (current bss becomes invalid as well) + * - we add the new bss: it adds new network and tell the + * plugin about it. */ + + new_bss = g_try_new0(struct g_supplicant_bss, 1); + if (new_bss == NULL) + return; + + memcpy(new_bss, bss, sizeof(struct g_supplicant_bss)); + new_bss->path = g_strdup(bss->path); + + g_hash_table_remove(interface->network_table, network->group); + + add_or_replace_bss_to_network(new_bss); + + return; + } + + if (bss->signal == network->signal) + return; + + /* + * If the new signal is lower than the SSID signal, we need + * to check for the new maximum. + */ + if (bss->signal < network->signal) { + if (bss != network->best_bss) + return; + network->signal = bss->signal; + update_network_signal(network); + } else { + network->signal = bss->signal; + network->best_bss = bss; + } + + SUPPLICANT_DBG("New network signal for %s %d dBm", network->ssid, network->signal); + + callback_network_changed(network, "Signal"); } static void wps_credentials(const char *key, DBusMessageIter *iter, @@ -2086,6 +2346,13 @@ struct interface_connect_data { void *user_data; }; +struct interface_scan_data { + GSupplicantInterface *interface; + GSupplicantInterfaceCallback callback; + GSupplicantScanParams *scan_params; + void *user_data; +}; + static void interface_create_property(const char *key, DBusMessageIter *iter, void *user_data) { @@ -2185,7 +2452,6 @@ static void interface_get_result(const char *error, if (error != NULL) { SUPPLICANT_DBG("Interface not created yet"); - err = -EIO; goto create; } @@ -2341,9 +2607,11 @@ int g_supplicant_interface_remove(GSupplicantInterface *interface, static void interface_scan_result(const char *error, DBusMessageIter *iter, void *user_data) { - struct interface_data *data = user_data; + struct interface_scan_data *data = user_data; if (error != NULL) { + SUPPLICANT_DBG("error %s", error); + if (data->callback != NULL) data->callback(-EIO, data->interface, data->user_data); } else { @@ -2351,27 +2619,139 @@ static void interface_scan_result(const char *error, data->interface->scan_data = data->user_data; } + if (data != NULL && data->scan_params != NULL) + g_supplicant_free_scan_params(data->scan_params); + dbus_free(data); } +static void add_scan_frequency(DBusMessageIter *iter, unsigned int freq) +{ + DBusMessageIter data; + unsigned int width = 0; /* Not used by wpa_supplicant atm */ + + dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &data); + + dbus_message_iter_append_basic(&data, DBUS_TYPE_UINT32, &freq); + dbus_message_iter_append_basic(&data, DBUS_TYPE_UINT32, &width); + + dbus_message_iter_close_container(iter, &data); +} + +static void add_scan_frequencies(DBusMessageIter *iter, + void *user_data) +{ + GSupplicantScanParams *scan_data = user_data; + unsigned int freq; + int i; + + for (i = 0; i < scan_data->num_ssids; i++) { + freq = scan_data->freqs[i]; + if (!freq) + break; + + add_scan_frequency(iter, freq); + } +} + +static void append_ssid(DBusMessageIter *iter, + const void *ssid, unsigned int len) +{ + DBusMessageIter array; + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, &array); + + dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, + &ssid, len); + dbus_message_iter_close_container(iter, &array); +} + +static void append_ssids(DBusMessageIter *iter, void *user_data) +{ + GSupplicantScanParams *scan_data = user_data; + GSList *list; + + for (list = scan_data->ssids; list; list = list->next) { + struct scan_ssid *scan_ssid = list->data; + + append_ssid(iter, scan_ssid->ssid, scan_ssid->ssid_len); + } +} + +static void supplicant_add_scan_frequency(DBusMessageIter *dict, + supplicant_dbus_array_function function, + void *user_data) +{ + GSupplicantScanParams *scan_params = user_data; + DBusMessageIter entry, value, array; + const char *key = "Channels"; + + if (scan_params->freqs && scan_params->freqs[0] != 0) { + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, + NULL, &entry); + + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); + + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, + DBUS_TYPE_ARRAY_AS_STRING + DBUS_STRUCT_BEGIN_CHAR_AS_STRING + DBUS_TYPE_UINT32_AS_STRING + DBUS_TYPE_UINT32_AS_STRING + DBUS_STRUCT_END_CHAR_AS_STRING, + &value); + + dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY, + DBUS_STRUCT_BEGIN_CHAR_AS_STRING + DBUS_TYPE_UINT32_AS_STRING + DBUS_TYPE_UINT32_AS_STRING + DBUS_STRUCT_END_CHAR_AS_STRING, + &array); + + if (function) + function(&array, user_data); + + dbus_message_iter_close_container(&value, &array); + dbus_message_iter_close_container(&entry, &value); + dbus_message_iter_close_container(dict, &entry); + } +} + static void interface_scan_params(DBusMessageIter *iter, void *user_data) { DBusMessageIter dict; const char *type = "passive"; + struct interface_scan_data *data = user_data; supplicant_dbus_dict_open(iter, &dict); - supplicant_dbus_dict_append_basic(&dict, "Type", - DBUS_TYPE_STRING, &type); + if (data && data->scan_params) { + type = "active"; + + supplicant_dbus_dict_append_basic(&dict, "Type", + DBUS_TYPE_STRING, &type); + + supplicant_dbus_dict_append_array(&dict, "SSIDs", + DBUS_TYPE_STRING, + append_ssids, + data->scan_params); + + supplicant_add_scan_frequency(&dict, add_scan_frequencies, + data->scan_params); + } else + supplicant_dbus_dict_append_basic(&dict, "Type", + DBUS_TYPE_STRING, &type); supplicant_dbus_dict_close(iter, &dict); } int g_supplicant_interface_scan(GSupplicantInterface *interface, + GSupplicantScanParams *scan_data, GSupplicantInterfaceCallback callback, void *user_data) { - struct interface_data *data; + struct interface_scan_data *data; + int ret; if (interface == NULL) return -EINVAL; @@ -2404,10 +2784,39 @@ int g_supplicant_interface_scan(GSupplicantInterface *interface, data->interface = interface; data->callback = callback; data->user_data = user_data; + data->scan_params = scan_data; - return supplicant_dbus_method_call(interface->path, + ret = supplicant_dbus_method_call(interface->path, SUPPLICANT_INTERFACE ".Interface", "Scan", interface_scan_params, interface_scan_result, data); + + if (ret < 0) + dbus_free(data); + + return ret; +} + +static int parse_supplicant_error(DBusMessageIter *iter) +{ + int err = -ECANCELED; + char *key; + + /* If the given passphrase is malformed wpa_s returns + * "invalid message format" but this error should be interpreted as + * invalid-key. + */ + while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) { + dbus_message_iter_get_basic(iter, &key); + if (strncmp(key, "psk", 3) == 0 || + strncmp(key, "wep_key", 7) == 0 || + strcmp(key, "invalid message format") == 0) { + err = -ENOKEY; + break; + } + dbus_message_iter_next(iter); + } + + return err; } static void interface_select_network_result(const char *error, @@ -2419,8 +2828,10 @@ static void interface_select_network_result(const char *error, SUPPLICANT_DBG(""); err = 0; - if (error != NULL) - err = -EIO; + if (error != NULL) { + SUPPLICANT_DBG("SelectNetwork error %s", error); + err = parse_supplicant_error(iter); + } if (data->callback != NULL) data->callback(err, data->interface, data->user_data); @@ -2445,6 +2856,7 @@ static void interface_add_network_result(const char *error, struct interface_connect_data *data = user_data; GSupplicantInterface *interface = data->interface; const char *path; + int err; if (error != NULL) goto error; @@ -2466,6 +2878,11 @@ static void interface_add_network_result(const char *error, return; error: + SUPPLICANT_DBG("AddNetwork error %s", error); + err = parse_supplicant_error(iter); + if (data->callback != NULL) + data->callback(err, data->interface, data->user_data); + g_free(interface->network_path); interface->network_path = NULL; g_free(data->ssid); @@ -2528,13 +2945,35 @@ static void add_network_security_wep(DBusMessageIter *dict, } } +static dbus_bool_t is_psk_raw_key(const char *psk) +{ + int i; + + /* A raw key is always 64 bytes length... */ + if (strlen(psk) != 64) + return FALSE; + + /* ... and its content is in hex representation */ + for (i = 0; i < 64; i++) + if (!isxdigit((unsigned char) psk[i])) + return FALSE; + + return TRUE; +} + static void add_network_security_psk(DBusMessageIter *dict, GSupplicantSSID *ssid) { - if (ssid->passphrase && strlen(ssid->passphrase) > 0) + if (ssid->passphrase && strlen(ssid->passphrase) > 0) { + if (is_psk_raw_key(ssid->passphrase) == TRUE) + supplicant_dbus_dict_append_fixed_array(dict, + "psk", DBUS_TYPE_BYTE, + &ssid->passphrase, 64); + else supplicant_dbus_dict_append_basic(dict, "psk", - DBUS_TYPE_STRING, + DBUS_TYPE_STRING, &ssid->passphrase); + } } static void add_network_security_tls(DBusMessageIter *dict, @@ -2583,7 +3022,7 @@ static void add_network_security_peap(DBusMessageIter *dict, * The 2nd phase authentication method * The 2nd phase passphrase * - * The Client certificate is optional although strongly required + * The Client certificate is optional although strongly recommended * When setting it, we need in addition * The Client private key file * The Client private key file password @@ -2591,9 +3030,6 @@ static void add_network_security_peap(DBusMessageIter *dict, if (ssid->passphrase == NULL) return; - if (ssid->ca_cert_path == NULL) - return; - if (ssid->phase2_auth == NULL) return; @@ -2628,7 +3064,8 @@ static void add_network_security_peap(DBusMessageIter *dict, DBUS_TYPE_STRING, &ssid->passphrase); - supplicant_dbus_dict_append_basic(dict, "ca_cert", + if (ssid->ca_cert_path) + supplicant_dbus_dict_append_basic(dict, "ca_cert", DBUS_TYPE_STRING, &ssid->ca_cert_path); @@ -2769,6 +3206,7 @@ static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid) case G_SUPPLICANT_SECURITY_WEP: key_mgmt = "NONE"; add_network_security_wep(dict, ssid); + add_network_security_ciphers(dict, ssid); break; case G_SUPPLICANT_SECURITY_PSK: key_mgmt = "WPA-PSK"; @@ -2825,6 +3263,10 @@ static void interface_add_network_params(DBusMessageIter *iter, void *user_data) supplicant_dbus_dict_append_basic(&dict, "frequency", DBUS_TYPE_UINT32, &ssid->freq); + if (ssid->bgscan != NULL) + supplicant_dbus_dict_append_basic(&dict, "bgscan", + DBUS_TYPE_STRING, &ssid->bgscan); + add_network_mode(&dict, ssid); add_network_security(&dict, ssid); @@ -3002,8 +3444,10 @@ static void interface_disconnect_result(const char *error, /* If we are disconnecting from previous WPS successful * association. i.e.: it did not went through AddNetwork, * and interface->network_path was never set. */ - if (data->interface->network_path == NULL) + if (data->interface->network_path == NULL) { + dbus_free(data); return; + } network_remove(data); } @@ -3162,7 +3606,7 @@ void g_supplicant_unregister(const GSupplicantCallbacks *callbacks) callback_system_killed(); if (interface_table != NULL) { - g_hash_table_foreach(interface_table, + g_hash_table_foreach(interface_table, unregister_remove_interface, NULL); g_hash_table_destroy(interface_table); interface_table = NULL;