Rectify gvariant type for frequency
[platform/core/connectivity/net-config.git] / src / wifi-netlink-scan.c
index 04d6f75..a02c9a7 100755 (executable)
 
 static GSList *bss_info_list = NULL;
 
-void __netconfig_notify_netlink_scan_done(void)
+static gint __netconfig_compare_bss_by_rssi(gconstpointer a, gconstpointer b)
+{
+       struct bss_scan_info_t *entry_a = (struct bss_scan_info_t *) a;
+       struct bss_scan_info_t *entry_b = (struct bss_scan_info_t *) b;
+
+       if (entry_a->signal > entry_b->signal)
+               return -1;
+
+       if (entry_a->signal < entry_b->signal)
+               return 1;
+
+       return 0;
+}
+
+void __netconfig_notify_netlink_scan_done(const char *interface_name)
 {
        GVariantBuilder *builder = NULL;
        GVariantBuilder *builder1 = NULL;
@@ -47,6 +61,9 @@ void __netconfig_notify_netlink_scan_done(void)
        const char *prop_vsie_list = "vsie_list";
        const char *prop_sec = "security";
        const char *prop_enc = "encryption";
+       const char *prop_pmf = "pmf";
+
+       bss_info_list = g_slist_sort(bss_info_list, __netconfig_compare_bss_by_rssi);
 
        builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
        for (list = bss_info_list; list != NULL; list = list->next) {
@@ -60,6 +77,7 @@ void __netconfig_notify_netlink_scan_done(void)
                        int signal = (int)bss_info->signal;
                        int sec_type = (int)bss_info->security_type;
                        int enc_type = (int)bss_info->encryption_type;
+                       int pmf_required = (int)bss_info->pmf_required;
 
                        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));
@@ -92,10 +110,12 @@ void __netconfig_notify_netlink_scan_done(void)
 
                        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));
+                       g_variant_builder_add(builder, "{sv}", prop_pmf, g_variant_new_int32(pmf_required));
                }
        }
 
-       wifi_emit_netlink_scan_completed((Wifi *)get_wifi_object(), g_variant_builder_end(builder));
+       wifi_emit_netlink_scan_completed((Wifi *)get_wifi_object(),
+               interface_name, g_variant_builder_end(builder));
        g_variant_builder_unref(builder);
 
        if (bss_info_list != NULL)
@@ -119,6 +139,8 @@ static int finish_handler(struct nl_msg *msg, void *user_data)
 {
        int *ret = user_data;
        *ret = 0;
+
+       DBG("");
        return NL_SKIP;
 }
 
@@ -127,7 +149,9 @@ static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
 {
        int *ret = user_data;
        *ret = err->error;
-       return NL_SKIP;
+
+       DBG("");
+       return NL_STOP;
 }
 
 static int no_seq_check(struct nl_msg *msg, void *user_data)
@@ -236,7 +260,8 @@ typedef enum {
        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_SAE = 4,
+       WIFI_SECURITY_TYPE_EAP = 5,
 } wifi_security_type_e;
 
 typedef enum {
@@ -250,13 +275,15 @@ typedef enum {
 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)
+static void __netconfig_get_security(unsigned char *bss_element, int length,
+               wifi_security_type_e *sec_type, wifi_encryption_type_e *enc_type, int *pmf_required)
 {
        int i;
        unsigned char *data;
        uint8_t *t_data;
        int len;
        __u16 count;
+       gboolean ieee80211_psk = false;
 
        *sec_type = WIFI_SECURITY_TYPE_NONE;
        *enc_type = WIFI_ENCRYPTION_TYPE_NONE;
@@ -330,6 +357,8 @@ static void __netconfig_get_security(unsigned char *bss_element, int length, wif
                                        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 (t_data[3] == 6)
+                                                       *pmf_required = 1;
                                                if (*sec_type != WIFI_SECURITY_TYPE_WPA2_PSK)
                                                        *sec_type = WIFI_SECURITY_TYPE_WPA_PSK;
                                        }
@@ -399,7 +428,13 @@ static void __netconfig_get_security(unsigned char *bss_element, int length, wif
                                        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 (t_data[3] == 6)
+                                                       *pmf_required = 1;
                                                *sec_type = WIFI_SECURITY_TYPE_WPA2_PSK;
+                                               ieee80211_psk = true;
+                                       } else if (t_data[3] == 8) { // Add SAE security type for netlink scan
+                                               if (ieee80211_psk != true)
+                                                       *sec_type = WIFI_SECURITY_TYPE_SAE;
                                        }
                                }
                        } //for
