Fixed some coverity
[platform/core/connectivity/net-config.git] / src / wifi-netlink-scan.c
index 7c3f9b2..e008fd2 100755 (executable)
@@ -22,6 +22,7 @@
 #include "netsupplicant.h"
 #include "log.h"
 #include "util.h"
+#include "wifi-config.h"
 #include "wifi-netlink-scan.h"
 #include <netlink/genl/genl.h>
 #include <netlink/genl/family.h>
 #include <ctype.h>
 
 static GSList *bss_info_list = NULL;
-static guint scan_timer = 0;
 static unsigned char samsung_oui[3] = {0x00, 0x16, 0x32};
 
-static gboolean __netconfig_scan_timeout(gpointer data)
-{
-       __netconfig_notify_netlink_scan_done();
-
-       return FALSE;
-}
-
-static void __netconfig_start_scan_timer(void)
-{
-       if (scan_timer == 0) {
-               netconfig_start_timer_seconds(5, __netconfig_scan_timeout, NULL, &scan_timer);
-               INFO("Get scan data timer started: %d", scan_timer);
-       }
-}
-
-static void __netconfig_stop_scan_timer(void)
-{
-       netconfig_stop_timer(&scan_timer);
-       INFO("Get scan data timer stopped: %d", scan_timer);
-}
-
 void __netconfig_notify_netlink_scan_done(void)
 {
        GVariantBuilder *builder = NULL;
@@ -65,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) {
@@ -76,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));
                }
        }
 
@@ -92,7 +77,6 @@ void __netconfig_notify_netlink_scan_done(void)
                g_slist_free_full(bss_info_list, g_free);
 
        bss_info_list = NULL;
-       __netconfig_stop_scan_timer();
        INFO("NetlinkScanCompleted");
 
        return;
@@ -221,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;
@@ -276,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;
                }
@@ -291,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];
@@ -318,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') {
@@ -325,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]);
 
@@ -341,19 +524,21 @@ 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);
                else
                        bss_info_list = g_slist_append(bss_info_list, bss_info);
 
-               if (scan_timer == 0) {
-                       DBG("Start scan timer");
-                       __netconfig_start_scan_timer();
-               }
        }
 
+       g_free(vsie);
        return NL_SKIP;
 }
 
@@ -376,7 +561,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)
+static int __netconfig_request_netlink_scan(struct nl_sock *socket,
+               int if_index, int id, GVariant *params)
 {
        struct netconfig_netlink_scan_results results = { .done = 0, .aborted = 0 };
        struct nl_msg *msg = NULL;
@@ -384,18 +570,31 @@ static int __netconfig_request_netlink_scan(struct nl_sock *socket, int if_index
        struct nl_msg *ssids = NULL;
        int err = 0;
        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");
-       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);
@@ -403,16 +602,68 @@ static int __netconfig_request_netlink_scan(struct nl_sock *socket, int if_index
                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);
-       nla_put(ssids, 1, 0, "");
+       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)) {
+               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);
+                       }
+               }
+       }
+       g_variant_iter_free(iter);
+
+       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]);
+               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;
        nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, __netconfig_netlink_scan_reply, &results);
        nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
        nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
@@ -420,15 +671,21 @@ static int __netconfig_request_netlink_scan(struct nl_sock *socket, int if_index
        nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
 
        /** Send NL80211_CMD_TRIGGER_SCAN to start the scan. */
-       err = 1;
        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;
+
        while (err > 0)
                ret = nl_recvmsgs(socket, cb);
 
        if (ret < 0) {
                DBG("nl_recvmsgs() ret: %d (%s)", ret, nl_geterror(-ret));
-               return ret;
+               goto out;
        }
 
        while (!results.done)
@@ -438,51 +695,132 @@ static int __netconfig_request_netlink_scan(struct nl_sock *socket, int if_index
                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;
+}
+
+static int __netconfig_initialize_nl80211(netconfig_nl_global *global)
+{
+       int err = 0;
+
+       global->if_index = __netconfig_get_interface_index(WIFI_IFNAME);
+       if (global->if_index < 0) {
+               DBG("Failed to get interface index");
+               return -1;
+       }
+
+       global->socket = nl_socket_alloc();
+       if (!global->socket) {
+               DBG("Failed to allocate netlink socket.");
+               return -ENOMEM;
+       }
+
+       if (genl_connect(global->socket)) {
+               DBG("Failed to connect to generic netlink.");
+               err = -ENOLINK;
+               goto fail;
+       }
+
+       global->id = genl_ctrl_resolve(global->socket, "nl80211");
+       if (global->id < 0) {
+               DBG("Failed to find the nl80211 driver");
+               err = -ENOENT;
+               goto fail;
+       }
+
+       return 0;
+
+fail:
+       nl_socket_free(global->socket);
+       return err;
+}
+
+static int __netconfig_initialize_nl_msg(netconfig_nl_global *global)
+{
+       int rv;
+
+       if (global == NULL) {
+               DBG("Invalid parameter.");
+               return -EINVAL;
+       }
+
+       global->msg = nlmsg_alloc();
+       if (global->msg == NULL) {
+               DBG("Failed to allocate netlink message");
+               return -ENOMEM;
+       }
+
+       /* Set command into message */
+       genlmsg_put(global->msg, 0, 0, global->id, 0, NLM_F_DUMP, NL80211_CMD_GET_SCAN, 0);
+       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;
 }
 
-gboolean handle_netlink_scan(Wifi *wifi, GDBusMethodInvocation *context)
+int handle_netlink_scan(Wifi *wifi, GDBusMethodInvocation *context, GVariant *params)
 {
        DBG("");
-       int if_index = __netconfig_get_interface_index(WIFI_IFNAME);
+       netconfig_nl_global global = {
+               .id = -1,
+               .if_index = -1,
+               .socket = NULL,
+               .msg = NULL,
+       };
 
-       /** Open socket to kernel. */
-       struct nl_sock *socket = nl_socket_alloc();
-       genl_connect(socket);
-       int id = genl_ctrl_resolve(socket, "nl80211");
+       /** Initialize netlink socket */
+       int ret = __netconfig_initialize_nl80211(&global);
+       if (ret < 0) {
+               DBG("__netconfig_initialize_nl80211() failed, error %d", ret);
+               wifi_complete_netlink_scan(wifi, context);
+               return TRUE;
+       }
 
        /** Request NL80211_CMD_TRIGGER_SCAN to the kernel. */
-       int err = __netconfig_request_netlink_scan(socket, if_index, id);
-       if (err != 0) {
-               DBG("__netconfig_request_netlink_scan() failed, error %d", err);
+       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);
                wifi_complete_netlink_scan(wifi, context);
-               return err;
+               return TRUE;
        }
 
-       /** Get info of all available APs. */
-       struct nl_msg *msg = nlmsg_alloc();
-       genlmsg_put(msg, 0, 0, id, 0, NLM_F_DUMP, NL80211_CMD_GET_SCAN, 0);
-       nla_put_u32(msg, NL80211_ATTR_IFINDEX, if_index);
-       nl_socket_modify_cb(socket, NL_CB_VALID, NL_CB_CUSTOM, __netconfig_netlink_scan_cb, NULL);
+       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 TRUE;
+       }
 
-       int ret = nl_send_auto_complete(socket, msg);
+       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(socket);
-       nlmsg_free(msg);
+       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));
                wifi_complete_netlink_scan(wifi, context);
-               return ret;
+               return TRUE;
        }
 
        wifi_complete_netlink_scan(wifi, context);
+       __netconfig_notify_netlink_scan_done();
+
        return TRUE;
 }