2 * Network Configuration Module
4 * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
22 #include "netsupplicant.h"
25 #include "wifi-config.h"
26 #include "wifi-netlink-scan.h"
27 #include <netlink/genl/genl.h>
28 #include <netlink/genl/family.h>
29 #include <netlink/genl/ctrl.h>
30 #include <netlink/msg.h>
31 #include <netlink/attr.h>
32 #include <netlink/netlink.h>
35 static GSList *bss_info_list = NULL;
37 void __netconfig_notify_netlink_scan_done(void)
39 GVariantBuilder *builder = NULL;
40 GVariantBuilder *builder1 = NULL;
41 GVariantBuilder *builder2 = NULL;
43 const char *prop_ssid = "ssid";
44 const char *prop_bssid = "bssid";
45 const char *prop_freq = "freq";
46 const char *prop_rssi = "rssi";
47 const char *prop_vsie_list = "vsie_list";
48 const char *prop_sec = "security";
49 const char *prop_enc = "encryption";
51 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
52 for (list = bss_info_list; list != NULL; list = list->next) {
53 struct bss_scan_info_t *bss_info = (struct bss_scan_info_t *)list->data;
56 char *bssid = (char *)bss_info->bssid;
57 char *ssid = (char *)bss_info->ssid;
58 GSList *vsie_list = bss_info->vsie_list;
59 int freq = (int)bss_info->freq;
60 int signal = (int)bss_info->signal;
61 int sec_type = (int)bss_info->security_type;
62 int enc_type = (int)bss_info->encryption_type;
64 g_variant_builder_add(builder, "{sv}", prop_ssid, g_variant_new_string(ssid));
65 g_variant_builder_add(builder, "{sv}", prop_bssid, g_variant_new_string(bssid));
66 g_variant_builder_add(builder, "{sv}", prop_freq, g_variant_new_int32(freq));
67 g_variant_builder_add(builder, "{sv}", prop_rssi, g_variant_new_int32(signal));
68 builder1 = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
70 unsigned char *net_vsie;
71 unsigned int net_vsie_len;
73 for (list = vsie_list; list; list = list->next) {
74 builder2 = g_variant_builder_new(G_VARIANT_TYPE("ay"));
75 net_vsie = (unsigned char *)list->data;
76 net_vsie_len = net_vsie[1] + 2;
78 for (count = 0; count < net_vsie_len; count++) {
79 g_variant_builder_add(builder2, "y", net_vsie[count]);
82 g_variant_builder_add(builder1, "{sv}", "Vsie", g_variant_builder_end(builder2));
83 g_variant_builder_unref(builder2);
85 g_variant_builder_add(builder, "{sv}", prop_vsie_list, g_variant_builder_end(builder1));
86 g_variant_builder_unref(builder1);
88 if (vsie_list != NULL)
89 g_slist_free_full(vsie_list, g_free);
93 g_variant_builder_add(builder, "{sv}", prop_sec, g_variant_new_int32(sec_type));
94 g_variant_builder_add(builder, "{sv}", prop_enc, g_variant_new_int32(enc_type));
98 wifi_emit_netlink_scan_completed((Wifi *)get_wifi_object(), g_variant_builder_end(builder));
99 g_variant_builder_unref(builder);
101 if (bss_info_list != NULL)
102 g_slist_free_full(bss_info_list, g_free);
104 bss_info_list = NULL;
105 INFO("NetlinkScanCompleted");
110 static int ack_handler(struct nl_msg *msg, void *user_data)
112 int *err = user_data;
118 static int finish_handler(struct nl_msg *msg, void *user_data)
120 int *ret = user_data;
125 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
128 int *ret = user_data;
133 static int no_seq_check(struct nl_msg *msg, void *user_data)
139 static int __netconfig_family_handler(struct nl_msg *msg, void *user_data)
141 /** Callback for NL_CB_VALID in multicast group */
142 struct netconfig_netlink_scan_handler_args *grp = user_data;
143 struct nlattr *tb[CTRL_ATTR_MAX + 1];
144 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
145 struct nlattr *mc_grp;
148 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
150 if (!tb[CTRL_ATTR_MCAST_GROUPS])
153 nla_for_each_nested(mc_grp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mc_grp) {
154 struct nlattr *tb_mc_grp[CTRL_ATTR_MCAST_GRP_MAX + 1];
156 nla_parse(tb_mc_grp, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mc_grp), nla_len(mc_grp), NULL);
158 if (!tb_mc_grp[CTRL_ATTR_MCAST_GRP_NAME] || !tb_mc_grp[CTRL_ATTR_MCAST_GRP_ID])
160 if (strncmp(nla_data(tb_mc_grp[CTRL_ATTR_MCAST_GRP_NAME]), grp->group,
161 nla_len(tb_mc_grp[CTRL_ATTR_MCAST_GRP_NAME])))
164 grp->id = nla_get_u32(tb_mc_grp[CTRL_ATTR_MCAST_GRP_ID]);
171 static int __netconfig_get_multicast_id(struct nl_sock *socket, const char *family, const char *group)
173 struct nl_msg *msg = NULL;
174 struct nl_cb *cb = NULL;
176 struct netconfig_netlink_scan_handler_args grp = { .group = group, .id = -ENOENT, };
182 cb = nl_cb_alloc(NL_CB_DEFAULT);
188 ctrl_id = genl_ctrl_resolve(socket, "nlctrl");
190 genlmsg_put(msg, 0, 0, ctrl_id, 0, 0, CTRL_CMD_GETFAMILY, 0);
193 NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
195 ret = nl_send_auto_complete(socket, msg);
201 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret);
202 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &ret);
203 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, __netconfig_family_handler, &grp);
206 nl_recvmsgs(socket, cb);
219 static void __netconfig_macaddress_str(char *bssid, unsigned char *user_data)
223 for (i = 0; i < 6; i++) {
225 snprintf(bssid, 3, "%02x", user_data[i]);
228 snprintf(bssid, 4, ":%02x", user_data[i]);
235 WIFI_SECURITY_TYPE_NONE = 0,
236 WIFI_SECURITY_TYPE_WEP = 1,
237 WIFI_SECURITY_TYPE_WPA_PSK = 2,
238 WIFI_SECURITY_TYPE_WPA2_PSK = 3,
239 WIFI_SECURITY_TYPE_EAP = 4,
240 } wifi_security_type_e;
243 WIFI_ENCRYPTION_TYPE_NONE = 0,
244 WIFI_ENCRYPTION_TYPE_WEP = 1,
245 WIFI_ENCRYPTION_TYPE_TKIP = 2,
246 WIFI_ENCRYPTION_TYPE_AES = 3,
247 WIFI_ENCRYPTION_TYPE_TKIP_AES_MIXED = 4,
248 } wifi_encryption_type_e;
250 static unsigned char ms_oui[3] = { 0x00, 0x50, 0xf2 };
251 static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
253 static void __netconfig_get_security(unsigned char *bss_element, int length, wifi_security_type_e *sec_type, wifi_encryption_type_e *enc_type)
261 *sec_type = WIFI_SECURITY_TYPE_NONE;
262 *enc_type = WIFI_ENCRYPTION_TYPE_NONE;
264 while (length >= 2 && length >= bss_element[1]) {
265 if (bss_element[0] == 221 && (bss_element[1] >= 4 && memcmp(bss_element + 2, ms_oui, 3) == 0)) {
266 data = bss_element + 2 + 4 + 2 + 4;
267 len = bss_element[1] - 4 - 2 - 4;
270 length -= bss_element[1] + 2;
271 bss_element += bss_element[1] + 2;
275 count = data[0] | (data[1] << 8);
277 if (2 + (count * 4) > len) {
278 length -= bss_element[1] + 2;
279 bss_element += bss_element[1] + 2;
283 for (i = 0; i < count; i++) {
284 t_data = (data + 2 + (i * 4));
286 if ((memcmp(t_data, ms_oui, 3) == 0) || (memcmp(t_data, ieee80211_oui, 3) == 0)) {
287 if (t_data[3] == 1 || t_data[3] == 5) { // 1 : WEP-40, 5 : WEP-104
288 *sec_type = WIFI_SECURITY_TYPE_WEP;
289 *enc_type = WIFI_ENCRYPTION_TYPE_WEP;
291 } else if (t_data[3] == 2) { // 2 : TKIP
292 if (*sec_type != WIFI_SECURITY_TYPE_WPA2_PSK)
293 *sec_type = WIFI_SECURITY_TYPE_WPA_PSK;
294 if (*enc_type == WIFI_ENCRYPTION_TYPE_AES)
295 *enc_type = WIFI_ENCRYPTION_TYPE_TKIP_AES_MIXED;
297 *enc_type = WIFI_ENCRYPTION_TYPE_TKIP;
298 } else if (t_data[3] == 4) { // 3 : CCMP
299 if (*sec_type != WIFI_SECURITY_TYPE_WPA2_PSK)
300 *sec_type = WIFI_SECURITY_TYPE_WPA_PSK;
301 if (*enc_type == WIFI_ENCRYPTION_TYPE_TKIP)
302 *enc_type = WIFI_ENCRYPTION_TYPE_TKIP_AES_MIXED;
304 *enc_type = WIFI_ENCRYPTION_TYPE_AES;
309 data += 2 + (count * 4);
310 len -= 2 + (count * 4);
313 length -= bss_element[1] + 2;
314 bss_element += bss_element[1] + 2;
318 count = data[0] | (data[1] << 8);
320 if (2 + (count * 4) > len) {
321 length -= bss_element[1] + 2;
322 bss_element += bss_element[1] + 2;
326 for (i = 0; i < count; i++) {
327 t_data = (data + 2 + (i * 4));
329 if ((memcmp(t_data, ms_oui, 3) == 0) || (memcmp(t_data, ieee80211_oui, 3) == 0)) {
330 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
331 *sec_type = WIFI_SECURITY_TYPE_EAP;
332 } else if (t_data[3] == 2 || t_data[3] == 4 || t_data[3] == 6) { // 2 : PSK, 4 : FT/PSK, 6 : PSK/SHA-256
333 if (*sec_type != WIFI_SECURITY_TYPE_WPA2_PSK)
334 *sec_type = WIFI_SECURITY_TYPE_WPA_PSK;
338 } else if (bss_element[0] == 48 && (bss_element[1] >= 2 && bss_element[1] <= 255)) {
339 data = bss_element + 2 + 2 + 4;
340 len = bss_element[1] - 2 - 4;
343 length -= bss_element[1] + 2;
344 bss_element += bss_element[1] + 2;
348 count = data[0] | (data[1] << 8);
349 if (2 + (count + 4) > len) {
350 length -= bss_element[1] + 2;
351 bss_element += bss_element[1] + 2;
355 for (i = 0; i < count; i++) {
356 t_data = (data + 2 + (i * 4));
358 if ((memcmp(t_data, ms_oui, 3) == 0) || (memcmp(t_data, ieee80211_oui, 3) == 0)) {
359 if (t_data[3] == 1 || t_data[3] == 5) { // 1 : WEP-40, 5 : WEP-104
360 *sec_type = WIFI_SECURITY_TYPE_WEP;
361 *enc_type = WIFI_ENCRYPTION_TYPE_WEP;
363 } else if (t_data[3] == 2) { // 2 : TKIP
364 *sec_type = WIFI_SECURITY_TYPE_WPA2_PSK;
365 if (*enc_type == WIFI_ENCRYPTION_TYPE_AES)
366 *enc_type = WIFI_ENCRYPTION_TYPE_TKIP_AES_MIXED;
368 *enc_type = WIFI_ENCRYPTION_TYPE_TKIP;
369 } else if (t_data[3] == 4) { // 3 : CCMP
370 *sec_type = WIFI_SECURITY_TYPE_WPA2_PSK;
371 if (*enc_type == WIFI_ENCRYPTION_TYPE_TKIP)
372 *enc_type = WIFI_ENCRYPTION_TYPE_TKIP_AES_MIXED;
374 *enc_type = WIFI_ENCRYPTION_TYPE_AES;
379 data += 2 + (count * 4);
380 len -= 2 + (count * 4);
383 length -= bss_element[1] + 2;
384 bss_element += bss_element[1] + 2;
388 count = data[0] | (data[1] << 8);
389 if (2 + (count * 4) > len) {
390 length -= bss_element[1] + 2;
391 bss_element += bss_element[1] + 2;
395 for (i = 0; i < count; i++) {
396 t_data = (data + 2 + (i * 4));
398 if ((memcmp(t_data, ms_oui, 3) == 0) || (memcmp(t_data, ieee80211_oui, 3) == 0)) {
399 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
400 *sec_type = WIFI_SECURITY_TYPE_EAP;
401 } else if (t_data[3] == 2 || t_data[3] == 4 || t_data[3] == 6) { // 2 : PSK, 4 : FT/PSK, 6 : PSK/SHA-256
402 *sec_type = WIFI_SECURITY_TYPE_WPA2_PSK;
408 length -= bss_element[1] + 2;
409 bss_element += bss_element[1] + 2;
415 static void __netconfig_get_vsie(unsigned char *bss_element, int length, GSList **dst)
421 DBG("Vendor specific data not available");
425 while (length >= 2 && length >= bss_element[1]) {
426 if (bss_element[0] == NETCONFIG_VENDOR_SPECIFIC_ID) {
427 vsie_len = bss_element[1]+2;
428 vsie = (unsigned char *)g_try_malloc0(vsie_len);
431 memcpy(vsie, bss_element, vsie_len);
432 *dst = g_slist_append(*dst, vsie);
434 DBG("Failed to allocate memory");
437 length -= bss_element[1] + 2;
438 bss_element += bss_element[1] + 2;
442 static void __netconfig_found_ap(unsigned char *bss_element, int length, char *str)
448 while (length >= 2 && length >= bss_element[1]) {
449 if (bss_element[0] == 0 && bss_element[1] <= 32) {
450 len = bss_element[1];
451 data = bss_element + 2;
452 for (i = 0; i < len; i++) {
453 if (isprint(data[i]) && data[i] != ' ' && data[i] != '\\')
454 snprintf(&str[i], 2, "%c", data[i]);
455 else if (data[i] == ' ' && (i != 0 && i != len -1))
456 snprintf(&str[i], 2, "%c", ' ');
458 snprintf(&str[i], 2, "%c", data[i]);
462 length -= bss_element[1] + 2;
463 bss_element += bss_element[1] + 2;
467 static int __netconfig_netlink_scan_cb(struct nl_msg *msg, void *user_data)
469 /** Called by the kernel with a dump of the successful scan's data. Called for each SSID. */
470 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
471 char bssid[NETCONFIG_BSSID_LEN+1];
472 char ssid[NETCONFIG_SSID_LEN+1] = {0, };
473 wifi_security_type_e sec_type = WIFI_SECURITY_TYPE_NONE;
474 wifi_encryption_type_e enc_type = WIFI_ENCRYPTION_TYPE_NONE;
476 struct nlattr *tb[NL80211_ATTR_MAX + 1];
477 struct nlattr *bss[NL80211_BSS_MAX + 1];
478 struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
479 [NL80211_BSS_FREQUENCY] = {.type = NLA_U32},
480 [NL80211_BSS_BSSID] = { },
481 [NL80211_BSS_INFORMATION_ELEMENTS] = { },
482 [NL80211_BSS_SIGNAL_MBM] = {.type = NLA_U32},
485 /** Parse nl message and check error. */
486 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
487 if (!tb[NL80211_ATTR_BSS]) {
488 DBG("BSS info not available");
491 if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], bss_policy)) {
492 DBG("Failed to parse nested attributes");
495 if ((!bss[NL80211_BSS_BSSID]) || (!bss[NL80211_BSS_INFORMATION_ELEMENTS]))
498 /** Extract BSSID and AP info. */
499 __netconfig_macaddress_str(bssid, nla_data(bss[NL80211_BSS_BSSID]));
500 __netconfig_found_ap(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]), nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]), ssid);
501 __netconfig_get_vsie(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]), nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]), &vsie);
502 __netconfig_get_security(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
503 nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]), &sec_type, &enc_type);
505 if (sec_type == WIFI_SECURITY_TYPE_EAP) {
506 g_slist_free_full(vsie, g_free);
509 for (GSList *list = bss_info_list; list != NULL; list = list->next) {
510 struct bss_scan_info_t *bss_info = (struct bss_scan_info_t *)list->data;
511 if ((g_strcmp0(bss_info->ssid, ssid) == 0) && (bss_info->security_type == sec_type)
512 && (bss_info->encryption_type == enc_type)) {
513 g_slist_free_full(vsie, g_free);
518 /** Create AP info list. */
519 if (ssid[0] != '\0') {
520 struct bss_scan_info_t *bss_info;
523 bss_info = g_try_new0(struct bss_scan_info_t, 1);
524 if (bss_info == NULL) {
525 g_slist_free_full(vsie, g_free);
529 g_strlcpy(bss_info->bssid, bssid, strlen(bssid)+1);
530 g_strlcpy(bss_info->ssid, ssid, strlen(ssid)+1);
531 bss_info->vsie_list = vsie;
532 bss_info->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
534 if (bss[NL80211_BSS_SIGNAL_MBM]) {
535 signal = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
536 signal /= 100; /** mBm to dBm */
537 bss_info->signal = signal;
540 bss_info->security_type = sec_type;
541 bss_info->encryption_type = enc_type;
542 DBG("%s %d %d %s %d %d ", bss_info->bssid, bss_info->freq,
543 bss_info->signal, bss_info->ssid, bss_info->security_type,
544 bss_info->encryption_type);
546 if (bss_info->ssid[0] == '\0')
549 bss_info_list = g_slist_append(bss_info_list, bss_info);
552 g_slist_free_full(vsie, g_free);
557 static int __netconfig_netlink_scan_reply(struct nl_msg *msg, void *user_data)
559 /** Called by the kernel when the scan is done or has been aborted. */
560 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
561 struct netconfig_netlink_scan_results *results = user_data;
563 if (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS) {
564 DBG("Received NL80211_CMD_NEW_SCAN_RESULTS in reply");
566 results->aborted = 0;
567 } else if (gnlh->cmd == NL80211_CMD_SCAN_ABORTED) {
568 DBG("Received NL80211_CMD_SCAN_ABORTED in reply");
570 results->aborted = 1;
576 static int __netconfig_request_netlink_scan(struct nl_sock *socket,
577 int if_index, int id, GVariant *params)
579 struct netconfig_netlink_scan_results results = { .done = 0, .aborted = 0 };
580 struct nl_msg *msg = NULL;
581 struct nl_cb *cb = NULL;
582 struct nl_msg *ssids = NULL;
585 unsigned char ies[NETCONFIG_MAX_VSIE_LEN+1] = {0x00, };
590 gboolean ssid_found = FALSE;
591 int mcid = __netconfig_get_multicast_id(socket, "nl80211", "scan");
593 ret = nl_socket_add_membership(socket, mcid);
595 DBG("Failed to add membership, error: (%s)", nl_geterror(-ret));
601 DBG("Failed to allocate msg");
602 nl_socket_drop_membership(socket, mcid);
605 ssids = nlmsg_alloc();
607 DBG("Failed to allocate ssids");
609 nl_socket_drop_membership(socket, mcid);
612 cb = nl_cb_alloc(NL_CB_DEFAULT);
614 DBG("Failed to allocate callbacks");
617 nl_socket_drop_membership(socket, mcid);
621 /** Set nl message and callback functions. */
622 genlmsg_put(msg, 0, 0, id, 0, 0, NL80211_CMD_TRIGGER_SCAN, 0);
623 ret = nla_put_u32(msg, NL80211_ATTR_IFINDEX, if_index);
625 DBG("Failed to add integer attribute to netlink message, error: (%s)", nl_geterror(-ret));
629 g_variant_get(params, "a{sv}", &iter);
630 while (g_variant_iter_loop(iter, "{sv}", &key, &value)) {
631 if (g_strcmp0(key, "SSID") == 0) {
632 if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
633 char *ssid = g_strdup(g_variant_get_string(value, NULL));
635 DBG("ssid [%s]", ssid);
637 ret = nla_put(ssids, 1, strlen(ssid), ssid);
640 DBG("Failed to add ssid to netlink message, error: (%s)", nl_geterror(-ret));
641 g_variant_iter_free(iter);
645 } else if (g_strcmp0(key, "VSIE") == 0) {
646 if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
647 char *vsie = g_strdup(g_variant_get_string(value, NULL));
648 int vsie_len = strlen(vsie);
649 DBG("vsie: %s vsie_len: %d", vsie, vsie_len);
651 ies_len = (vsie_len % 2) ? ((vsie_len / 2) + 1) : (vsie_len / 2);
652 __netconfig_hex_str_to_bin(vsie, ies, ies_len);
657 g_variant_iter_free(iter);
660 ret = nla_put(ssids, 1, 0, "");
662 DBG("nla_put error: (%s)", nl_geterror(-ret));
666 nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
668 if (ies[0] == NETCONFIG_VENDOR_SPECIFIC_ID && ies[1] >= 4) {
669 DBG("ies_len: %d ies: %02x %02x %02x %02x %02x %02x %02x", ies_len,
670 ies[0], ies[1], ies[2], ies[3], ies[4], ies[5], ies[6]);
671 ret = nla_put(msg, NL80211_ATTR_IE, ies_len, ies);
673 DBG("Failed to add vsie data to netlink message, error: (%s)", nl_geterror(-ret));
679 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, __netconfig_netlink_scan_reply, &results);
680 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
681 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
682 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
683 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
684 ret = nl_socket_set_nonblocking(socket);
685 DBG("Set the non-blocking mode [%d]", ret);
687 /** Send NL80211_CMD_TRIGGER_SCAN to start the scan. */
688 ret = nl_send_auto_complete(socket, msg);
691 DBG("nl_send_auto_complete() error: (%s)", nl_geterror(-ret));
695 DBG("Sent %d bytes to the kernel", ret);
699 ret = nl_recvmsgs(socket, cb);
701 DBG("nl_recvmsgs() ret: %d (%s)", ret, nl_geterror(-ret));
706 while (!results.done) {
707 ret = nl_recvmsgs(socket, cb);
708 if (ret < 0 || err < 0) {
715 if (results.aborted) {
722 /** Release memory */
726 nl_socket_drop_membership(socket, mcid);
728 if (ret < 0 || ret == 1)
735 static int __netconfig_initialize_nl80211(netconfig_nl_global *global)
739 global->if_index = __netconfig_get_interface_index(WIFI_IFNAME);
740 if (global->if_index < 0) {
741 DBG("Failed to get interface index");
745 global->socket = nl_socket_alloc();
746 if (!global->socket) {
747 DBG("Failed to allocate netlink socket.");
751 if (genl_connect(global->socket)) {
752 DBG("Failed to connect to generic netlink.");
757 global->id = genl_ctrl_resolve(global->socket, "nl80211");
758 if (global->id < 0) {
759 DBG("Failed to find the nl80211 driver");
767 nl_socket_free(global->socket);
771 static int __netconfig_initialize_nl_msg(netconfig_nl_global *global)
775 if (global == NULL) {
776 DBG("Invalid parameter.");
780 global->msg = nlmsg_alloc();
781 if (global->msg == NULL) {
782 DBG("Failed to allocate netlink message");
786 /* Set command into message */
787 genlmsg_put(global->msg, 0, 0, global->id, 0, NLM_F_DUMP, NL80211_CMD_GET_SCAN, 0);
788 rv = nla_put_u32(global->msg, NL80211_ATTR_IFINDEX, global->if_index);
790 DBG("Failed to add integer attribute to netlink message.");
791 nlmsg_free(global->msg);
794 nl_socket_modify_cb(global->socket, NL_CB_VALID, NL_CB_CUSTOM, __netconfig_netlink_scan_cb, NULL);
799 int handle_netlink_scan(Wifi *wifi, GDBusMethodInvocation *context, GVariant *params)
802 netconfig_nl_global global = {
809 /** Initialize netlink socket */
810 int ret = __netconfig_initialize_nl80211(&global);
812 DBG("__netconfig_initialize_nl80211() failed, error %d", ret);
813 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AccessDenied");
814 wifi_complete_netlink_scan(wifi, context);
818 /** Request NL80211_CMD_TRIGGER_SCAN to the kernel. */
819 ret = __netconfig_request_netlink_scan(global.socket, global.if_index, global.id, params);
821 DBG("__netconfig_request_netlink_scan() failed, error %d", ret);
822 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AccessDenied");
823 wifi_complete_netlink_scan(wifi, context);
827 ret = __netconfig_initialize_nl_msg(&global);
829 DBG("__netconfig_initialize_nl_msg() failed, error %d", ret);
830 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AccessDenied");
831 wifi_complete_netlink_scan(wifi, context);
835 ret = nl_send_auto_complete(global.socket, global.msg);
836 DBG("NL80211_CMD_GET_SCAN sent %d bytes to the kernel", ret);
838 /** Receive the kernel message. */
839 ret = nl_recvmsgs_default(global.socket);
840 nlmsg_free(global.msg);
842 DBG("nl_recvmsgs_default() failed. ret: %d (error: %s)", ret, nl_geterror(-ret));
843 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AccessDenied");
844 wifi_complete_netlink_scan(wifi, context);
848 wifi_complete_netlink_scan(wifi, context);
849 __netconfig_notify_netlink_scan_done();