X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fwifi-netlink-scan.c;h=e008fd221d1ced27493476312e59b997a9f72a86;hb=c955b04ec785ee8bfcb5df372625580988317369;hp=320078f7d4fbb9a1ce3a20904e30c08fbff5303a;hpb=68cac656ba0a7b549278e2c368714bcc0670f3cd;p=platform%2Fcore%2Fconnectivity%2Fnet-config.git diff --git a/src/wifi-netlink-scan.c b/src/wifi-netlink-scan.c index 320078f..e008fd2 100755 --- a/src/wifi-netlink-scan.c +++ b/src/wifi-netlink-scan.c @@ -44,6 +44,8 @@ void __netconfig_notify_netlink_scan_done(void) const char *prop_freq = "freq"; const char *prop_rssi = "rssi"; const char *prop_vsie = "vsie"; + const char *prop_sec = "security"; + const char *prop_enc = "encryption"; builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); for (list = bss_info_list; list != NULL; list = list->next) { @@ -55,12 +57,16 @@ void __netconfig_notify_netlink_scan_done(void) char *vsie = (char *)bss_info->vsie; int freq = (int)bss_info->freq; int signal = (int)bss_info->signal; + int sec_type = (int)bss_info->security_type; + int enc_type = (int)bss_info->encryption_type; g_variant_builder_add(builder, "{sv}", prop_ssid, g_variant_new_string(ssid)); g_variant_builder_add(builder, "{sv}", prop_bssid, g_variant_new_string(bssid)); g_variant_builder_add(builder, "{sv}", prop_freq, g_variant_new_int32(freq)); g_variant_builder_add(builder, "{sv}", prop_rssi, g_variant_new_int32(signal)); g_variant_builder_add(builder, "{sv}", prop_vsie, g_variant_new_string(vsie)); + g_variant_builder_add(builder, "{sv}", prop_sec, g_variant_new_int32(sec_type)); + g_variant_builder_add(builder, "{sv}", prop_enc, g_variant_new_int32(enc_type)); } } @@ -199,6 +205,187 @@ static void __netconfig_macaddress_str(char *bssid, unsigned char *user_data) } } +typedef enum { + WIFI_SECURITY_TYPE_NONE = 0, + WIFI_SECURITY_TYPE_WEP = 1, + WIFI_SECURITY_TYPE_WPA_PSK = 2, + WIFI_SECURITY_TYPE_WPA2_PSK = 3, + WIFI_SECURITY_TYPE_EAP = 4, +} wifi_security_type_e; + +typedef enum { + WIFI_ENCRYPTION_TYPE_NONE = 0, + WIFI_ENCRYPTION_TYPE_WEP = 1, + WIFI_ENCRYPTION_TYPE_TKIP = 2, + WIFI_ENCRYPTION_TYPE_AES = 3, + WIFI_ENCRYPTION_TYPE_TKIP_AES_MIXED = 4, +} wifi_encryption_type_e; + +static unsigned char ms_oui[3] = { 0x00, 0x50, 0xf2 }; +static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac }; + +static void __netconfig_get_security(unsigned char *bss_element, int length, wifi_security_type_e *sec_type, wifi_encryption_type_e *enc_type) +{ + int i; + unsigned char *data; + uint8_t *t_data; + int len; + __u16 count; + + *sec_type = WIFI_SECURITY_TYPE_NONE; + *enc_type = WIFI_ENCRYPTION_TYPE_NONE; + + while (length >= 2 && length >= bss_element[1]) { + if (bss_element[0] == 221 && (bss_element[1] >= 4 && memcmp(bss_element + 2, ms_oui, 3) == 0)) { + data = bss_element + 2 + 4 + 2 + 4; + len = bss_element[1] - 4 - 2 - 4; + + if (len < 2) { + length -= bss_element[1] + 2; + bss_element += bss_element[1] + 2; + continue; + } + + count = data[0] | (data[1] << 8); + + if (2 + (count * 4) > len) { + length -= bss_element[1] + 2; + bss_element += bss_element[1] + 2; + continue; + } + + for (i = 0; i < count; i++) { + t_data = (data + 2 + (i * 4)); + + if ((memcmp(t_data, ms_oui, 3) == 0) || (memcmp(t_data, ieee80211_oui, 3) == 0)) { + if (t_data[3] == 1 || t_data[3] == 5) { // 1 : WEP-40, 5 : WEP-104 + *sec_type = WIFI_SECURITY_TYPE_WEP; + *enc_type = WIFI_ENCRYPTION_TYPE_WEP; + return; + } else if (t_data[3] == 2) { // 2 : TKIP + if (*sec_type != WIFI_SECURITY_TYPE_WPA2_PSK) + *sec_type = WIFI_SECURITY_TYPE_WPA_PSK; + if (*enc_type == WIFI_ENCRYPTION_TYPE_AES) + *enc_type = WIFI_ENCRYPTION_TYPE_TKIP_AES_MIXED; + else + *enc_type = WIFI_ENCRYPTION_TYPE_TKIP; + } else if (t_data[3] == 4) { // 3 : CCMP + if (*sec_type != WIFI_SECURITY_TYPE_WPA2_PSK) + *sec_type = WIFI_SECURITY_TYPE_WPA_PSK; + if (*enc_type == WIFI_ENCRYPTION_TYPE_TKIP) + *enc_type = WIFI_ENCRYPTION_TYPE_TKIP_AES_MIXED; + else + *enc_type = WIFI_ENCRYPTION_TYPE_AES; + } + } //if + } //for + + data += 2 + (count * 4); + len -= 2 + (count * 4); + + if (len < 2) { + length -= bss_element[1] + 2; + bss_element += bss_element[1] + 2; + continue; + } + + count = data[0] | (data[1] << 8); + + if (2 + (count * 4) > len) { + length -= bss_element[1] + 2; + bss_element += bss_element[1] + 2; + continue; + } + + for (i = 0; i < count; i++) { + t_data = (data + 2 + (i * 4)); + + if ((memcmp(t_data, ms_oui, 3) == 0) || (memcmp(t_data, ieee80211_oui, 3) == 0)) { + if (t_data[3] == 1 || t_data[3] == 3 || t_data[3] == 5) { // 1 : IEEE 802.1X, 3 : FT/IEEE 802.1X, 5 : IEEE 802.1X/SHA-256 + *sec_type = WIFI_SECURITY_TYPE_EAP; + } else if (t_data[3] == 2 || t_data[3] == 4 || t_data[3] == 6) { // 2 : PSK, 4 : FT/PSK, 6 : PSK/SHA-256 + if (*sec_type != WIFI_SECURITY_TYPE_WPA2_PSK) + *sec_type = WIFI_SECURITY_TYPE_WPA_PSK; + } + } + } + } else if (bss_element[0] == 48 && (bss_element[1] >= 2 && bss_element[1] <= 255)) { + data = bss_element + 2 + 2 + 4; + len = bss_element[1] - 2 - 4; + + if (len < 2) { + length -= bss_element[1] + 2; + bss_element += bss_element[1] + 2; + continue; + } + + count = data[0] | (data[1] << 8); + if (2 + (count + 4) > len) { + length -= bss_element[1] + 2; + bss_element += bss_element[1] + 2; + continue; + } + + for (i = 0; i < count; i++) { + t_data = (data + 2 + (i * 4)); + + if ((memcmp(t_data, ms_oui, 3) == 0) || (memcmp(t_data, ieee80211_oui, 3) == 0)) { + if (t_data[3] == 1 || t_data[3] == 5) { // 1 : WEP-40, 5 : WEP-104 + *sec_type = WIFI_SECURITY_TYPE_WEP; + *enc_type = WIFI_ENCRYPTION_TYPE_WEP; + return; + } else if (t_data[3] == 2) { // 2 : TKIP + *sec_type = WIFI_SECURITY_TYPE_WPA2_PSK; + if (*enc_type == WIFI_ENCRYPTION_TYPE_AES) + *enc_type = WIFI_ENCRYPTION_TYPE_TKIP_AES_MIXED; + else + *enc_type = WIFI_ENCRYPTION_TYPE_TKIP; + } else if (t_data[3] == 4) { // 3 : CCMP + *sec_type = WIFI_SECURITY_TYPE_WPA2_PSK; + if (*enc_type == WIFI_ENCRYPTION_TYPE_TKIP) + *enc_type = WIFI_ENCRYPTION_TYPE_TKIP_AES_MIXED; + else + *enc_type = WIFI_ENCRYPTION_TYPE_AES; + } + } + } + + data += 2 + (count * 4); + len -= 2 + (count * 4); + + if (len < 2) { + length -= bss_element[1] + 2; + bss_element += bss_element[1] + 2; + continue; + } + + count = data[0] | (data[1] << 8); + if (2 + (count * 4) > len) { + length -= bss_element[1] + 2; + bss_element += bss_element[1] + 2; + continue; + } + + for (i = 0; i < count; i++) { + t_data = (data + 2 + (i * 4)); + + if ((memcmp(t_data, ms_oui, 3) == 0) || (memcmp(t_data, ieee80211_oui, 3) == 0)) { + if (t_data[3] == 1 || t_data[3] == 3 || t_data[3] == 5) { // 1 : IEEE 802.1X, 3 : FT/IEEE 802.1X, 5 : IEEE 802.1X/SHA-256 + *sec_type = WIFI_SECURITY_TYPE_EAP; + } else if (t_data[3] == 2 || t_data[3] == 4 || t_data[3] == 6) { // 2 : PSK, 4 : FT/PSK, 6 : PSK/SHA-256 + *sec_type = WIFI_SECURITY_TYPE_WPA2_PSK; + } + } + } //for + } //else if + + length -= bss_element[1] + 2; + bss_element += bss_element[1] + 2; + } //while + + return; +} + static void __netconfig_get_vsie(unsigned char *bss_element, int length, char **dst) { int i = 0; @@ -254,7 +441,7 @@ static void __netconfig_found_ap(unsigned char *bss_element, int length, char *s else if (data[i] == ' ' && (i != 0 && i != len -1)) snprintf(&str[i], 2, "%c", ' '); else - snprintf(&str[i], 3, "%.2x", data[i]); + snprintf(&str[i], 2, "%c", data[i]); } break; } @@ -269,6 +456,8 @@ static int __netconfig_netlink_scan_cb(struct nl_msg *msg, void *user_data) struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); char bssid[NETCONFIG_BSSID_LEN+1]; char ssid[NETCONFIG_SSID_LEN+1] = {0, }; + wifi_security_type_e sec_type = WIFI_SECURITY_TYPE_NONE; + wifi_encryption_type_e enc_type = WIFI_ENCRYPTION_TYPE_NONE; char *vsie = NULL; struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct nlattr *bss[NL80211_BSS_MAX + 1]; @@ -296,6 +485,19 @@ static int __netconfig_netlink_scan_cb(struct nl_msg *msg, void *user_data) __netconfig_macaddress_str(bssid, nla_data(bss[NL80211_BSS_BSSID])); __netconfig_found_ap(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]), nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]), ssid); __netconfig_get_vsie(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]), nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]), &vsie); + __netconfig_get_security(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]), + nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]), &sec_type, &enc_type); + + if (sec_type == WIFI_SECURITY_TYPE_EAP) + return NL_SKIP; + for (GSList *list = bss_info_list; list != NULL; list = list->next) { + struct bss_scan_info_t *bss_info = (struct bss_scan_info_t *)list->data; + if ((g_strcmp0(bss_info->ssid, ssid) == 0) && (bss_info->security_type == sec_type) + && (bss_info->encryption_type == enc_type)) { + g_free(vsie); + return NL_SKIP; + } + } /** Create AP info list. */ if (ssid[0] != '\0') { @@ -303,14 +505,17 @@ static int __netconfig_netlink_scan_cb(struct nl_msg *msg, void *user_data) int signal; bss_info = g_try_new0(struct bss_scan_info_t, 1); - if (bss_info == NULL) + if (bss_info == NULL) { + g_free(vsie); return NL_SKIP; + } g_strlcpy(bss_info->bssid, bssid, strlen(bssid)+1); g_strlcpy(bss_info->ssid, ssid, strlen(ssid)+1); if (vsie) { g_strlcpy(bss_info->vsie, vsie, strlen(vsie)+1); g_free(vsie); + vsie = NULL; } bss_info->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]); @@ -319,7 +524,12 @@ static int __netconfig_netlink_scan_cb(struct nl_msg *msg, void *user_data) signal /= 100; /** mBm to dBm */ bss_info->signal = signal; } - DBG("%s %d %d %s [vsie: %s]", bss_info->bssid, bss_info->freq, bss_info->signal, bss_info->ssid, bss_info->vsie); + + bss_info->security_type = sec_type; + bss_info->encryption_type = enc_type; + DBG("%s %d %d %s %d %d [vsie: %s]", bss_info->bssid, bss_info->freq, + bss_info->signal, bss_info->ssid, bss_info->security_type, + bss_info->encryption_type, bss_info->vsie); if (bss_info->ssid[0] == '\0') g_free(bss_info); @@ -328,6 +538,7 @@ static int __netconfig_netlink_scan_cb(struct nl_msg *msg, void *user_data) } + g_free(vsie); return NL_SKIP; } @@ -366,17 +577,24 @@ static int __netconfig_request_netlink_scan(struct nl_sock *socket, gchar *key; gboolean ssid_found = FALSE; int mcid = __netconfig_get_multicast_id(socket, "nl80211", "scan"); - nl_socket_add_membership(socket, mcid); + + ret = nl_socket_add_membership(socket, mcid); + if (ret < 0) { + DBG("Failed to add membership, error: (%s)", nl_geterror(-ret)); + return ret; + } msg = nlmsg_alloc(); if (!msg) { DBG("Failed to allocate msg"); + nl_socket_drop_membership(socket, mcid); return -ENOMEM; } ssids = nlmsg_alloc(); if (!ssids) { DBG("Failed to allocate ssids"); nlmsg_free(msg); + nl_socket_drop_membership(socket, mcid); return -ENOMEM; } cb = nl_cb_alloc(NL_CB_DEFAULT); @@ -384,12 +602,17 @@ static int __netconfig_request_netlink_scan(struct nl_sock *socket, DBG("Failed to allocate callbacks"); nlmsg_free(msg); nlmsg_free(ssids); + nl_socket_drop_membership(socket, mcid); return -ENOMEM; } /** Set nl message and callback functions. */ genlmsg_put(msg, 0, 0, id, 0, 0, NL80211_CMD_TRIGGER_SCAN, 0); - nla_put_u32(msg, NL80211_ATTR_IFINDEX, if_index); + ret = nla_put_u32(msg, NL80211_ATTR_IFINDEX, if_index); + if (ret < 0) { + DBG("Failed to add integer attribute to netlink message, error: (%s)", nl_geterror(-ret)); + goto out; + } g_variant_get(params, "a{sv}", &iter); while (g_variant_iter_loop(iter, "{sv}", &key, &value)) { @@ -399,8 +622,13 @@ static int __netconfig_request_netlink_scan(struct nl_sock *socket, ssid_found = TRUE; DBG("ssid [%s]", ssid); - nla_put(ssids, 1, strlen(ssid), ssid); + ret = nla_put(ssids, 1, strlen(ssid), ssid); g_free(ssid); + if (ret < 0) { + DBG("Failed to add ssid to netlink message, error: (%s)", nl_geterror(-ret)); + g_variant_iter_free(iter); + goto out; + } } } else if (g_strcmp0(key, "VSIE") == 0) { if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) { @@ -416,15 +644,23 @@ static int __netconfig_request_netlink_scan(struct nl_sock *socket, } g_variant_iter_free(iter); - if (!ssid_found) - nla_put(ssids, 1, 0, ""); + if (!ssid_found) { + ret = nla_put(ssids, 1, 0, ""); + if (ret < 0) { + DBG("nla_put error: (%s)", nl_geterror(-ret)); + goto out; + } + } nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids); - nlmsg_free(ssids); if (ies[0] == NETCONFIG_VENDOR_SPECIFIC_ID && ies[1] >= 4) { DBG("ies_len: %d ies: %02x %02x %02x %02x %02x %02x %02x", ies_len, ies[0], ies[1], ies[2], ies[3], ies[4], ies[5], ies[6]); - nla_put(msg, NL80211_ATTR_IE, ies_len, ies); + ret = nla_put(msg, NL80211_ATTR_IE, ies_len, ies); + if (ret < 0) { + DBG("Failed to add vsie data to netlink message, error: (%s)", nl_geterror(-ret)); + goto out; + } } err = 1; @@ -436,6 +672,11 @@ static int __netconfig_request_netlink_scan(struct nl_sock *socket, /** Send NL80211_CMD_TRIGGER_SCAN to start the scan. */ ret = nl_send_auto_complete(socket, msg); + if (ret < 0) { + DBG("nl_send_auto_complete() error: (%s)", nl_geterror(-ret)); + goto out; + } + DBG("Sent %d bytes to the kernel", ret); ssid_found = FALSE; @@ -444,7 +685,7 @@ static int __netconfig_request_netlink_scan(struct nl_sock *socket, if (ret < 0) { DBG("nl_recvmsgs() ret: %d (%s)", ret, nl_geterror(-ret)); - return ret; + goto out; } while (!results.done) @@ -454,12 +695,18 @@ static int __netconfig_request_netlink_scan(struct nl_sock *socket, DBG("scan aborted"); return 1; } - DBG("Scan done"); +out: /** Release memory */ + nlmsg_free(ssids); nlmsg_free(msg); nl_cb_put(cb); nl_socket_drop_membership(socket, mcid); + + if (ret < 0) + return ret; + + DBG("Scan done"); return 0; } @@ -501,6 +748,8 @@ fail: static int __netconfig_initialize_nl_msg(netconfig_nl_global *global) { + int rv; + if (global == NULL) { DBG("Invalid parameter."); return -EINVAL; @@ -514,7 +763,12 @@ static int __netconfig_initialize_nl_msg(netconfig_nl_global *global) /* Set command into message */ genlmsg_put(global->msg, 0, 0, global->id, 0, NLM_F_DUMP, NL80211_CMD_GET_SCAN, 0); - nla_put_u32(global->msg, NL80211_ATTR_IFINDEX, global->if_index); + rv = nla_put_u32(global->msg, NL80211_ATTR_IFINDEX, global->if_index); + if (rv < 0) { + DBG("Failed to add integer attribute to netlink message."); + nlmsg_free(global->msg); + return rv; + } nl_socket_modify_cb(global->socket, NL_CB_VALID, NL_CB_CUSTOM, __netconfig_netlink_scan_cb, NULL); return 0; @@ -535,7 +789,7 @@ int handle_netlink_scan(Wifi *wifi, GDBusMethodInvocation *context, GVariant *pa if (ret < 0) { DBG("__netconfig_initialize_nl80211() failed, error %d", ret); wifi_complete_netlink_scan(wifi, context); - return ret; + return TRUE; } /** Request NL80211_CMD_TRIGGER_SCAN to the kernel. */ @@ -543,14 +797,14 @@ int handle_netlink_scan(Wifi *wifi, GDBusMethodInvocation *context, GVariant *pa if (ret < 0) { DBG("__netconfig_request_netlink_scan() failed, error %d", ret); wifi_complete_netlink_scan(wifi, context); - return ret; + return TRUE; } ret = __netconfig_initialize_nl_msg(&global); if (ret < 0) { DBG("__netconfig_initialize_nl_msg() failed, error %d", ret); wifi_complete_netlink_scan(wifi, context); - return ret; + return TRUE; } ret = nl_send_auto_complete(global.socket, global.msg); @@ -562,11 +816,11 @@ int handle_netlink_scan(Wifi *wifi, GDBusMethodInvocation *context, GVariant *pa if (ret < 0) { DBG("nl_recvmsgs_default() failed. ret: %d (error: %s)", ret, nl_geterror(-ret)); wifi_complete_netlink_scan(wifi, context); - return ret; + return TRUE; } wifi_complete_netlink_scan(wifi, context); __netconfig_notify_netlink_scan_done(); - return 1; + return TRUE; }