#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;
+ GVariantBuilder *builder1 = NULL;
+ GVariantBuilder *builder2 = NULL;
GSList* list = NULL;
const char *prop_ssid = "ssid";
const char *prop_bssid = "bssid";
const char *prop_freq = "freq";
const char *prop_rssi = "rssi";
- const char *prop_vsie = "vsie";
+ const char *prop_vsie_list = "vsie_list";
+ 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) {
if (bss_info) {
char *bssid = (char *)bss_info->bssid;
char *ssid = (char *)bss_info->ssid;
- char *vsie = (char *)bss_info->vsie;
+ GSList *vsie_list = bss_info->vsie_list;
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));
+ builder1 = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ GSList *list;
+ unsigned char *net_vsie;
+ unsigned int net_vsie_len;
+ int count;
+ for (list = vsie_list; list; list = list->next) {
+ builder2 = g_variant_builder_new(G_VARIANT_TYPE("ay"));
+ net_vsie = (unsigned char *)list->data;
+ net_vsie_len = net_vsie[1] + 2;
+
+ for (count = 0; count < net_vsie_len; count++) {
+ g_variant_builder_add(builder2, "y", net_vsie[count]);
+ }
+
+ g_variant_builder_add(builder1, "{sv}", "Vsie", g_variant_builder_end(builder2));
+ g_variant_builder_unref(builder2);
+ }
+ g_variant_builder_add(builder, "{sv}", prop_vsie_list, g_variant_builder_end(builder1));
+ g_variant_builder_unref(builder1);
+
+ if (vsie_list != NULL)
+ g_slist_free_full(vsie_list, g_free);
+
+ vsie_list = NULL;
+
+ 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_slist_free_full(bss_info_list, g_free);
bss_info_list = NULL;
- __netconfig_stop_scan_timer();
INFO("NetlinkScanCompleted");
return;
}
}
-static void __netconfig_get_vsie(unsigned char *bss_element, int length, char **dst)
+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, GSList **dst)
{
- int i = 0;
- uint8_t len = 0;
- gboolean vsie_found = FALSE;
+ unsigned char *vsie;
+ int vsie_len = 0;
if (length < 3) {
DBG("Vendor specific data not available");
return;
}
- /** Check for vendor specific information element */
- for (i = 0; i < length; i++) {
- if (bss_element[i] == 221) {
- len = bss_element[i+1];
- vsie_found = TRUE;
- goto out;
- }
- }
-out:
- if (vsie_found && memcmp(bss_element+i+2, samsung_oui, 3) == 0) {
- DBG("Vendor Specific IE found, len: %d", len);
- *dst = g_try_malloc0(2*(len+2) + 1);
- if (*dst == NULL) {
- DBG("Failed to allocate memory");
- return;
- }
- char *buf = (*dst);
- int j = 0;
-
- for (j = i; j <= (i + len + 1); j++) {
- snprintf(buf, 3, "%02x", bss_element[j]);
- buf += 2;
+ while (length >= 2 && length >= bss_element[1]) {
+ if (bss_element[0] == NETCONFIG_VENDOR_SPECIFIC_ID) {
+ vsie_len = bss_element[1]+2;
+ vsie = (unsigned char *)g_try_malloc0(vsie_len);
+
+ if (vsie) {
+ memcpy(vsie, bss_element, vsie_len);
+ *dst = g_slist_append(*dst, vsie);
+ } else
+ DBG("Failed to allocate memory");
}
- vsie_found = FALSE;
+ length -= bss_element[1] + 2;
+ bss_element += bss_element[1] + 2;
}
}
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;
}
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
char bssid[NETCONFIG_BSSID_LEN+1];
char ssid[NETCONFIG_SSID_LEN+1] = {0, };
- char *vsie = NULL;
+ wifi_security_type_e sec_type = WIFI_SECURITY_TYPE_NONE;
+ wifi_encryption_type_e enc_type = WIFI_ENCRYPTION_TYPE_NONE;
+ GSList *vsie = NULL;
struct nlattr *tb[NL80211_ATTR_MAX + 1];
struct nlattr *bss[NL80211_BSS_MAX + 1];
struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
__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) {
+ g_slist_free_full(vsie, g_free);
+ 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_slist_free_full(vsie, g_free);
+ return NL_SKIP;
+ }
+ }
/** Create AP info list. */
if (ssid[0] != '\0') {
int signal;
bss_info = g_try_new0(struct bss_scan_info_t, 1);
- if (bss_info == NULL)
+ if (bss_info == NULL) {
+ g_slist_free_full(vsie, g_free);
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);
- }
+ bss_info->vsie_list = vsie;
bss_info->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
if (bss[NL80211_BSS_SIGNAL_MBM]) {
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 ", bss_info->bssid, bss_info->freq,
+ bss_info->signal, bss_info->ssid, bss_info->security_type,
+ bss_info->encryption_type);
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();
- }
- }
+ } else
+ g_slist_free_full(vsie, g_free);
return NL_SKIP;
}
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;
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);
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);
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)
if (results.aborted) {
DBG("scan aborted");
- return 1;
+ goto out;
}
- 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 || ret == 1)
+ return ret;
+
+ DBG("Scan done");
return 0;
}
-gboolean handle_netlink_scan(Wifi *wifi, GDBusMethodInvocation *context)
+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;
+}
+
+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;
}