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 static gint __netconfig_compare_bss_by_rssi(gconstpointer a, gconstpointer b)
39 struct bss_scan_info_t *entry_a = (struct bss_scan_info_t *) a;
40 struct bss_scan_info_t *entry_b = (struct bss_scan_info_t *) b;
42 if (entry_a->signal > entry_b->signal)
45 if (entry_a->signal < entry_b->signal)
51 void __netconfig_notify_netlink_scan_done(const char *interface_name)
53 GVariantBuilder *builder = NULL;
54 GVariantBuilder *builder1 = NULL;
55 GVariantBuilder *builder2 = NULL;
57 const char *prop_ssid = "ssid";
58 const char *prop_bssid = "bssid";
59 const char *prop_freq = "freq";
60 const char *prop_rssi = "rssi";
61 const char *prop_vsie_list = "vsie_list";
62 const char *prop_sec = "security";
63 const char *prop_enc = "encryption";
64 const char *prop_pmf = "pmf";
66 bss_info_list = g_slist_sort(bss_info_list, __netconfig_compare_bss_by_rssi);
68 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
69 for (list = bss_info_list; list != NULL; list = list->next) {
70 struct bss_scan_info_t *bss_info = (struct bss_scan_info_t *)list->data;
73 char *bssid = (char *)bss_info->bssid;
74 char *ssid = (char *)bss_info->ssid;
75 int ssid_len = bss_info->ssid_len;
76 GSList *vsie_list = bss_info->vsie_list;
77 int freq = (int)bss_info->freq;
78 int signal = (int)bss_info->signal;
79 int sec_type = (int)bss_info->security_type;
80 int enc_type = (int)bss_info->encryption_type;
81 int pmf_required = (int)bss_info->pmf_required;
83 builder1 = g_variant_builder_new(G_VARIANT_TYPE("ay"));
84 for (int i = 0; i < ssid_len; i++)
85 g_variant_builder_add(builder1, "y", ssid[i]);
86 g_variant_builder_add(builder, "{sv}", prop_ssid, g_variant_builder_end(builder1));
87 g_variant_builder_unref(builder1);
89 g_variant_builder_add(builder, "{sv}", prop_bssid, g_variant_new_string(bssid));
90 g_variant_builder_add(builder, "{sv}", prop_freq, g_variant_new_int32(freq));
91 g_variant_builder_add(builder, "{sv}", prop_rssi, g_variant_new_int32(signal));
92 builder1 = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
94 unsigned char *net_vsie;
95 unsigned int net_vsie_len;
97 for (list = vsie_list; list; list = list->next) {
98 builder2 = g_variant_builder_new(G_VARIANT_TYPE("ay"));
99 net_vsie = (unsigned char *)list->data;
100 net_vsie_len = net_vsie[1] + 2;
102 for (count = 0; count < net_vsie_len; count++) {
103 g_variant_builder_add(builder2, "y", net_vsie[count]);
106 g_variant_builder_add(builder1, "{sv}", "Vsie", g_variant_builder_end(builder2));
107 g_variant_builder_unref(builder2);
109 g_variant_builder_add(builder, "{sv}", prop_vsie_list, g_variant_builder_end(builder1));
110 g_variant_builder_unref(builder1);
112 if (vsie_list != NULL)
113 g_slist_free_full(vsie_list, g_free);
117 g_variant_builder_add(builder, "{sv}", prop_sec, g_variant_new_int32(sec_type));
118 g_variant_builder_add(builder, "{sv}", prop_enc, g_variant_new_int32(enc_type));
119 g_variant_builder_add(builder, "{sv}", prop_pmf, g_variant_new_int32(pmf_required));
123 wifi_emit_netlink_scan_completed((Wifi *)get_wifi_object(),
124 interface_name, g_variant_builder_end(builder));
125 g_variant_builder_unref(builder);
127 if (bss_info_list != NULL)
128 g_slist_free_full(bss_info_list, g_free);
130 bss_info_list = NULL;
131 INFO("NetlinkScanCompleted");
136 static int ack_handler(struct nl_msg *msg, void *user_data)
138 int *err = user_data;
144 static int finish_handler(struct nl_msg *msg, void *user_data)
146 int *ret = user_data;
153 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
156 int *ret = user_data;
163 static int no_seq_check(struct nl_msg *msg, void *user_data)
169 static int __netconfig_family_handler(struct nl_msg *msg, void *user_data)
171 /** Callback for NL_CB_VALID in multicast group */
172 struct netconfig_netlink_scan_handler_args *grp = user_data;
173 struct nlattr *tb[CTRL_ATTR_MAX + 1];
174 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
175 struct nlattr *mc_grp;
178 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
180 if (!tb[CTRL_ATTR_MCAST_GROUPS])
183 nla_for_each_nested(mc_grp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mc_grp) {
184 struct nlattr *tb_mc_grp[CTRL_ATTR_MCAST_GRP_MAX + 1];
186 nla_parse(tb_mc_grp, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mc_grp), nla_len(mc_grp), NULL);
188 if (!tb_mc_grp[CTRL_ATTR_MCAST_GRP_NAME] || !tb_mc_grp[CTRL_ATTR_MCAST_GRP_ID])
190 if (strncmp(nla_data(tb_mc_grp[CTRL_ATTR_MCAST_GRP_NAME]), grp->group,
191 nla_len(tb_mc_grp[CTRL_ATTR_MCAST_GRP_NAME])))
194 grp->id = nla_get_u32(tb_mc_grp[CTRL_ATTR_MCAST_GRP_ID]);
201 static int __netconfig_get_multicast_id(struct nl_sock *socket, const char *family, const char *group)
203 struct nl_msg *msg = NULL;
204 struct nl_cb *cb = NULL;
206 struct netconfig_netlink_scan_handler_args grp = { .group = group, .id = -ENOENT, };
212 cb = nl_cb_alloc(NL_CB_DEFAULT);
218 ctrl_id = genl_ctrl_resolve(socket, "nlctrl");
220 genlmsg_put(msg, 0, 0, ctrl_id, 0, 0, CTRL_CMD_GETFAMILY, 0);
223 NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
225 ret = nl_send_auto_complete(socket, msg);
231 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret);
232 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &ret);
233 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, __netconfig_family_handler, &grp);
236 nl_recvmsgs(socket, cb);
249 static void __netconfig_macaddress_str(char *bssid, unsigned char *user_data)
253 for (i = 0; i < 6; i++) {
255 snprintf(bssid, 3, "%02x", user_data[i]);
258 snprintf(bssid, 4, ":%02x", user_data[i]);
265 WIFI_SECURITY_TYPE_NONE = 0,
266 WIFI_SECURITY_TYPE_WEP = 1,
267 WIFI_SECURITY_TYPE_WPA_PSK = 2,
268 WIFI_SECURITY_TYPE_WPA2_PSK = 3,
269 WIFI_SECURITY_TYPE_SAE = 4,
270 WIFI_SECURITY_TYPE_EAP = 5,
271 } wifi_security_type_e;
274 WIFI_ENCRYPTION_TYPE_NONE = 0,
275 WIFI_ENCRYPTION_TYPE_WEP = 1,
276 WIFI_ENCRYPTION_TYPE_TKIP = 2,
277 WIFI_ENCRYPTION_TYPE_AES = 3,
278 WIFI_ENCRYPTION_TYPE_TKIP_AES_MIXED = 4,
279 } wifi_encryption_type_e;
281 static unsigned char ms_oui[3] = { 0x00, 0x50, 0xf2 };
282 static unsigned char ieee80211_oui[3] = { 0x00, 0x0f, 0xac };
284 static void __netconfig_get_security(unsigned char *bss_element, int length,
285 wifi_security_type_e *sec_type, wifi_encryption_type_e *enc_type, int *pmf_required)
292 gboolean ieee80211_psk = false;
294 *sec_type = WIFI_SECURITY_TYPE_NONE;
295 *enc_type = WIFI_ENCRYPTION_TYPE_NONE;
297 while (length >= 2 && length >= bss_element[1]) {
298 if (bss_element[0] == 221 && (bss_element[1] >= 4 && memcmp(bss_element + 2, ms_oui, 3) == 0)) {
299 data = bss_element + 2 + 4 + 2 + 4;
300 len = bss_element[1] - 4 - 2 - 4;
303 length -= bss_element[1] + 2;
304 bss_element += bss_element[1] + 2;
308 count = data[0] | (data[1] << 8);
310 if (2 + (count * 4) > len) {
311 length -= bss_element[1] + 2;
312 bss_element += bss_element[1] + 2;
316 for (i = 0; i < count; i++) {
317 t_data = (data + 2 + (i * 4));
319 if ((memcmp(t_data, ms_oui, 3) == 0) || (memcmp(t_data, ieee80211_oui, 3) == 0)) {
320 if (t_data[3] == 1 || t_data[3] == 5) { // 1 : WEP-40, 5 : WEP-104
321 *sec_type = WIFI_SECURITY_TYPE_WEP;
322 *enc_type = WIFI_ENCRYPTION_TYPE_WEP;
324 } else if (t_data[3] == 2) { // 2 : TKIP
325 if (*sec_type != WIFI_SECURITY_TYPE_WPA2_PSK)
326 *sec_type = WIFI_SECURITY_TYPE_WPA_PSK;
327 if (*enc_type == WIFI_ENCRYPTION_TYPE_AES)
328 *enc_type = WIFI_ENCRYPTION_TYPE_TKIP_AES_MIXED;
330 *enc_type = WIFI_ENCRYPTION_TYPE_TKIP;
331 } else if (t_data[3] == 4) { // 3 : CCMP
332 if (*sec_type != WIFI_SECURITY_TYPE_WPA2_PSK)
333 *sec_type = WIFI_SECURITY_TYPE_WPA_PSK;
334 if (*enc_type == WIFI_ENCRYPTION_TYPE_TKIP)
335 *enc_type = WIFI_ENCRYPTION_TYPE_TKIP_AES_MIXED;
337 *enc_type = WIFI_ENCRYPTION_TYPE_AES;
342 data += 2 + (count * 4);
343 len -= 2 + (count * 4);
346 length -= bss_element[1] + 2;
347 bss_element += bss_element[1] + 2;
351 count = data[0] | (data[1] << 8);
353 if (2 + (count * 4) > len) {
354 length -= bss_element[1] + 2;
355 bss_element += bss_element[1] + 2;
359 for (i = 0; i < count; i++) {
360 t_data = (data + 2 + (i * 4));
362 if ((memcmp(t_data, ms_oui, 3) == 0) || (memcmp(t_data, ieee80211_oui, 3) == 0)) {
363 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
364 *sec_type = WIFI_SECURITY_TYPE_EAP;
365 } else if (t_data[3] == 2 || t_data[3] == 4 || t_data[3] == 6) { // 2 : PSK, 4 : FT/PSK, 6 : PSK/SHA-256
368 if (*sec_type != WIFI_SECURITY_TYPE_WPA2_PSK)
369 *sec_type = WIFI_SECURITY_TYPE_WPA_PSK;
373 } else if (bss_element[0] == 48 && (bss_element[1] >= 2 && bss_element[1] <= 255)) {
374 data = bss_element + 2 + 2 + 4;
375 len = bss_element[1] - 2 - 4;
378 length -= bss_element[1] + 2;
379 bss_element += bss_element[1] + 2;
383 count = data[0] | (data[1] << 8);
384 if (2 + (count + 4) > len) {
385 length -= bss_element[1] + 2;
386 bss_element += bss_element[1] + 2;
390 for (i = 0; i < count; i++) {
391 t_data = (data + 2 + (i * 4));
393 if ((memcmp(t_data, ms_oui, 3) == 0) || (memcmp(t_data, ieee80211_oui, 3) == 0)) {
394 if (t_data[3] == 1 || t_data[3] == 5) { // 1 : WEP-40, 5 : WEP-104
395 *sec_type = WIFI_SECURITY_TYPE_WEP;
396 *enc_type = WIFI_ENCRYPTION_TYPE_WEP;
398 } else if (t_data[3] == 2) { // 2 : TKIP
399 *sec_type = WIFI_SECURITY_TYPE_WPA2_PSK;
400 if (*enc_type == WIFI_ENCRYPTION_TYPE_AES)
401 *enc_type = WIFI_ENCRYPTION_TYPE_TKIP_AES_MIXED;
403 *enc_type = WIFI_ENCRYPTION_TYPE_TKIP;
404 } else if (t_data[3] == 4) { // 3 : CCMP
405 *sec_type = WIFI_SECURITY_TYPE_WPA2_PSK;
406 if (*enc_type == WIFI_ENCRYPTION_TYPE_TKIP)
407 *enc_type = WIFI_ENCRYPTION_TYPE_TKIP_AES_MIXED;
409 *enc_type = WIFI_ENCRYPTION_TYPE_AES;
414 data += 2 + (count * 4);
415 len -= 2 + (count * 4);
418 length -= bss_element[1] + 2;
419 bss_element += bss_element[1] + 2;
423 count = data[0] | (data[1] << 8);
424 if (2 + (count * 4) > len) {
425 length -= bss_element[1] + 2;
426 bss_element += bss_element[1] + 2;
430 for (i = 0; i < count; i++) {
431 t_data = (data + 2 + (i * 4));
433 if ((memcmp(t_data, ms_oui, 3) == 0) || (memcmp(t_data, ieee80211_oui, 3) == 0)) {
434 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
435 *sec_type = WIFI_SECURITY_TYPE_EAP;
436 } else if (t_data[3] == 2 || t_data[3] == 4 || t_data[3] == 6) { // 2 : PSK, 4 : FT/PSK, 6 : PSK/SHA-256
439 *sec_type = WIFI_SECURITY_TYPE_WPA2_PSK;
440 ieee80211_psk = true;
441 } else if (t_data[3] == 8) { // Add SAE security type for netlink scan
442 if (ieee80211_psk != true)
443 *sec_type = WIFI_SECURITY_TYPE_SAE;
449 length -= bss_element[1] + 2;
450 bss_element += bss_element[1] + 2;
456 static void __netconfig_get_vsie(unsigned char *bss_element, int length, GSList **dst)
462 DBG("Vendor specific data not available");
466 while (length >= 2 && length >= bss_element[1]) {
467 if (bss_element[0] == NETCONFIG_VENDOR_SPECIFIC_ID) {
468 vsie_len = bss_element[1]+2;
469 vsie = (unsigned char *)g_try_malloc0(vsie_len);
472 memcpy(vsie, bss_element, vsie_len);
473 *dst = g_slist_append(*dst, vsie);
475 DBG("Failed to allocate memory");
478 length -= bss_element[1] + 2;
479 bss_element += bss_element[1] + 2;
483 static void __netconfig_found_ap(unsigned char *bss_element, int length, char *str, int *ssid_len)
491 while (length >= 2 && length >= bss_element[1]) {
492 if (bss_element[0] == 0 && bss_element[1] <= 32) {
493 len = bss_element[1];
494 data = bss_element + 2;
495 for (i = 0; i < len; i++) {
496 memcpy(&str[i], &data[i], 1);
501 length -= bss_element[1] + 2;
502 bss_element += bss_element[1] + 2;
506 static int __netconfig_netlink_scan_cb(struct nl_msg *msg, void *user_data)
508 /** Called by the kernel with a dump of the successful scan's data. Called for each SSID. */
509 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
510 char bssid[NETCONFIG_BSSID_LEN+1];
511 char ssid[NETCONFIG_SSID_LEN+1] = {0, };
513 wifi_security_type_e sec_type = WIFI_SECURITY_TYPE_NONE;
514 wifi_encryption_type_e enc_type = WIFI_ENCRYPTION_TYPE_NONE;
517 struct nlattr *tb[NL80211_ATTR_MAX + 1];
518 struct nlattr *bss[NL80211_BSS_MAX + 1];
519 struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
520 [NL80211_BSS_FREQUENCY] = {.type = NLA_U32},
521 [NL80211_BSS_BSSID] = { },
522 [NL80211_BSS_CAPABILITY] = {.type = NLA_U16},
523 [NL80211_BSS_INFORMATION_ELEMENTS] = { },
524 [NL80211_BSS_SIGNAL_MBM] = {.type = NLA_U32},
529 /** Parse nl message and check error. */
530 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
531 if (!tb[NL80211_ATTR_BSS]) {
532 DBG("BSS info not available");
535 if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], bss_policy)) {
536 DBG("Failed to parse nested attributes");
539 if ((!bss[NL80211_BSS_BSSID]) || (!bss[NL80211_BSS_INFORMATION_ELEMENTS]))
542 /** Extract BSSID and AP info. */
543 __netconfig_macaddress_str(bssid, nla_data(bss[NL80211_BSS_BSSID]));
544 __netconfig_found_ap(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]), nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]), ssid, &ssid_len);
545 __netconfig_get_vsie(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]), nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]), &vsie);
547 if (bss[NL80211_BSS_CAPABILITY]) {
548 __u16 capa = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
549 if (capa & WLAN_CAPABILITY_PRIVACY) {
553 __netconfig_get_security(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
554 nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]), &sec_type, &enc_type, &pmf_needed);
556 if (wep_check && sec_type == WIFI_SECURITY_TYPE_NONE) {
557 sec_type = WIFI_SECURITY_TYPE_WEP;
558 enc_type = WIFI_ENCRYPTION_TYPE_WEP;
561 if (sec_type == WIFI_SECURITY_TYPE_EAP) {
562 g_slist_free_full(vsie, g_free);
565 for (GSList *list = bss_info_list; list != NULL; list = list->next) {
566 struct bss_scan_info_t *bss_info = (struct bss_scan_info_t *)list->data;
567 if ((g_strcmp0(bss_info->ssid, ssid) == 0) && (bss_info->security_type == sec_type)
568 && (bss_info->encryption_type == enc_type)) {
569 g_slist_free_full(vsie, g_free);
574 /** Create AP info list. */
575 if (ssid[0] != '\0') {
576 struct bss_scan_info_t *bss_info;
579 bss_info = g_try_new0(struct bss_scan_info_t, 1);
580 if (bss_info == NULL) {
581 g_slist_free_full(vsie, g_free);
585 g_strlcpy(bss_info->bssid, bssid, strlen(bssid)+1);
586 g_strlcpy(bss_info->ssid, ssid, ssid_len+1);
587 bss_info->ssid_len = ssid_len;
588 bss_info->vsie_list = vsie;
589 bss_info->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
591 if (bss[NL80211_BSS_SIGNAL_MBM]) {
592 signal = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
593 signal /= 100; /** mBm to dBm */
594 bss_info->signal = signal;
597 bss_info->security_type = sec_type;
598 bss_info->encryption_type = enc_type;
599 bss_info->pmf_required = pmf_needed;
600 SECURE_LOGD("%s %d %d %s %d %d %d ", bss_info->bssid, bss_info->freq,
601 bss_info->signal, bss_info->ssid, bss_info->security_type,
602 bss_info->encryption_type, bss_info->pmf_required);
604 if (bss_info->ssid[0] == '\0')
607 bss_info_list = g_slist_append(bss_info_list, bss_info);
610 g_slist_free_full(vsie, g_free);
615 static int __netconfig_netlink_scan_reply(struct nl_msg *msg, void *user_data)
617 /** Called by the kernel when the scan is done or has been aborted. */
618 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
619 struct netconfig_netlink_scan_results *results = user_data;
621 if (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS) {
622 DBG("Received NL80211_CMD_NEW_SCAN_RESULTS in reply");
624 results->aborted = 0;
625 } else if (gnlh->cmd == NL80211_CMD_SCAN_ABORTED) {
626 DBG("Received NL80211_CMD_SCAN_ABORTED in reply");
628 results->aborted = 1;
634 static int __netconfig_trigger_netlink_scan(struct nl_sock *socket,
635 int if_index, int id, GSList *ssid_list, char *vsie)
637 struct netconfig_netlink_scan_results results = { .done = 0, .aborted = 0 };
638 struct nl_msg *msg = NULL;
639 struct nl_cb *cb = NULL;
640 struct nl_msg *ssids = NULL;
643 unsigned char ies[NETCONFIG_MAX_VSIE_LEN+1] = {0x00, };
645 int mcid = __netconfig_get_multicast_id(socket, "nl80211", "scan");
648 ret = nl_socket_add_membership(socket, mcid);
650 DBG("Failed to add membership, error: (%s)", nl_geterror(-ret));
656 DBG("Failed to allocate msg");
657 nl_socket_drop_membership(socket, mcid);
660 ssids = nlmsg_alloc();
662 DBG("Failed to allocate ssids");
664 nl_socket_drop_membership(socket, mcid);
667 cb = nl_cb_alloc(NL_CB_DEFAULT);
669 DBG("Failed to allocate callbacks");
672 nl_socket_drop_membership(socket, mcid);
676 /** Set nl message and callback functions. */
677 genlmsg_put(msg, 0, 0, id, 0, 0, NL80211_CMD_TRIGGER_SCAN, 0);
678 ret = nla_put_u32(msg, NL80211_ATTR_IFINDEX, if_index);
680 DBG("Failed to add integer attribute to netlink message, error: (%s)", nl_geterror(-ret));
684 for (GSList *i = ssid_list; i; i = i->next) {
685 char *ssid = (char *)i->data;
686 ret = nla_put(ssids, 1, strlen(ssid), ssid);
688 DBG("Failed to add ssid to netlink message, error: (%s)", nl_geterror(-ret));
693 if (g_slist_length(ssid_list) == 0) {
694 DBG("Scan with no ssids");
695 ret = nla_put(ssids, 1, 0, "");
697 DBG("nla_put error: (%s)", nl_geterror(-ret));
701 nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
704 int vsie_len = strlen(vsie);
705 DBG("vsie: %s vsie_len: %d", vsie, vsie_len);
706 ies_len = (vsie_len % 2) ? ((vsie_len / 2) + 1) : (vsie_len / 2);
707 __netconfig_hex_str_to_bin(vsie, ies, ies_len);
710 if (ies[0] == NETCONFIG_VENDOR_SPECIFIC_ID && ies[1] >= 4) {
711 DBG("ies_len: %d ies: %02x %02x %02x %02x %02x %02x %02x", ies_len,
712 ies[0], ies[1], ies[2], ies[3], ies[4], ies[5], ies[6]);
713 ret = nla_put(msg, NL80211_ATTR_IE, ies_len, ies);
715 DBG("Failed to add vsie data to netlink message, error: (%s)", nl_geterror(-ret));
721 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, __netconfig_netlink_scan_reply, &results);
722 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
723 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
724 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
725 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
726 ret = nl_socket_set_nonblocking(socket);
727 DBG("Set the non-blocking mode [%d]", ret);
729 /** Send NL80211_CMD_TRIGGER_SCAN to start the scan. */
730 ret = nl_send_auto_complete(socket, msg);
733 DBG("nl_send_auto_complete() error: (%s)", nl_geterror(-ret));
737 DBG("Sent %d bytes to the kernel", ret);
740 ret = nl_recvmsgs(socket, cb);
742 DBG("nl_recvmsgs() ret: %d (%s)", ret, nl_geterror(-ret));
748 DBG("error code = %d", err);
753 while (!results.done) {
754 ret = nl_recvmsgs(socket, cb);
755 #if !defined TIZEN_WEARABLE
756 if (ret == -NLE_AGAIN && err >= 0)
764 DBG("scan failed err: %d", err);
770 if (results.aborted) {
777 /** Release memory */
781 nl_socket_drop_membership(socket, mcid);
783 if (ret < 0 || ret == 1)
790 static int __netconfig_netlink_scan(netconfig_nl_global *global, GSList *ssid_list, char *vsie)
793 int ret = __netconfig_trigger_netlink_scan(global->socket, global->if_index, global->id, ssid_list, vsie);
794 if (ret == -NLE_AGAIN) {
796 ret = __netconfig_trigger_netlink_scan(global->socket, global->if_index, global->id, ssid_list, vsie);
801 static int __netconfig_initialize_nl80211(netconfig_nl_global *global,
802 const char *interface_name)
806 global->if_index = __netconfig_get_interface_index(interface_name);
807 if (global->if_index < 0) {
808 DBG("Failed to get interface index");
812 global->socket = nl_socket_alloc();
813 if (!global->socket) {
814 DBG("Failed to allocate netlink socket.");
818 if (genl_connect(global->socket)) {
819 DBG("Failed to connect to generic netlink.");
824 global->id = genl_ctrl_resolve(global->socket, "nl80211");
825 if (global->id < 0) {
826 DBG("Failed to find the nl80211 driver");
834 nl_socket_free(global->socket);
838 static void __netconfig_deinitialize_nl80211(netconfig_nl_global *global)
843 if (global->socket) {
844 nl_socket_free(global->socket);
845 global->socket = NULL;
849 static int __netconfig_initialize_nl_msg(netconfig_nl_global *global)
853 if (global == NULL) {
854 DBG("Invalid parameter.");
858 global->msg = nlmsg_alloc();
859 if (global->msg == NULL) {
860 DBG("Failed to allocate netlink message");
864 /* Set command into message */
865 genlmsg_put(global->msg, 0, 0, global->id, 0, NLM_F_DUMP, NL80211_CMD_GET_SCAN, 0);
866 rv = nla_put_u32(global->msg, NL80211_ATTR_IFINDEX, global->if_index);
868 DBG("Failed to add integer attribute to netlink message.");
869 nlmsg_free(global->msg);
872 nl_socket_modify_cb(global->socket, NL_CB_VALID, NL_CB_CUSTOM, __netconfig_netlink_scan_cb, NULL);
877 static void __netconfig_get_netlink_scan_parameters(GVariant *params, GSList *ssid_list, char **vsie)
882 g_variant_get(params, "a{sv}", &iter);
883 while (g_variant_iter_loop(iter, "{sv}", &key, &value)) {
884 if (g_strcmp0(key, "SSID") == 0) {
885 if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
886 char *ssid = g_strdup(g_variant_get_string(value, NULL));
887 DBG("ssid [%s]", ssid);
888 ssid_list = g_slist_append(ssid_list, ssid);
890 } else if (g_strcmp0(key, "VSIE") == 0) {
891 if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING))
892 *vsie = g_strdup(g_variant_get_string(value, NULL));
895 g_variant_iter_free(iter);
898 static int __netconfig_get_scan_results(netconfig_nl_global *global)
900 int ret = __netconfig_initialize_nl_msg(global);
902 DBG("__netconfig_initialize_nl_msg() failed, error %d", ret);
906 ret = nl_send_auto_complete(global->socket, global->msg);
908 DBG("nl_send_auto_complete() failed, error %d", ret);
911 DBG("NL80211_CMD_GET_SCAN sent %d bytes to the kernel", ret);
913 /** Receive the kernel message. */
914 ret = nl_recvmsgs_default(global->socket);
915 nlmsg_free(global->msg);
917 DBG("nl_recvmsgs_default() failed. ret: %d (error: %s)", ret, nl_geterror(-ret));
923 int handle_netlink_scan(Wifi *wifi, GDBusMethodInvocation *context,
924 const gchar *ifname, GVariant *params)
927 netconfig_nl_global global = {
934 /** Initialize netlink socket */
935 int ret = __netconfig_initialize_nl80211(&global, ifname);
937 DBG("__netconfig_initialize_nl80211() failed, error %d", ret);
938 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AccessDenied");
942 GSList *ssid_list = NULL;
944 __netconfig_get_netlink_scan_parameters(params, ssid_list, &vsie);
945 /** Request NL80211_CMD_TRIGGER_SCAN to the kernel. */
946 ret = __netconfig_netlink_scan(&global, ssid_list, vsie);
947 g_slist_free_full(ssid_list, g_free);
951 DBG("__netconfig_netlink_scan() failed, error %d", ret);
952 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AccessDenied");
953 __netconfig_deinitialize_nl80211(&global);
957 ret = __netconfig_get_scan_results(&global);
959 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AccessDenied");
960 __netconfig_deinitialize_nl80211(&global);
964 wifi_complete_netlink_scan(wifi, context);
965 __netconfig_notify_netlink_scan_done(ifname);
966 __netconfig_deinitialize_nl80211(&global);