X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=plugins%2Fsupplicant.c;h=a9c524c27c99ea189ee5c12b3ac22856005d1786;hb=cd07fbeb1af81232dfb452ec7494bdc33051371e;hp=2ef95fe577a30198cd1450e2a105b2eb2aeb3a8a;hpb=9bab56da9307eb687e9c80eb2640f210fc5de21e;p=platform%2Fupstream%2Fconnman.git diff --git a/plugins/supplicant.c b/plugins/supplicant.c index 2ef95fe..a9c524c 100644 --- a/plugins/supplicant.c +++ b/plugins/supplicant.c @@ -252,6 +252,15 @@ static int get_range(struct supplicant_task *task) close(fd); + if (err < 0) + task->range->max_qual.updated |= IW_QUAL_ALL_INVALID; + + connman_info("%s {scan} capabilities 0x%02x", task->ifname, + task->range->scan_capa); + + connman_info("%s {quality} flags 0x%02x", task->ifname, + task->range->max_qual.updated); + return err; } @@ -364,15 +373,12 @@ static int add_interface(struct supplicant_task *task) dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &task->ifname); - 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); + connman_dbus_dict_open(&array, &dict); - connman_dbus_dict_append_variant(&dict, "driver", + connman_dbus_dict_append_basic(&dict, "driver", DBUS_TYPE_STRING, &driver); - dbus_message_iter_close_container(&array, &dict); + connman_dbus_dict_close(&array, &dict); if (dbus_connection_send_with_reply(connection, message, &call, TIMEOUT) == FALSE) { @@ -751,6 +757,118 @@ static int disconnect_network(struct supplicant_task *task) return 0; } +static int set_network_tls(struct connman_network *network, + DBusMessageIter *dict) +{ + const char *private_key, *client_cert, *ca_cert; + const char *private_key_password; + + /* + * For TLS, we at least need a key, the client cert, + * and a passhprase. + * Server cert is optional. + */ + client_cert = connman_network_get_string(network, + "WiFi.ClientCertFile"); + if (client_cert == NULL) + return -EINVAL; + + private_key = connman_network_get_string(network, + "WiFi.PrivateKeyFile"); + if (private_key == NULL) + return -EINVAL; + + private_key_password = connman_network_get_string(network, + "WiFi.PrivateKeyPassphrase"); + if (private_key_password == NULL) + return -EINVAL; + + ca_cert = connman_network_get_string(network, "WiFi.CACertFile"); + if (ca_cert) + connman_dbus_dict_append_basic(dict, "ca_cert", + DBUS_TYPE_STRING, &ca_cert); + + DBG("client cert %s private key %s", client_cert, private_key); + + connman_dbus_dict_append_basic(dict, "private_key", + DBUS_TYPE_STRING, &private_key); + connman_dbus_dict_append_basic(dict, "private_key_passwd", + DBUS_TYPE_STRING, + &private_key_password); + connman_dbus_dict_append_basic(dict, "client_cert", + DBUS_TYPE_STRING, &client_cert); + + return 0; +} + +static int set_network_peap(struct connman_network *network, + DBusMessageIter *dict, const char *passphrase) +{ + const char *client_cert, *ca_cert, *phase2; + char *phase2_auth; + + /* + * For PEAP, we at least need the sever cert, a 2nd + * phase authentication and a passhprase. + * Client cert is optional although strongly required + * When setting the client cert, we then need a private + * key as well. + */ + ca_cert = connman_network_get_string(network, "WiFi.CACertFile"); + if (ca_cert == NULL) + return -EINVAL; + + phase2 = connman_network_get_string(network, "WiFi.Phase2"); + if (phase2 == NULL) + return -EINVAL; + + DBG("CA cert %s phase2 auth %s", ca_cert, phase2); + + client_cert = connman_network_get_string(network, + "WiFi.ClientCertFile"); + if (client_cert) { + const char *private_key, *private_key_password; + + private_key = connman_network_get_string(network, + "WiFi.PrivateKeyFile"); + if (private_key == NULL) + return -EINVAL; + + private_key_password = + connman_network_get_string(network, + "WiFi.PrivateKeyPassphrase"); + if (private_key_password == NULL) + return -EINVAL; + + connman_dbus_dict_append_basic(dict, "client_cert", + DBUS_TYPE_STRING, &client_cert); + + connman_dbus_dict_append_basic(dict, "private_key", + DBUS_TYPE_STRING, &private_key); + + connman_dbus_dict_append_basic(dict, "private_key_passwd", + DBUS_TYPE_STRING, + &private_key_password); + + DBG("client cert %s private key %s", client_cert, private_key); + } + + phase2_auth = g_strdup_printf("\"auth=%s\"", phase2); + + connman_dbus_dict_append_basic(dict, "password", + DBUS_TYPE_STRING, &passphrase); + + connman_dbus_dict_append_basic(dict, "ca_cert", + DBUS_TYPE_STRING, &ca_cert); + + connman_dbus_dict_append_basic(dict, "phase2", + DBUS_TYPE_STRING, &phase2_auth); + + g_free(phase2_auth); + + return 0; +} + static int set_network(struct supplicant_task *task, const unsigned char *network, int len, const char *address, const char *security, @@ -775,30 +893,92 @@ static int set_network(struct supplicant_task *task, 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); + connman_dbus_dict_open(&array, &dict); - connman_dbus_dict_append_variant(&dict, "scan_ssid", + connman_dbus_dict_append_basic(&dict, "scan_ssid", DBUS_TYPE_UINT32, &scan_ssid); if (network) - connman_dbus_dict_append_array(&dict, "ssid", + connman_dbus_dict_append_fixed_array(&dict, "ssid", DBUS_TYPE_BYTE, &network, len); else if (address) - connman_dbus_dict_append_variant(&dict, "bssid", + connman_dbus_dict_append_basic(&dict, "bssid", DBUS_TYPE_STRING, &address); - if (g_ascii_strcasecmp(security, "wpa") == 0 || + if (g_ascii_strcasecmp(security, "psk") == 0 || + g_ascii_strcasecmp(security, "wpa") == 0 || g_ascii_strcasecmp(security, "rsn") == 0) { const char *key_mgmt = "WPA-PSK"; - connman_dbus_dict_append_variant(&dict, "key_mgmt", + connman_dbus_dict_append_basic(&dict, "key_mgmt", DBUS_TYPE_STRING, &key_mgmt); if (passphrase && strlen(passphrase) > 0) - connman_dbus_dict_append_variant(&dict, "psk", + connman_dbus_dict_append_basic(&dict, "psk", DBUS_TYPE_STRING, &passphrase); + } else if (g_ascii_strcasecmp(security, "ieee8021x") == 0) { + struct connman_network *network = task->network; + const char *key_mgmt = "WPA-EAP", *eap, *identity; + char *eap_value; + + /* + * If our private key password is unset, + * we use the supplied passphrase. That is needed + * for PEAP where 2 passphrases (identity and client + * cert may have to be provided. + */ + if (connman_network_get_string(network, + "WiFi.PrivateKeyPassphrase") == NULL) + connman_network_set_string(network, + "WiFi.PrivateKeyPassphrase", + passphrase); + + eap = connman_network_get_string(network, "WiFi.EAP"); + if (eap == NULL) + goto invalid; + + /* We must have an identity for both PEAP and TLS */ + identity = connman_network_get_string(network, "WiFi.Identity"); + if (identity == NULL) + goto invalid; + + DBG("key_mgmt %s eap %s identity %s", key_mgmt, eap, identity); + + if (g_strcmp0(eap, "tls") == 0) { + int err; + + err = set_network_tls(network, &dict); + if (err < 0) { + dbus_message_unref(message); + return err; + } + } else if (g_strcmp0(eap, "peap") == 0) { + int err; + + err = set_network_peap(network, &dict, passphrase); + if (err < 0) { + dbus_message_unref(message); + return err; + } + } else { + connman_error("Unknown EAP %s", eap); + goto invalid; + } + + /* wpa_supplicant only accepts upper case EAPs */ + eap_value = g_ascii_strup(eap, -1); + + connman_dbus_dict_append_basic(&dict, "key_mgmt", + DBUS_TYPE_STRING, + &key_mgmt); + connman_dbus_dict_append_basic(&dict, "eap", + DBUS_TYPE_STRING, + &eap_value); + connman_dbus_dict_append_basic(&dict, "identity", + DBUS_TYPE_STRING, + &identity); + + g_free(eap_value); + } else if (g_ascii_strcasecmp(security, "wep") == 0) { const char *key_mgmt = "NONE"; const char *auth_alg = "OPEN"; @@ -807,10 +987,10 @@ static int set_network(struct supplicant_task *task, if (task->mac80211 == TRUE) auth_alg = "OPEN SHARED"; - connman_dbus_dict_append_variant(&dict, "auth_alg", + connman_dbus_dict_append_basic(&dict, "auth_alg", DBUS_TYPE_STRING, &auth_alg); - connman_dbus_dict_append_variant(&dict, "key_mgmt", + connman_dbus_dict_append_basic(&dict, "key_mgmt", DBUS_TYPE_STRING, &key_mgmt); if (passphrase) { @@ -827,25 +1007,25 @@ static int set_network(struct supplicant_task *task, key[i] = (unsigned char) strtol(tmp, NULL, 16); } - connman_dbus_dict_append_array(&dict, + connman_dbus_dict_append_fixed_array(&dict, "wep_key0", DBUS_TYPE_BYTE, &key, size / 2); free(key); } else - connman_dbus_dict_append_variant(&dict, + connman_dbus_dict_append_basic(&dict, "wep_key0", DBUS_TYPE_STRING, &passphrase); - connman_dbus_dict_append_variant(&dict, "wep_tx_keyidx", + connman_dbus_dict_append_basic(&dict, "wep_tx_keyidx", DBUS_TYPE_STRING, &key_index); } } else { const char *key_mgmt = "NONE"; - connman_dbus_dict_append_variant(&dict, "key_mgmt", + connman_dbus_dict_append_basic(&dict, "key_mgmt", DBUS_TYPE_STRING, &key_mgmt); } - dbus_message_iter_close_container(&array, &dict); + connman_dbus_dict_close(&array, &dict); dbus_error_init(&error); @@ -866,6 +1046,10 @@ static int set_network(struct supplicant_task *task, dbus_message_unref(reply); return 0; + +invalid: + dbus_message_unref(message); + return -EINVAL; } static void scan_reply(DBusPendingCall *call, void *user_data) @@ -1148,7 +1332,7 @@ static void extract_wpaie(DBusMessageIter *value, dbus_message_iter_recurse(value, &array); dbus_message_iter_get_fixed_array(&array, &ie, &ie_len); - if (ie_len > 0) { + if (ie_len > 6) { result->has_wpa = TRUE; extract_rsn(result, ie + 6, ie_len - 6); } @@ -1164,7 +1348,7 @@ static void extract_rsnie(DBusMessageIter *value, dbus_message_iter_recurse(value, &array); dbus_message_iter_get_fixed_array(&array, &ie, &ie_len); - if (ie_len > 0) { + if (ie_len > 2) { result->has_rsn = TRUE; extract_rsn(result, ie + 2, ie_len - 2); } @@ -1201,7 +1385,7 @@ static void extract_capabilites(DBusMessageIter *value, static unsigned char calculate_strength(struct supplicant_task *task, struct supplicant_result *result) { - if (task->range->max_qual.qual == 0) { + if (result->quality == -1 || task->range->max_qual.qual == 0) { unsigned char strength; if (result->level > 0) @@ -1318,6 +1502,12 @@ static void properties_reply(DBusPendingCall *call, void *user_data) dbus_message_iter_next(&dict); } + DBG("capabilties %u frequency %d " + "quality %d noise %d level %d maxrate %d", + result.capabilities, result.frequency, + result.quality, result.noise, + result.level, result.maxrate); + if (result.path == NULL) goto done; @@ -1336,10 +1526,6 @@ static void properties_reply(DBusPendingCall *call, void *user_data) if (result.has_8021x == TRUE) security = "ieee8021x"; - else if (result.has_rsn == TRUE) - security = "rsn"; - else if (result.has_wpa == TRUE) - security = "wpa"; else if (result.has_psk == TRUE) security = "psk"; else if (result.has_wep == TRUE) @@ -1353,6 +1539,13 @@ static void properties_reply(DBusPendingCall *call, void *user_data) result.ssid, result.ssid_len, mode, security); + if (result.has_psk == TRUE) { + if (result.has_rsn == TRUE) + security = "rsn"; + else if (result.has_wpa == TRUE) + security = "wpa"; + } + network = connman_device_get_network(task->device, result.path); if (network == NULL) { int index; @@ -1613,7 +1806,9 @@ static int task_connect(struct supplicant_task *task) add_network(task); - set_network(task, ssid, ssid_len, address, security, passphrase); + err = set_network(task, ssid, ssid_len, address, security, passphrase); + if (err < 0) + return err; err = select_network(task); if (err < 0) @@ -1702,6 +1897,8 @@ static void state_change(struct supplicant_task *task, DBusMessage *msg) bssid, bssid_len); /* carrier on */ + connman_network_set_method(task->network, + CONNMAN_IPCONFIG_METHOD_DHCP); connman_network_set_connected(task->network, TRUE); break; @@ -1756,27 +1953,23 @@ badstate: oldstate, newstate); } -static DBusHandlerResult supplicant_filter(DBusConnection *conn, +static gboolean supplicant_filter(DBusConnection *conn, DBusMessage *msg, void *data) { struct supplicant_task *task; const char *member, *path; - 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; + return TRUE; path = dbus_message_get_path(msg); if (path == NULL) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + return TRUE; task = find_task_by_path(path); if (task == NULL) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + return TRUE; DBG("task %p member %s", task, member); @@ -1787,7 +1980,7 @@ static DBusHandlerResult supplicant_filter(DBusConnection *conn, else if (g_str_equal(member, "StateChange") == TRUE) state_change(task, msg); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + return TRUE; } int supplicant_start(struct connman_device *device) @@ -2018,9 +2211,8 @@ static void supplicant_remove(DBusConnection *conn, void *user_data) } } -static const char *supplicant_rule = "type=signal," - "interface=" SUPPLICANT_INTF ".Interface"; static guint watch; +static guint iface_watch; static int supplicant_create(void) { @@ -2033,18 +2225,20 @@ static int supplicant_create(void) DBG("connection %p", connection); - if (dbus_connection_add_filter(connection, - supplicant_filter, NULL, NULL) == FALSE) { - connection = connman_dbus_get_connection(); - return -EIO; - } - - dbus_bus_add_match(connection, supplicant_rule, NULL); - dbus_connection_flush(connection); - watch = g_dbus_add_service_watch(connection, SUPPLICANT_NAME, supplicant_probe, supplicant_remove, NULL, NULL); + iface_watch = g_dbus_add_signal_watch(connection, NULL, NULL, + SUPPLICANT_INTF ".Interface", + NULL, supplicant_filter, + NULL, NULL); + + if (watch == 0 || iface_watch == 0) { + g_dbus_remove_watch(connection, watch); + g_dbus_remove_watch(connection, iface_watch); + return -EIO; + } + return 0; } @@ -2055,13 +2249,8 @@ static void supplicant_destroy(void) DBG("connection %p", connection); - if (watch > 0) - g_dbus_remove_watch(connection, watch); - - dbus_bus_remove_match(connection, supplicant_rule, NULL); - dbus_connection_flush(connection); - - dbus_connection_remove_filter(connection, supplicant_filter, NULL); + g_dbus_remove_watch(connection, watch); + g_dbus_remove_watch(connection, iface_watch); dbus_connection_unref(connection); connection = NULL;