@@ -484,6 +519,8 @@ static int __netconfig_netlink_scan_cb(struct nl_msg *msg, void *user_data)
                [NL80211_BSS_SIGNAL_MBM] = {.type = NLA_U32},
        };
 
+       int pmf_needed = 0;
+
        /** Parse nl message and check error. */
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
        if (!tb[NL80211_ATTR_BSS]) {
@@ -509,7 +546,7 @@ static int __netconfig_netlink_scan_cb(struct nl_msg *msg, void *user_data)
                }
        }
        __netconfig_get_security(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
-                       nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]), &sec_type, &enc_type);
+                       nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]), &sec_type, &enc_type, &pmf_needed);
 
        if (wep_check && sec_type == WIFI_SECURITY_TYPE_NONE) {
                sec_type = WIFI_SECURITY_TYPE_WEP;
@@ -553,9 +590,10 @@ static int __netconfig_netlink_scan_cb(struct nl_msg *msg, void *user_data)
 
                bss_info->security_type = sec_type;
                bss_info->encryption_type = enc_type;
-               DBG("%s %d %d %s %d %d ", bss_info->bssid, bss_info->freq,
+               bss_info->pmf_required = pmf_needed;
+               SECURE_LOGD("%s %d %d %s %d %d %d ", bss_info->bssid, bss_info->freq,
                                bss_info->signal, bss_info->ssid, bss_info->security_type,
-                               bss_info->encryption_type);
+                               bss_info->encryption_type, bss_info->pmf_required);
 
                if (bss_info->ssid[0] == '\0')
                        g_free(bss_info);
@@ -587,8 +625,8 @@ static int __netconfig_netlink_scan_reply(struct nl_msg *msg, void *user_data)
        return NL_SKIP;
 }
 
