X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=plugins%2Fsupplicant.c;h=958200efd7c500d5853e52db456d275d29587a6f;hb=e6be58c2322fab098466d66816d99f67ae5a210f;hp=192a016b7688af7fc4c9ff9fb09f6ec2c11f45e8;hpb=36b19e423a2d66c0c9d722d4ee2fc65c03163b43;p=framework%2Fconnectivity%2Fconnman.git diff --git a/plugins/supplicant.c b/plugins/supplicant.c index 192a016..958200e 100644 --- a/plugins/supplicant.c +++ b/plugins/supplicant.c @@ -24,9 +24,14 @@ #endif #include +#include #include #include #include +#include +#include +#include +#include #include #include @@ -150,7 +155,8 @@ enum supplicant_state { struct supplicant_result { char *path; char *name; - char *addr; + unsigned char *addr; + unsigned int addr_len; unsigned char *ssid; unsigned int ssid_len; dbus_uint16_t capabilities; @@ -171,12 +177,16 @@ struct supplicant_task { char *ifname; struct connman_device *device; struct connman_network *network; + struct connman_network *pending_network; char *path; char *netpath; gboolean created; enum supplicant_state state; gboolean noscan; GSList *scan_results; + struct iw_range *range; + gboolean connecting; + gboolean disconnecting; }; static GSList *task_list = NULL; @@ -213,13 +223,82 @@ static struct supplicant_task *find_task_by_path(const char *path) for (list = task_list; list; list = list->next) { struct supplicant_task *task = list->data; - if (g_str_equal(task->path, path) == TRUE) + if (g_strcmp0(task->path, path) == 0) return task; } return NULL; } +static int get_range(struct supplicant_task *task) +{ + struct iwreq wrq; + int fd, err; + + fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) + return -1; + + memset(&wrq, 0, sizeof(struct iwreq)); + strncpy(wrq.ifr_name, task->ifname, IFNAMSIZ); + wrq.u.data.pointer = task->range; + wrq.u.data.length = sizeof(struct iw_range); + + err = ioctl(fd, SIOCGIWRANGE, &wrq); + + close(fd); + + return err; +} + +static char *get_bssid(struct connman_device *device) +{ + char *bssid; + unsigned char ioctl_bssid[ETH_ALEN]; + int ifindex; + char *ifname; + struct iwreq wrq; + int fd, err; + + ifindex = connman_device_get_index(device); + if (ifindex < 0) + return NULL; + + ifname = connman_inet_ifname(ifindex); + if (ifname == NULL) + return NULL; + + fd = socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + g_free(ifname); + return NULL; + } + + memset(&wrq, 0, sizeof(wrq)); + strncpy(wrq.ifr_name, ifname, IFNAMSIZ); + + err = ioctl(fd, SIOCGIWAP, &wrq); + + g_free(ifname); + close(fd); + + if (err < 0) + return NULL; + + memcpy(ioctl_bssid, wrq.u.ap_addr.sa_data, ETH_ALEN); + + bssid = g_try_malloc0(13); + if (bssid == NULL) + return NULL; + + snprintf(bssid, 13, "%02x%02x%02x%02x%02x%02x", + ioctl_bssid[0], ioctl_bssid[1], + ioctl_bssid[2], ioctl_bssid[3], + ioctl_bssid[4], ioctl_bssid[5]); + + return bssid; +} + static void add_interface_reply(DBusPendingCall *call, void *user_data) { struct supplicant_task *task = user_data; @@ -234,7 +313,7 @@ static void add_interface_reply(DBusPendingCall *call, void *user_data) return; if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) - goto done; + goto failed; dbus_error_init(&error); @@ -245,7 +324,7 @@ static void add_interface_reply(DBusPendingCall *call, void *user_data) dbus_error_free(&error); } else connman_error("Wrong arguments for add interface"); - goto done; + goto failed; } DBG("path %s", path); @@ -255,8 +334,16 @@ static void add_interface_reply(DBusPendingCall *call, void *user_data) connman_device_set_powered(task->device, TRUE); -done: dbus_message_unref(reply); + + return; + +failed: + task_list = g_slist_remove(task_list, task); + + connman_device_unref(task->device); + + free_task(task); } static int add_interface(struct supplicant_task *task) @@ -698,6 +785,7 @@ static int set_network(struct supplicant_task *task, DBusMessage *message, *reply; DBusMessageIter array, dict; DBusError error; + dbus_uint32_t scan_ssid = 1; DBG("task %p", task); @@ -716,11 +804,10 @@ 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, "scan_ssid", + DBUS_TYPE_UINT32, &scan_ssid); + + if (address) connman_dbus_dict_append_variant(&dict, "bssid", DBUS_TYPE_STRING, &address); @@ -737,7 +824,13 @@ static int set_network(struct supplicant_task *task, connman_dbus_dict_append_variant(&dict, "psk", DBUS_TYPE_STRING, &passphrase); } else if (g_ascii_strcasecmp(security, "wep") == 0) { - const char *key_mgmt = "NONE", *index = "0"; + const char *key_mgmt = "NONE"; + const char *auth_alg = "OPEN SHARED"; + const char *key_index = "0"; + + connman_dbus_dict_append_variant(&dict, "auth_alg", + DBUS_TYPE_STRING, &auth_alg); + connman_dbus_dict_append_variant(&dict, "key_mgmt", DBUS_TYPE_STRING, &key_mgmt); @@ -763,8 +856,9 @@ static int set_network(struct supplicant_task *task, connman_dbus_dict_append_variant(&dict, "wep_key0", DBUS_TYPE_STRING, &passphrase); + connman_dbus_dict_append_variant(&dict, "wep_tx_keyidx", - DBUS_TYPE_STRING, &index); + DBUS_TYPE_STRING, &key_index); } } else { const char *key_mgmt = "NONE"; @@ -835,6 +929,7 @@ static struct { { "comcomcom", "3com" }, { "3Com", "3com" }, { "Symbol", "symbol" }, + { "Motorola", "motorola" }, { "Wireless" , "wireless" }, { "WLAN", "wlan" }, { } @@ -854,6 +949,11 @@ static char *build_group(const char *addr, const char *name, if (str == NULL) return NULL; + if (ssid == NULL) { + g_string_append_printf(str, "hidden_%s", addr); + goto done; + } + for (i = 0; special_ssid[i].name; i++) { if (g_strcmp0(special_ssid[i].name, name) == 0) { if (special_ssid[i].value == NULL) @@ -882,7 +982,7 @@ static void extract_addr(DBusMessageIter *value, struct supplicant_result *result) { DBusMessageIter array; - struct ether_addr *eth; + struct ether_addr eth; unsigned char *addr; int addr_len; @@ -892,31 +992,25 @@ static void extract_addr(DBusMessageIter *value, if (addr_len != 6) return; - eth = (void *) addr; - - result->addr = g_try_malloc0(18); + result->addr = g_try_malloc(addr_len); 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]); + memcpy(result->addr, addr, addr_len); + result->addr_len = addr_len; - result->path = g_try_malloc0(18); + result->path = g_try_malloc0(13); 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]); + memcpy(ð, addr, sizeof(eth)); + snprintf(result->path, 13, "%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, @@ -924,7 +1018,7 @@ static void extract_ssid(DBusMessageIter *value, { DBusMessageIter array; unsigned char *ssid; - int ssid_len; + int ssid_len, i; dbus_message_iter_recurse(value, &array); dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len); @@ -932,6 +1026,9 @@ static void extract_ssid(DBusMessageIter *value, if (ssid_len < 1) return; + if (ssid[0] == '\0') + return; + result->ssid = g_try_malloc(ssid_len); if (result->ssid == NULL) return; @@ -943,7 +1040,12 @@ static void extract_ssid(DBusMessageIter *value, if (result->name == NULL) return; - memcpy(result->name, ssid, ssid_len); + for (i = 0; i < ssid_len; i++) { + if (g_ascii_isprint(ssid[i])) + result->name[i] = ssid[i]; + else + result->name[i] = ' '; + } } static void extract_wpaie(DBusMessageIter *value, @@ -1002,9 +1104,10 @@ static void extract_capabilites(DBusMessageIter *value, result->has_wep = TRUE; } -static unsigned char calculate_strength(struct supplicant_result *result) +static unsigned char calculate_strength(struct supplicant_task *task, + struct supplicant_result *result) { - if (result->quality < 0) { + if (task->range->max_qual.qual == 0) { unsigned char strength; if (result->level > 0) @@ -1018,7 +1121,7 @@ static unsigned char calculate_strength(struct supplicant_result *result) return strength; } - return result->quality; + return (result->quality * 100) / task->range->max_qual.qual; } static unsigned short calculate_channel(struct supplicant_result *result) @@ -1041,7 +1144,8 @@ static void properties_reply(DBusPendingCall *call, void *user_data) unsigned char strength; unsigned short channel, frequency; const char *mode, *security; - char *group; + char *group = NULL; + unsigned int ssid_len; DBG("task %p", task); @@ -1132,7 +1236,7 @@ static void properties_reply(DBusPendingCall *call, void *user_data) else if (result.frequency == 14) result.frequency = 2484; - strength = calculate_strength(&result); + strength = calculate_strength(task, &result); channel = calculate_channel(&result); frequency = (result.frequency < 0) ? 0 : result.frequency; @@ -1167,7 +1271,8 @@ static void properties_reply(DBusPendingCall *call, void *user_data) connman_network_set_protocol(network, CONNMAN_NETWORK_PROTOCOL_IP); - connman_network_set_string(network, "Address", result.addr); + connman_network_set_address(network, result.addr, + result.addr_len); if (connman_device_add_network(task->device, network) < 0) { connman_network_unref(network); @@ -1176,10 +1281,12 @@ static void properties_reply(DBusPendingCall *call, void *user_data) } if (result.name != NULL && result.name[0] != '\0') - connman_network_set_string(network, "Name", result.name); + connman_network_set_name(network, result.name); - connman_network_set_blob(network, "WiFi.SSID", - result.ssid, result.ssid_len); + if (connman_network_get_blob(network, "WiFi.SSID", &ssid_len) == NULL) { + connman_network_set_blob(network, "WiFi.SSID", + result.ssid, result.ssid_len); + } connman_network_set_string(network, "WiFi.Mode", mode); @@ -1188,17 +1295,18 @@ static void properties_reply(DBusPendingCall *call, void *user_data) (result.has_wps == TRUE) ? "WPS" : "no WPS"); connman_network_set_available(network, TRUE); - connman_network_set_uint8(network, "Strength", strength); - connman_network_set_uint16(network, "Frequency", frequency); + connman_network_set_strength(network, strength); + connman_network_set_uint16(network, "Frequency", frequency); connman_network_set_uint16(network, "WiFi.Channel", channel); connman_network_set_string(network, "WiFi.Security", security); - connman_network_set_group(network, group); + if (result.ssid != NULL) + connman_network_set_group(network, group); +done: g_free(group); -done: g_free(result.path); g_free(result.addr); g_free(result.name); @@ -1366,6 +1474,41 @@ static enum supplicant_state string2state(const char *state) return WPA_INVALID; } +static int task_connect(struct supplicant_task *task) +{ + const char *address, *security, *passphrase; + const void *ssid; + unsigned int ssid_len; + + address = connman_network_get_string(task->network, "Address"); + security = connman_network_get_string(task->network, "WiFi.Security"); + passphrase = connman_network_get_string(task->network, "WiFi.Passphrase"); + + ssid = connman_network_get_blob(task->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; + + task->connecting = TRUE; + + add_network(task); + + select_network(task); + disable_network(task); + + set_network(task, ssid, ssid_len, address, security, passphrase); + + enable_network(task); + + return 0; +} + static void state_change(struct supplicant_task *task, DBusMessage *msg) { DBusError error; @@ -1421,18 +1564,64 @@ static void state_change(struct supplicant_task *task, DBusMessage *msg) switch (task->state) { case WPA_COMPLETED: + if (connman_network_get_group(task->network) == NULL) { + const char *name, *mode, *security; + char *bssid; + + /* + * This is a hidden network, we need to set its + * group based on the BSSID we just joined. + */ + bssid = get_bssid(task->device); + + name = connman_network_get_string(task->network, + "Name"); + mode = connman_network_get_string(task->network, + "WiFi.Mode"); + security = connman_network_get_string(task->network, + "WiFi.Security"); + + if (bssid && name && mode && security) { + char *group; + + group = build_group(bssid, name, NULL, 0, + mode, security); + connman_network_set_group(task->network, group); + g_free(group); + } + + g_free(bssid); + } + /* carrier on */ connman_network_set_connected(task->network, TRUE); connman_device_set_scanning(task->device, FALSE); + task->connecting = FALSE; break; + case WPA_DISCONNECTED: - /* carrier off */ - connman_network_set_connected(task->network, FALSE); - connman_device_set_scanning(task->device, FALSE); + if (task->disconnecting == TRUE) { + connman_network_set_connected(task->network, FALSE); + connman_network_unref(task->network); + task->disconnecting = FALSE; + + if (task->pending_network != NULL) { + task->network = task->pending_network; + task->pending_network = NULL; + task_connect(task); + } + } else { + /* carrier off */ + connman_network_set_connected(task->network, FALSE); + connman_device_set_scanning(task->device, FALSE); + task->connecting = FALSE; + } break; + case WPA_ASSOCIATING: connman_network_set_associating(task->network, TRUE); break; + default: connman_network_set_associating(task->network, FALSE); break; @@ -1474,6 +1663,7 @@ static DBusHandlerResult supplicant_filter(DBusConnection *conn, int supplicant_start(struct connman_device *device) { struct supplicant_task *task; + int err; DBG("device %p", device); @@ -1485,19 +1675,39 @@ int supplicant_start(struct connman_device *device) task->ifname = connman_inet_ifname(task->ifindex); if (task->ifname == NULL) { - g_free(task); - return -ENOMEM; + err = -ENOMEM; + goto failed; + } + + task->range = g_try_malloc0(sizeof(struct iw_range)); + if (task->range == NULL) { + err = -ENOMEM; + goto failed; } + err = get_range(task); + if (err < 0) + goto failed; + task->device = connman_device_ref(device); task->created = FALSE; task->noscan = FALSE; task->state = WPA_INVALID; + task->connecting = FALSE; + task->disconnecting = FALSE; + task->pending_network = NULL; task_list = g_slist_append(task_list, task); return create_interface(task); + +failed: + g_free(task->range); + g_free(task->ifname); + g_free(task); + + return err; } int supplicant_stop(struct connman_device *device) @@ -1511,6 +1721,8 @@ int supplicant_stop(struct connman_device *device) if (task == NULL) return -ENODEV; + g_free(task->range); + task_list = g_slist_remove(task_list, task); disable_network(task); @@ -1552,46 +1764,22 @@ int supplicant_scan(struct connman_device *device) 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); - address = connman_network_get_string(network, "Address"); - security = connman_network_get_string(network, "WiFi.Security"); - passphrase = connman_network_get_string(network, "WiFi.Passphrase"); - - 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, address, security, passphrase); - - enable_network(task); - - connman_network_set_associating(task->network, TRUE); + if (task->disconnecting == TRUE) + task->pending_network = connman_network_ref(network); + else { + task->network = connman_network_ref(network); + return task_connect(task); + } return 0; } @@ -1609,13 +1797,14 @@ int supplicant_disconnect(struct connman_network *network) if (task == NULL) return -ENODEV; + if (task->disconnecting == TRUE) + return -EINPROGRESS; + disable_network(task); remove_network(task); - connman_network_set_connected(task->network, FALSE); - - connman_network_unref(task->network); + task->disconnecting = TRUE; return 0; }