X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=plugins%2Fsupplicant.c;h=69e79eb2261800a23f208c761752b33236c885f5;hb=6e84765a8dda6c0cb5f13fbaf7bdecf9016c8de4;hp=c11b885850746c07a189d683bdeb84edfa687164;hpb=3f83680866994c2859b9b7286595f2d8d17accb8;p=connman diff --git a/plugins/supplicant.c b/plugins/supplicant.c index c11b885..69e79eb 100644 --- a/plugins/supplicant.c +++ b/plugins/supplicant.c @@ -23,14 +23,18 @@ #include #endif +#include +#include #include #include +#include #include #define CONNMAN_API_SUBJECT_TO_CHANGE -#include +#include #include +#include #include "inet.h" #include "supplicant.h" @@ -41,54 +45,136 @@ #define IEEE80211_CAP_IBSS 0x0002 #define IEEE80211_CAP_PRIVACY 0x0010 -static GSList *driver_list = NULL; - -static void process_state_change(struct connman_device *device, - enum supplicant_state state) -{ - GSList *list; - - for (list = driver_list; list; list = list->next) { - struct supplicant_driver *driver = list->data; - - if (driver->state_change) - driver->state_change(device, state); - } -} - -static void process_clear_results(struct connman_device *device) -{ - GSList *list; - - for (list = driver_list; list; list = list->next) { - struct supplicant_driver *driver = list->data; - - if (driver->clear_results) - driver->clear_results(device); - } -} - -static void process_scan_result(struct connman_device *device, - struct supplicant_network *network) -{ - GSList *list; - - for (list = driver_list; list; list = list->next) { - struct supplicant_driver *driver = list->data; +#define SUPPLICANT_NAME "fi.epitest.hostap.WPASupplicant" +#define SUPPLICANT_INTF "fi.epitest.hostap.WPASupplicant" +#define SUPPLICANT_PATH "/fi/epitest/hostap/WPASupplicant" + +/* Taken from "WPA Supplicant - Common definitions" */ +enum supplicant_state { + /** + * WPA_DISCONNECTED - Disconnected state + * + * This state indicates that client is not associated, but is likely to + * start looking for an access point. This state is entered when a + * connection is lost. + */ + WPA_DISCONNECTED, + + /** + * WPA_INACTIVE - Inactive state (wpa_supplicant disabled) + * + * This state is entered if there are no enabled networks in the + * configuration. wpa_supplicant is not trying to associate with a new + * network and external interaction (e.g., ctrl_iface call to add or + * enable a network) is needed to start association. + */ + WPA_INACTIVE, + + /** + * WPA_SCANNING - Scanning for a network + * + * This state is entered when wpa_supplicant starts scanning for a + * network. + */ + WPA_SCANNING, + + /** + * WPA_ASSOCIATING - Trying to associate with a BSS/SSID + * + * This state is entered when wpa_supplicant has found a suitable BSS + * to associate with and the driver is configured to try to associate + * with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this + * state is entered when the driver is configured to try to associate + * with a network using the configured SSID and security policy. + */ + WPA_ASSOCIATING, + + /** + * WPA_ASSOCIATED - Association completed + * + * This state is entered when the driver reports that association has + * been successfully completed with an AP. If IEEE 802.1X is used + * (with or without WPA/WPA2), wpa_supplicant remains in this state + * until the IEEE 802.1X/EAPOL authentication has been completed. + */ + WPA_ASSOCIATED, + + /** + * WPA_4WAY_HANDSHAKE - WPA 4-Way Key Handshake in progress + * + * This state is entered when WPA/WPA2 4-Way Handshake is started. In + * case of WPA-PSK, this happens when receiving the first EAPOL-Key + * frame after association. In case of WPA-EAP, this state is entered + * when the IEEE 802.1X/EAPOL authentication has been completed. + */ + WPA_4WAY_HANDSHAKE, + + /** + * WPA_GROUP_HANDSHAKE - WPA Group Key Handshake in progress + * + * This state is entered when 4-Way Key Handshake has been completed + * (i.e., when the supplicant sends out message 4/4) and when Group + * Key rekeying is started by the AP (i.e., when supplicant receives + * message 1/2). + */ + WPA_GROUP_HANDSHAKE, + + /** + * WPA_COMPLETED - All authentication completed + * + * This state is entered when the full authentication process is + * completed. In case of WPA2, this happens when the 4-Way Handshake is + * successfully completed. With WPA, this state is entered after the + * Group Key Handshake; with IEEE 802.1X (non-WPA) connection is + * completed after dynamic keys are received (or if not used, after + * the EAP authentication has been completed). With static WEP keys and + * plaintext connections, this state is entered when an association + * has been completed. + * + * This state indicates that the supplicant has completed its + * processing for the association phase and that data connection is + * fully configured. + */ + WPA_COMPLETED, + + /** + * WPA_INVALID - Invalid state (parsing error) + * + * This state is returned if the string input is invalid. It is not + * an official wpa_supplicant state. + */ + WPA_INVALID, +}; - if (driver->scan_result) - driver->scan_result(device, network); - } -} +struct supplicant_result { + char *path; + char *name; + char *addr; + unsigned char *ssid; + unsigned int ssid_len; + dbus_uint16_t capabilities; + gboolean adhoc; + gboolean has_wep; + gboolean has_wpa; + gboolean has_rsn; + gboolean has_wps; + dbus_int32_t quality; + dbus_int32_t noise; + dbus_int32_t level; + dbus_int32_t maxrate; +}; struct supplicant_task { int ifindex; - gchar *ifname; + char *ifname; struct connman_device *device; - gchar *path; + struct connman_network *network; + char *path; + char *netpath; gboolean created; - gchar *network; enum supplicant_state state; + gboolean noscan; + GSList *scan_results; }; static GSList *task_list = NULL; @@ -193,6 +279,12 @@ static int add_interface(struct supplicant_task *task) return -EIO; } + if (call == NULL) { + connman_error("D-Bus connection not available"); + dbus_message_unref(message); + return -EIO; + } + dbus_pending_call_set_notify(call, add_interface_reply, task, NULL); dbus_message_unref(message); @@ -263,6 +355,12 @@ static int create_interface(struct supplicant_task *task) return -EIO; } + if (call == NULL) { + connman_error("D-Bus connection not available"); + dbus_message_unref(message); + return -EIO; + } + dbus_pending_call_set_notify(call, get_interface_reply, task, NULL); dbus_message_unref(message); @@ -281,6 +379,10 @@ static void remove_interface_reply(DBusPendingCall *call, void *user_data) connman_device_set_powered(task->device, FALSE); + connman_device_unref(task->device); + + inet_ifdown(task->ifindex); + free_task(task); dbus_message_unref(reply); @@ -313,6 +415,12 @@ static int remove_interface(struct supplicant_task *task) return -EIO; } + if (call == NULL) { + connman_error("D-Bus connection not available"); + dbus_message_unref(message); + return -EIO; + } + dbus_pending_call_set_notify(call, remove_interface_reply, task, NULL); dbus_message_unref(message); @@ -367,7 +475,7 @@ static int add_network(struct supplicant_task *task) DBG("task %p", task); - if (task->network != NULL) + if (task->netpath != NULL) return -EALREADY; message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path, @@ -406,7 +514,7 @@ static int add_network(struct supplicant_task *task) DBG("path %s", path); - task->network = g_strdup(path); + task->netpath = g_strdup(path); dbus_message_unref(reply); @@ -420,7 +528,7 @@ static int remove_network(struct supplicant_task *task) DBG("task %p", task); - if (task->network == NULL) + if (task->netpath == NULL) return -EINVAL; message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path, @@ -428,7 +536,7 @@ static int remove_network(struct supplicant_task *task) if (message == NULL) return -ENOMEM; - dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->network, + dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->netpath, DBUS_TYPE_INVALID); dbus_error_init(&error); @@ -449,8 +557,8 @@ static int remove_network(struct supplicant_task *task) dbus_message_unref(reply); - g_free(task->network); - task->network = NULL; + g_free(task->netpath); + task->netpath = NULL; return 0; } @@ -462,7 +570,7 @@ static int select_network(struct supplicant_task *task) DBG("task %p", task); - if (task->network == NULL) + if (task->netpath == NULL) return -EINVAL; message = dbus_message_new_method_call(SUPPLICANT_NAME, task->path, @@ -470,7 +578,7 @@ static int select_network(struct supplicant_task *task) if (message == NULL) return -ENOMEM; - dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->network, + dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &task->netpath, DBUS_TYPE_INVALID); dbus_error_init(&error); @@ -501,10 +609,10 @@ static int enable_network(struct supplicant_task *task) DBG("task %p", task); - if (task->network == NULL) + if (task->netpath == NULL) return -EINVAL; - message = dbus_message_new_method_call(SUPPLICANT_NAME, task->network, + message = dbus_message_new_method_call(SUPPLICANT_NAME, task->netpath, SUPPLICANT_INTF ".Network", "enable"); if (message == NULL) return -ENOMEM; @@ -537,10 +645,10 @@ static int disable_network(struct supplicant_task *task) DBG("task %p", task); - if (task->network == NULL) + if (task->netpath == NULL) return -EINVAL; - message = dbus_message_new_method_call(SUPPLICANT_NAME, task->network, + message = dbus_message_new_method_call(SUPPLICANT_NAME, task->netpath, SUPPLICANT_INTF ".Network", "disable"); if (message == NULL) return -ENOMEM; @@ -568,7 +676,8 @@ static int disable_network(struct supplicant_task *task) static int set_network(struct supplicant_task *task, const unsigned char *network, int len, - const char *security, const char *passphrase) + const char *address, const char *security, + const char *passphrase) { DBusMessage *message, *reply; DBusMessageIter array, dict; @@ -576,10 +685,10 @@ static int set_network(struct supplicant_task *task, DBG("task %p", task); - if (task->network == NULL) + if (task->netpath == NULL) return -EINVAL; - message = dbus_message_new_method_call(SUPPLICANT_NAME, task->network, + message = dbus_message_new_method_call(SUPPLICANT_NAME, task->netpath, SUPPLICANT_INTF ".Network", "set"); if (message == NULL) return -ENOMEM; @@ -591,6 +700,14 @@ static int set_network(struct supplicant_task *task, DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); + if (address == NULL) { + dbus_uint32_t scan_ssid = 1; + connman_dbus_dict_append_variant(&dict, "scan_ssid", + DBUS_TYPE_UINT32, &scan_ssid); + } else + connman_dbus_dict_append_variant(&dict, "bssid", + DBUS_TYPE_STRING, &address); + connman_dbus_dict_append_array(&dict, "ssid", DBUS_TYPE_BYTE, &network, len); @@ -622,7 +739,7 @@ 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_array(&dict, "wep_key0", DBUS_TYPE_BYTE, &key, size / 2); free(key); @@ -686,8 +803,79 @@ static int initiate_scan(struct supplicant_task *task) return 0; } -static void extract_ssid(struct supplicant_network *network, - DBusMessageIter *value) +static char *build_group(const char *addr, + const unsigned char *ssid, unsigned int ssid_len, + const char *mode, const char *security) +{ + GString *str; + unsigned int i; + + if (ssid_len > 0 && ssid[0] != '\0') { + str = g_string_sized_new((ssid_len * 2) + 24); + if (str == NULL) + return NULL; + + for (i = 0; i < ssid_len; i++) + g_string_append_printf(str, "%02x", ssid[i]); + } else { + if (addr == NULL) + return NULL; + + str = g_string_sized_new(15 + 24); + if (str == NULL) + return NULL; + + g_string_append_printf(str, "hidden_%s", addr); + } + + g_string_append_printf(str, "_%s_%s", mode, security); + + return g_string_free(str, FALSE); +} + +static void extract_addr(DBusMessageIter *value, + struct supplicant_result *result) +{ + DBusMessageIter array; + struct ether_addr *eth; + unsigned char *addr; + int addr_len; + + dbus_message_iter_recurse(value, &array); + dbus_message_iter_get_fixed_array(&array, &addr, &addr_len); + + if (addr_len != 6) + return; + + eth = (void *) addr; + + result->addr = g_try_malloc0(18); + if (result->addr == NULL) + return; + + snprintf(result->addr, 18, "%02X:%02X:%02X:%02X:%02X:%02X", + eth->ether_addr_octet[0], + eth->ether_addr_octet[1], + eth->ether_addr_octet[2], + eth->ether_addr_octet[3], + eth->ether_addr_octet[4], + eth->ether_addr_octet[5]); + + result->path = g_try_malloc0(18); + if (result->path == NULL) + return; + + snprintf(result->path, 18, "%02x%02x%02x%02x%02x%02x", + eth->ether_addr_octet[0], + eth->ether_addr_octet[1], + eth->ether_addr_octet[2], + eth->ether_addr_octet[3], + eth->ether_addr_octet[4], + eth->ether_addr_octet[5]); +} + +static void extract_ssid(DBusMessageIter *value, + struct supplicant_result *result) { DBusMessageIter array; unsigned char *ssid; @@ -699,22 +887,39 @@ static void extract_ssid(struct supplicant_network *network, if (ssid_len < 1) return; - network->ssid = g_try_malloc(ssid_len); - if (network->ssid == NULL) + if (ssid[0] == '\0') return; - memcpy(network->ssid, ssid, ssid_len); - network->ssid_len = ssid_len; + result->ssid = g_try_malloc(ssid_len); + if (result->ssid == NULL) + return; + + memcpy(result->ssid, ssid, ssid_len); + result->ssid_len = ssid_len; - network->identifier = g_try_malloc0(ssid_len + 1); - if (network->identifier == NULL) + result->name = g_try_malloc0(ssid_len + 1); + if (result->name == NULL) return; - memcpy(network->identifier, ssid, ssid_len); + memcpy(result->name, ssid, ssid_len); +} + +static void extract_wpaie(DBusMessageIter *value, + struct supplicant_result *result) +{ + DBusMessageIter array; + unsigned char *ie; + int ie_len; + + dbus_message_iter_recurse(value, &array); + dbus_message_iter_get_fixed_array(&array, &ie, &ie_len); + + if (ie_len > 0) + result->has_wpa = TRUE; } -static void extract_wpaie(struct supplicant_network *network, - DBusMessageIter *value) +static void extract_rsnie(DBusMessageIter *value, + struct supplicant_result *result) { DBusMessageIter array; unsigned char *ie; @@ -724,11 +929,11 @@ static void extract_wpaie(struct supplicant_network *network, dbus_message_iter_get_fixed_array(&array, &ie, &ie_len); if (ie_len > 0) - network->has_wpa = TRUE; + result->has_rsn = TRUE; } -static void extract_rsnie(struct supplicant_network *network, - DBusMessageIter *value) +static void extract_wpsie(DBusMessageIter *value, + struct supplicant_result *result) { DBusMessageIter array; unsigned char *ie; @@ -738,37 +943,51 @@ static void extract_rsnie(struct supplicant_network *network, dbus_message_iter_get_fixed_array(&array, &ie, &ie_len); if (ie_len > 0) - network->has_rsn = TRUE; + result->has_wps = TRUE; } -static void extract_capabilites(struct supplicant_network *network, - DBusMessageIter *value) +static void extract_capabilites(DBusMessageIter *value, + struct supplicant_result *result) { - dbus_message_iter_get_basic(value, &network->capabilities); + dbus_message_iter_get_basic(value, &result->capabilities); - if (network->capabilities & IEEE80211_CAP_ESS) - network->adhoc = FALSE; - else if (network->capabilities & IEEE80211_CAP_IBSS) - network->adhoc = TRUE; + if (result->capabilities & IEEE80211_CAP_ESS) + result->adhoc = FALSE; + else if (result->capabilities & IEEE80211_CAP_IBSS) + result->adhoc = TRUE; - if (network->capabilities & IEEE80211_CAP_PRIVACY) - network->has_wep = TRUE; + if (result->capabilities & IEEE80211_CAP_PRIVACY) + result->has_wep = TRUE; } +static void get_properties(struct supplicant_task *task); + static void properties_reply(DBusPendingCall *call, void *user_data) { struct supplicant_task *task = user_data; - struct supplicant_network *network; + struct supplicant_result result; + struct connman_network *network; DBusMessage *reply; DBusMessageIter array, dict; + unsigned char strength; + const char *mode, *security; + char *group; DBG("task %p", task); reply = dbus_pending_call_steal_reply(call); + if (reply == NULL) { + get_properties(task); + return; + } - network = g_try_new0(struct supplicant_network, 1); - if (network == NULL) - goto done; + if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) { + dbus_message_unref(reply); + get_properties(task); + return; + } + + memset(&result, 0, sizeof(result)); dbus_message_iter_init(reply, &array); @@ -793,6 +1012,7 @@ static void properties_reply(DBusPendingCall *call, void *user_data) * ssid : a (97) * wpaie : a (97) * rsnie : a (97) + * wpsie : a (97) * frequency : i (105) * capabilities : q (113) * quality : i (105) @@ -801,61 +1021,159 @@ static void properties_reply(DBusPendingCall *call, void *user_data) * maxrate : i (105) */ - if (g_str_equal(key, "ssid") == TRUE) - extract_ssid(network, &value); + if (g_str_equal(key, "bssid") == TRUE) + extract_addr(&value, &result); + else if (g_str_equal(key, "ssid") == TRUE) + extract_ssid(&value, &result); else if (g_str_equal(key, "wpaie") == TRUE) - extract_wpaie(network, &value); + extract_wpaie(&value, &result); else if (g_str_equal(key, "rsnie") == TRUE) - extract_rsnie(network, &value); + extract_rsnie(&value, &result); + else if (g_str_equal(key, "wpsie") == TRUE) + extract_wpsie(&value, &result); else if (g_str_equal(key, "capabilities") == TRUE) - extract_capabilites(network, &value); + extract_capabilites(&value, &result); else if (g_str_equal(key, "quality") == TRUE) - dbus_message_iter_get_basic(&value, &network->quality); + dbus_message_iter_get_basic(&value, &result.quality); else if (g_str_equal(key, "noise") == TRUE) - dbus_message_iter_get_basic(&value, &network->noise); + dbus_message_iter_get_basic(&value, &result.noise); else if (g_str_equal(key, "level") == TRUE) - dbus_message_iter_get_basic(&value, &network->level); + dbus_message_iter_get_basic(&value, &result.level); else if (g_str_equal(key, "maxrate") == TRUE) - dbus_message_iter_get_basic(&value, &network->maxrate); - + dbus_message_iter_get_basic(&value, &result.maxrate); dbus_message_iter_next(&dict); } - process_scan_result(task->device, network); + if (result.path == NULL) + goto done; + + if (result.path[0] == '\0') + goto done; + + strength = result.quality; + + if (result.has_rsn == TRUE) + security = "wpa2"; + else if (result.has_wpa == TRUE) + security = "wpa"; + else if (result.has_wep == TRUE) + security = "wep"; + else + security = "none"; + + mode = (result.adhoc == TRUE) ? "adhoc" : "managed"; + + group = build_group(result.path, result.ssid, result.ssid_len, + mode, security); + + network = connman_device_get_network(task->device, result.path); + if (network == NULL) { + int index; + + network = connman_network_create(result.path, + CONNMAN_NETWORK_TYPE_WIFI); + if (network == NULL) + goto done; + + index = connman_device_get_index(task->device); + connman_network_set_index(network, index); + + connman_network_set_protocol(network, + CONNMAN_NETWORK_PROTOCOL_IP); + + connman_network_set_string(network, "Address", result.addr); + + connman_network_set_group(network, group); + + if (result.name != NULL && result.name[0] != '\0') + connman_network_set_string(network, "Name", result.name); + + connman_network_set_uint8(network, "Strength", strength); + + connman_network_set_string(network, "WiFi.Mode", mode); + connman_network_set_string(network, "WiFi.Security", security); + + if (connman_device_add_network(task->device, network) < 0) { + connman_network_unref(network); + goto done; + } + } + + connman_network_set_group(network, group); + + g_free(group); + + if (result.name != NULL && result.name[0] != '\0') + connman_network_set_string(network, "Name", result.name); + + connman_network_set_blob(network, "WiFi.SSID", + result.ssid, result.ssid_len); + + connman_network_set_string(network, "WiFi.Mode", mode); + + DBG("%s (%s %s) strength %d (%s)", + result.name, mode, security, strength, + (result.has_wps == TRUE) ? "WPS" : "no WPS"); + + connman_network_set_available(network, TRUE); + connman_network_set_uint8(network, "Strength", strength); - g_free(network->identifier); - g_free(network->ssid); - g_free(network); + connman_network_set_string(network, "WiFi.Security", security); done: + g_free(result.path); + g_free(result.addr); + g_free(result.name); + g_free(result.ssid); + dbus_message_unref(reply); + + get_properties(task); } -static int get_network_properties(struct supplicant_task *task, - const char *path) +static void get_properties(struct supplicant_task *task) { DBusMessage *message; DBusPendingCall *call; + char *path; + + path = g_slist_nth_data(task->scan_results, 0); + if (path == NULL) + goto noscan; message = dbus_message_new_method_call(SUPPLICANT_NAME, path, SUPPLICANT_INTF ".BSSID", "properties"); + + task->scan_results = g_slist_remove(task->scan_results, path); + g_free(path); + if (message == NULL) - return -ENOMEM; + goto noscan; if (dbus_connection_send_with_reply(connection, message, &call, TIMEOUT) == FALSE) { connman_error("Failed to get network properties"); dbus_message_unref(message); - return -EIO; + goto noscan; + } + + if (call == NULL) { + connman_error("D-Bus connection not available"); + dbus_message_unref(message); + goto noscan; } dbus_pending_call_set_notify(call, properties_reply, task, NULL); dbus_message_unref(message); - return 0; + return; + +noscan: + if (task->noscan == FALSE) + connman_device_set_scanning(task->device, FALSE); } static void scan_results_reply(DBusPendingCall *call, void *user_data) @@ -869,6 +1187,11 @@ static void scan_results_reply(DBusPendingCall *call, void *user_data) DBG("task %p", task); reply = dbus_pending_call_steal_reply(call); + if (reply == NULL) + goto noscan; + + if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) + goto done; dbus_error_init(&error); @@ -884,18 +1207,34 @@ static void scan_results_reply(DBusPendingCall *call, void *user_data) goto done; } - process_clear_results(task->device); + if (num_results == 0) + goto done; + + for (i = 0; i < num_results; i++) { + char *path = g_strdup(results[i]); + if (path == NULL) + continue; - for (i = 0; i < num_results; i++) - get_network_properties(task, results[i]); + task->scan_results = g_slist_append(task->scan_results, path); + } g_strfreev(results); + dbus_message_unref(reply); + + get_properties(task); + + return; + done: dbus_message_unref(reply); + +noscan: + if (task->noscan == FALSE) + connman_device_set_scanning(task->device, FALSE); } -static int scan_results_available(struct supplicant_task *task) +static void scan_results_available(struct supplicant_task *task) { DBusMessage *message; DBusPendingCall *call; @@ -906,31 +1245,60 @@ static int scan_results_available(struct supplicant_task *task) SUPPLICANT_INTF ".Interface", "scanResults"); if (message == NULL) - return -ENOMEM; + return; if (dbus_connection_send_with_reply(connection, message, &call, TIMEOUT) == FALSE) { connman_error("Failed to request scan result"); - dbus_message_unref(message); - return -EIO; + goto done; + } + + if (task->noscan == FALSE) + connman_device_set_scanning(task->device, TRUE); + + if (call == NULL) { + connman_error("D-Bus connection not available"); + goto done; } dbus_pending_call_set_notify(call, scan_results_reply, task, NULL); +done: dbus_message_unref(message); +} - return 0; +static enum supplicant_state string2state(const char *state) +{ + if (g_str_equal(state, "INACTIVE") == TRUE) + return WPA_INACTIVE; + else if (g_str_equal(state, "SCANNING") == TRUE) + return WPA_SCANNING; + else if (g_str_equal(state, "ASSOCIATING") == TRUE) + return WPA_ASSOCIATING; + else if (g_str_equal(state, "ASSOCIATED") == TRUE) + return WPA_ASSOCIATED; + else if (g_str_equal(state, "GROUP_HANDSHAKE") == TRUE) + return WPA_GROUP_HANDSHAKE; + else if (g_str_equal(state, "4WAY_HANDSHAKE") == TRUE) + return WPA_4WAY_HANDSHAKE; + else if (g_str_equal(state, "COMPLETED") == TRUE) + return WPA_COMPLETED; + else if (g_str_equal(state, "DISCONNECTED") == TRUE) + return WPA_DISCONNECTED; + else + return WPA_INVALID; } static void state_change(struct supplicant_task *task, DBusMessage *msg) { DBusError error; - const char *state, *previous; + const char *newstate, *oldstate; + enum supplicant_state state; dbus_error_init(&error); - if (dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &state, - DBUS_TYPE_STRING, &previous, + if (dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &newstate, + DBUS_TYPE_STRING, &oldstate, DBUS_TYPE_INVALID) == FALSE) { if (dbus_error_is_set(&error) == TRUE) { connman_error("%s", error.message); @@ -940,35 +1308,56 @@ static void state_change(struct supplicant_task *task, DBusMessage *msg) return; } - DBG("state %s ==> %s", previous, state); + DBG("state %s ==> %s", oldstate, newstate); - if (g_str_equal(state, "INACTIVE") == TRUE) - task->state = STATE_INACTIVE; - else if (g_str_equal(state, "SCANNING") == TRUE) - task->state = STATE_SCANNING; - else if (g_str_equal(state, "ASSOCIATING") == TRUE) - task->state = STATE_ASSOCIATING; - else if (g_str_equal(state, "ASSOCIATED") == TRUE) - task->state = STATE_ASSOCIATED; - else if (g_str_equal(state, "GROUP_HANDSHAKE") == TRUE) - task->state = STATE_4WAY_HANDSHAKE; - else if (g_str_equal(state, "4WAY_HANDSHAKE") == TRUE) - task->state = STATE_4WAY_HANDSHAKE; - else if (g_str_equal(state, "COMPLETED") == TRUE) - task->state = STATE_COMPLETED; - else if (g_str_equal(state, "DISCONNECTED") == TRUE) - task->state = STATE_DISCONNECTED; + state = string2state(newstate); + if (state == WPA_INVALID) + return; + + task->state = state; + + switch (task->state) { + case WPA_SCANNING: + task->noscan = TRUE; + connman_device_set_scanning(task->device, TRUE); + break; + case WPA_ASSOCIATING: + case WPA_ASSOCIATED: + case WPA_4WAY_HANDSHAKE: + case WPA_GROUP_HANDSHAKE: + task->noscan = TRUE; + break; + case WPA_COMPLETED: + case WPA_DISCONNECTED: + task->noscan = FALSE; + break; + case WPA_INACTIVE: + task->noscan = FALSE; + connman_device_set_scanning(task->device, FALSE); + break; + case WPA_INVALID: + break; + } - process_state_change(task->device, task->state); + if (task->network == NULL) + return; switch (task->state) { - case STATE_COMPLETED: + case WPA_COMPLETED: /* carrier on */ + connman_network_set_connected(task->network, TRUE); + connman_device_set_scanning(task->device, FALSE); break; - case STATE_DISCONNECTED: + case WPA_DISCONNECTED: /* carrier off */ + connman_network_set_connected(task->network, FALSE); + connman_device_set_scanning(task->device, FALSE); + break; + case WPA_ASSOCIATING: + connman_network_set_associating(task->network, TRUE); break; default: + connman_network_set_associating(task->network, FALSE); break; } } @@ -1017,15 +1406,17 @@ int supplicant_start(struct connman_device *device) task->ifindex = connman_device_get_index(device); task->ifname = inet_index2name(task->ifindex); - task->device = device; if (task->ifname == NULL) { g_free(task); return -ENOMEM; } + task->device = connman_device_ref(device); + task->created = FALSE; - task->state = STATE_INACTIVE; + task->noscan = FALSE; + task->state = WPA_INVALID; task_list = g_slist_append(task_list, task); @@ -1065,12 +1456,12 @@ int supplicant_scan(struct connman_device *device) return -ENODEV; switch (task->state) { - case STATE_SCANNING: + case WPA_SCANNING: return -EALREADY; - case STATE_ASSOCIATING: - case STATE_ASSOCIATED: - case STATE_4WAY_HANDSHAKE: - case STATE_GROUP_HANDSHAKE: + case WPA_ASSOCIATING: + case WPA_ASSOCIATED: + case WPA_4WAY_HANDSHAKE: + case WPA_GROUP_HANDSHAKE: return -EBUSY; default: break; @@ -1081,37 +1472,63 @@ int supplicant_scan(struct connman_device *device) return 0; } -int __supplicant_connect(struct connman_element *element, - const unsigned char *ssid, int ssid_len, - const char *security, const char *passphrase) +int supplicant_connect(struct connman_network *network) { struct supplicant_task *task; + const char *address, *security, *passphrase; + const void *ssid; + unsigned int ssid_len; + int index; + + DBG("network %p", network); - DBG("element %p", element); + address = connman_network_get_string(network, "Address"); + security = connman_network_get_string(network, "WiFi.Security"); + passphrase = connman_network_get_string(network, "WiFi.Passphrase"); - task = find_task_by_index(element->index); + ssid = connman_network_get_blob(network, "WiFi.SSID", &ssid_len); + + DBG("address %s security %s passphrase %s", + address, security, passphrase); + + if (security == NULL && passphrase == NULL) + return -EINVAL; + + if (g_str_equal(security, "none") == FALSE && passphrase == NULL) + return -EINVAL; + + index = connman_network_get_index(network); + + task = find_task_by_index(index); if (task == NULL) return -ENODEV; + task->network = connman_network_ref(network); + add_network(task); select_network(task); disable_network(task); - set_network(task, ssid, ssid_len, security, passphrase); + set_network(task, ssid, ssid_len, address, security, passphrase); enable_network(task); + connman_network_set_associating(task->network, TRUE); + return 0; } -int __supplicant_disconnect(struct connman_element *element) +int supplicant_disconnect(struct connman_network *network) { struct supplicant_task *task; + int index; - DBG("element %p", element); + DBG("network %p", network); - task = find_task_by_index(element->index); + index = connman_network_get_index(network); + + task = find_task_by_index(index); if (task == NULL) return -ENODEV; @@ -1119,6 +1536,10 @@ int __supplicant_disconnect(struct connman_element *element) remove_network(task); + connman_network_set_connected(task->network, FALSE); + + connman_network_unref(task->network); + return 0; } @@ -1140,6 +1561,8 @@ static void supplicant_activate(DBusConnection *conn) dbus_message_unref(message); } +static GSList *driver_list = NULL; + static void supplicant_probe(DBusConnection *conn, void *user_data) { GSList *list;