-static int __netconfig_request_netlink_scan(struct nl_sock *socket,
-               int if_index, int id, GVariant *params)
+static int __netconfig_trigger_netlink_scan(struct nl_sock *socket,
+               int if_index, int id, GSList *ssid_list, char *vsie)
 {
        struct netconfig_netlink_scan_results results = { .done = 0, .aborted = 0 };
        struct nl_msg *msg = NULL;
@@ -598,12 +636,9 @@ static int __netconfig_request_netlink_scan(struct nl_sock *socket,
        int ret = 0;
        unsigned char ies[NETCONFIG_MAX_VSIE_LEN+1] = {0x00, };
        int ies_len = 0;
-       GVariantIter *iter;
-       GVariant *value;
-       gchar *key;
-       gboolean ssid_found = FALSE;
        int mcid = __netconfig_get_multicast_id(socket, "nl80211", "scan");
 
+       DBG("");
        ret = nl_socket_add_membership(socket, mcid);
        if (ret < 0) {
                DBG("Failed to add membership, error: (%s)", nl_geterror(-ret));
@@ -640,37 +675,17 @@ static int __netconfig_request_netlink_scan(struct nl_sock *socket,
                goto out;
        }
 
-       g_variant_get(params, "a{sv}", &iter);
-       while (g_variant_iter_loop(iter, "{sv}", &key, &value)) {
-               if (g_strcmp0(key, "SSID") == 0) {
-                       if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
-                               char *ssid = g_strdup(g_variant_get_string(value, NULL));
-                               ssid_found = TRUE;
-                               DBG("ssid [%s]", 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)) {
-                               char *vsie = g_strdup(g_variant_get_string(value, NULL));
-                               int vsie_len = strlen(vsie);
-                               DBG("vsie: %s vsie_len: %d", vsie, vsie_len);
-
-                               ies_len = (vsie_len % 2) ? ((vsie_len / 2) + 1) : (vsie_len / 2);
-                               __netconfig_hex_str_to_bin(vsie, ies, ies_len);
-                               g_free(vsie);
-                       }
+       for (GSList *i = ssid_list; i; i = i->next) {
+               char *ssid = (char *)i->data;
+               ret = nla_put(ssids, 1, strlen(ssid), ssid);
+               if (ret < 0) {
+                       DBG("Failed to add ssid to netlink message, error: (%s)", nl_geterror(-ret));
+                       goto out;
                }
        }
-       g_variant_iter_free(iter);
 
-       if (!ssid_found) {
+       if (g_slist_length(ssid_list) == 0) {
+               DBG("Scan with no ssids");
                ret = nla_put(ssids, 1, 0, "");
                if (ret < 0) {
                        DBG("nla_put error: (%s)", nl_geterror(-ret));
@@ -679,6 +694,13 @@ static int __netconfig_request_netlink_scan(struct nl_sock *socket,
        }
        nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
 
+       if (vsie) {
+               int vsie_len = strlen(vsie);
+               DBG("vsie: %s vsie_len: %d", vsie, vsie_len);
+               ies_len = (vsie_len % 2) ? ((vsie_len / 2) + 1) : (vsie_len / 2);
+               __netconfig_hex_str_to_bin(vsie, ies, ies_len);
+       }
+
        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]);
@@ -707,7 +729,6 @@ static int __netconfig_request_netlink_scan(struct nl_sock *socket,
        }
 
        DBG("Sent %d bytes to the kernel", ret);
-       ssid_found = FALSE;
 
        while (err > 0) {
                ret = nl_recvmsgs(socket, cb);
@@ -717,14 +738,24 @@ static int __netconfig_request_netlink_scan(struct nl_sock *socket,
                }
        }
 
+       if (err < 0) {
+               DBG("error code = %d", err);
+               ret = -1;
+               goto out;
+       }
+
        while (!results.done) {
                ret = nl_recvmsgs(socket, cb);
 #if !defined TIZEN_WEARABLE
                if (ret == -NLE_AGAIN && err >= 0)
                        continue;
 #endif
-               if (ret < 0 || err < 0) {
+               if (ret < 0) {
                        DBG("scan failed");
+                       goto out;
+               }
+               if (err < 0) {
+                       DBG("scan failed err: %d", err);
                        ret = -1;
                        goto out;
                }
@@ -750,11 +781,23 @@ out:
        return 0;
 }
 
-static int __netconfig_initialize_nl80211(netconfig_nl_global *global)
+static int __netconfig_netlink_scan(netconfig_nl_global *global, GSList *ssid_list, char *vsie)
+{
+       DBG("");
+       int ret = __netconfig_trigger_netlink_scan(global->socket, global->if_index, global->id, ssid_list, vsie);
+       if (ret == -NLE_AGAIN) {
+               DBG("Try Again");
+               ret = __netconfig_trigger_netlink_scan(global->socket, global->if_index, global->id, ssid_list, vsie);
+       }
+       return ret;
+}
+
+static int __netconfig_initialize_nl80211(netconfig_nl_global *global,
+               const char *interface_name)
 {
        int err = 0;
 
-       global->if_index = __netconfig_get_interface_index(WIFI_IFNAME);
+       global->if_index = __netconfig_get_interface_index(interface_name);
        if (global->if_index < 0) {
                DBG("Failed to get interface index");
                return -1;
@@ -786,6 +829,17 @@ fail:
        return err;
 }
 
+static void __netconfig_deinitialize_nl80211(netconfig_nl_global *global)
+{
+       if (global == NULL)
+               return;
+
+       if (global->socket) {
+               nl_socket_free(global->socket);
+               global->socket = NULL;
+       }
+}
+
 static int __netconfig_initialize_nl_msg(netconfig_nl_global *global)
 {
        int rv;
@@ -814,7 +868,54 @@ static int __netconfig_initialize_nl_msg(netconfig_nl_global *global)
        return 0;
 }
 
-int handle_netlink_scan(Wifi *wifi, GDBusMethodInvocation *context, GVariant *params)
+static void __netconfig_get_netlink_scan_parameters(GVariant *params, GSList *ssid_list, char **vsie)
+{
+       GVariantIter *iter;
+       GVariant *value;
+       gchar *key;
+       g_variant_get(params, "a{sv}", &iter);
+       while (g_variant_iter_loop(iter, "{sv}", &key, &value)) {
+               if (g_strcmp0(key, "SSID") == 0) {
+                       if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
+                               char *ssid = g_strdup(g_variant_get_string(value, NULL));
+                               DBG("ssid [%s]", ssid);
+                               ssid_list = g_slist_append(ssid_list, ssid);
+                       }
+               } else if (g_strcmp0(key, "VSIE") == 0) {
+                       if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING))
+                               *vsie = g_strdup(g_variant_get_string(value, NULL));
+               }
+       }
+       g_variant_iter_free(iter);
+}
+
+static int __netconfig_get_scan_results(netconfig_nl_global *global)
+{
+       int ret = __netconfig_initialize_nl_msg(global);
+       if (ret < 0) {
+               DBG("__netconfig_initialize_nl_msg() failed, error %d", ret);
+               return ret;
+       }
+
+       ret = nl_send_auto_complete(global->socket, global->msg);
+       if (ret < 0) {
+               DBG("nl_send_auto_complete() failed, error %d", ret);
+               return ret;
+       }
+       DBG("NL80211_CMD_GET_SCAN sent %d bytes to the kernel", ret);
+
+       /** Receive the kernel message. */
+       ret = nl_recvmsgs_default(global->socket);
+       nlmsg_free(global->msg);
+       if (ret < 0) {
+               DBG("nl_recvmsgs_default() failed. ret: %d (error: %s)", ret, nl_geterror(-ret));
+               return ret;
+       }
+       return 0;
+}
+
+int handle_netlink_scan(Wifi *wifi, GDBusMethodInvocation *context,
+               const gchar *ifname, GVariant *params)
 {
        DBG("");
        netconfig_nl_global global = {
@@ -825,46 +926,38 @@ int handle_netlink_scan(Wifi *wifi, GDBusMethodInvocation *context, GVariant *pa
        };
 
        /** Initialize netlink socket */
-       int ret = __netconfig_initialize_nl80211(&global);
+       int ret = __netconfig_initialize_nl80211(&global, ifname);
        if (ret < 0) {
                DBG("__netconfig_initialize_nl80211() failed, error %d", ret);
                netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AccessDenied");
-               wifi_complete_netlink_scan(wifi, context);
                return TRUE;
        }
 
+       GSList *ssid_list = NULL;
+       char *vsie = NULL;
+       __netconfig_get_netlink_scan_parameters(params, ssid_list, &vsie);
        /** Request NL80211_CMD_TRIGGER_SCAN to the kernel. */
-       ret = __netconfig_request_netlink_scan(global.socket, global.if_index, global.id, params);
-       if (ret < 0) {
-               DBG("__netconfig_request_netlink_scan() failed, error %d", ret);
-               netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AccessDenied");
-               wifi_complete_netlink_scan(wifi, context);
-               return TRUE;
-       }
+       ret = __netconfig_netlink_scan(&global, ssid_list, vsie);
+       g_slist_free_full(ssid_list, g_free);
+       g_free(vsie);
 
-       ret = __netconfig_initialize_nl_msg(&global);
        if (ret < 0) {
-               DBG("__netconfig_initialize_nl_msg() failed, error %d", ret);
+               DBG("__netconfig_netlink_scan() failed, error %d", ret);
                netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AccessDenied");
-               wifi_complete_netlink_scan(wifi, context);
+               __netconfig_deinitialize_nl80211(&global);
                return TRUE;
        }
 
-       ret = nl_send_auto_complete(global.socket, global.msg);
-       DBG("NL80211_CMD_GET_SCAN sent %d bytes to the kernel", ret);
-
-       /** Receive the kernel message. */
-       ret = nl_recvmsgs_default(global.socket);
-       nlmsg_free(global.msg);
+       ret = __netconfig_get_scan_results(&global);
        if (ret < 0) {
-               DBG("nl_recvmsgs_default() failed. ret: %d (error: %s)", ret, nl_geterror(-ret));
                netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AccessDenied");
-               wifi_complete_netlink_scan(wifi, context);
+               __netconfig_deinitialize_nl80211(&global);
                return TRUE;
        }
 
        wifi_complete_netlink_scan(wifi, context);
-       __netconfig_notify_netlink_scan_done();
+       __netconfig_notify_netlink_scan_done(ifname);
+       __netconfig_deinitialize_nl80211(&global);
 
        return TRUE;
 }