DA: Fix netlink scan logic
[platform/core/connectivity/net-config.git] / src / wifi-netlink-scan.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
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
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  */
19
20 #include <glib.h>
21
22 #include "netsupplicant.h"
23 #include "log.h"
24 #include "util.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>
33 #include <ctype.h>
34
35 static GSList *bss_info_list = NULL;
36
37 static gint __netconfig_compare_bss_by_rssi(gconstpointer a, gconstpointer b)
38 {
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;
41
42         if (entry_a->signal > entry_b->signal)
43                 return -1;
44
45         if (entry_a->signal < entry_b->signal)
46                 return 1;
47
48         return 0;
49 }
50
51 void __netconfig_notify_netlink_scan_done(const char *interface_name)
52 {
53         GVariantBuilder *builder = NULL;
54         GVariantBuilder *builder1 = NULL;
55         GVariantBuilder *builder2 = NULL;
56         GSList* list = 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";
65
66         bss_info_list = g_slist_sort(bss_info_list, __netconfig_compare_bss_by_rssi);
67
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;
71
72                 if (bss_info) {
73                         char *bssid = (char *)bss_info->bssid;
74                         char *ssid = (char *)bss_info->ssid;
75                         GSList *vsie_list = bss_info->vsie_list;
76                         int freq = (int)bss_info->freq;
77                         int signal = (int)bss_info->signal;
78                         int sec_type = (int)bss_info->security_type;
79                         int enc_type = (int)bss_info->encryption_type;
80                         int pmf_required = (int)bss_info->pmf_required;
81
82                         g_variant_builder_add(builder, "{sv}", prop_ssid, g_variant_new_string(ssid));
83                         g_variant_builder_add(builder, "{sv}", prop_bssid, g_variant_new_string(bssid));
84                         g_variant_builder_add(builder, "{sv}", prop_freq, g_variant_new_int32(freq));
85                         g_variant_builder_add(builder, "{sv}", prop_rssi, g_variant_new_int32(signal));
86                         builder1 = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
87                         GSList *list;
88                         unsigned char *net_vsie;
89                         unsigned int net_vsie_len;
90                         int count;
91                         for (list = vsie_list; list; list = list->next) {
92                                 builder2 = g_variant_builder_new(G_VARIANT_TYPE("ay"));
93                                 net_vsie = (unsigned char *)list->data;
94                                 net_vsie_len = net_vsie[1] + 2;
95
96                                 for (count = 0; count < net_vsie_len; count++) {
97                                         g_variant_builder_add(builder2, "y", net_vsie[count]);
98                                 }
99
100                                 g_variant_builder_add(builder1, "{sv}", "Vsie", g_variant_builder_end(builder2));
101                                 g_variant_builder_unref(builder2);
102                         }
103                         g_variant_builder_add(builder, "{sv}", prop_vsie_list, g_variant_builder_end(builder1));
104                         g_variant_builder_unref(builder1);
105
106                         if (vsie_list != NULL)
107                                 g_slist_free_full(vsie_list, g_free);
108
109                         vsie_list = NULL;
110
111                         g_variant_builder_add(builder, "{sv}", prop_sec, g_variant_new_int32(sec_type));
112                         g_variant_builder_add(builder, "{sv}", prop_enc, g_variant_new_int32(enc_type));
113                         g_variant_builder_add(builder, "{sv}", prop_pmf, g_variant_new_int32(pmf_required));
114                 }
115         }
116
117         wifi_emit_netlink_scan_completed((Wifi *)get_wifi_object(),
118                 interface_name, g_variant_builder_end(builder));
119         g_variant_builder_unref(builder);
120
121         if (bss_info_list != NULL)
122                 g_slist_free_full(bss_info_list, g_free);
123
124         bss_info_list = NULL;
125         INFO("NetlinkScanCompleted");
126
127         return;
128 }
129
130 static int ack_handler(struct nl_msg *msg, void *user_data)
131 {
132         int *err = user_data;
133         *err = 0;
134         DBG("");
135         return NL_STOP;
136 }
137
138 static int finish_handler(struct nl_msg *msg, void *user_data)
139 {
140         int *ret = user_data;
141         *ret = 0;
142
143         DBG("");
144         return NL_SKIP;
145 }
146
147 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
148                          void *user_data)
149 {
150         int *ret = user_data;
151         *ret = err->error;
152
153         DBG("");
154         return NL_STOP;
155 }
156
157 static int no_seq_check(struct nl_msg *msg, void *user_data)
158 {
159         DBG("");
160         return NL_OK;
161 }
162
163 static int __netconfig_family_handler(struct nl_msg *msg, void *user_data)
164 {
165         /** Callback for NL_CB_VALID in multicast group */
166         struct netconfig_netlink_scan_handler_args *grp = user_data;
167         struct nlattr *tb[CTRL_ATTR_MAX + 1];
168         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
169         struct nlattr *mc_grp;
170         int rem_mc_grp;
171
172         nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
173
174         if (!tb[CTRL_ATTR_MCAST_GROUPS])
175                 return NL_SKIP;
176
177         nla_for_each_nested(mc_grp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mc_grp) {
178                 struct nlattr *tb_mc_grp[CTRL_ATTR_MCAST_GRP_MAX + 1];
179
180                 nla_parse(tb_mc_grp, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mc_grp), nla_len(mc_grp), NULL);
181
182                 if (!tb_mc_grp[CTRL_ATTR_MCAST_GRP_NAME] || !tb_mc_grp[CTRL_ATTR_MCAST_GRP_ID])
183                         continue;
184                 if (strncmp(nla_data(tb_mc_grp[CTRL_ATTR_MCAST_GRP_NAME]), grp->group,
185                                         nla_len(tb_mc_grp[CTRL_ATTR_MCAST_GRP_NAME])))
186                         continue;
187
188                 grp->id = nla_get_u32(tb_mc_grp[CTRL_ATTR_MCAST_GRP_ID]);
189                 break;
190         }
191
192         return NL_SKIP;
193 }
194
195 static int __netconfig_get_multicast_id(struct nl_sock *socket, const char *family, const char *group)
196 {
197         struct nl_msg *msg = NULL;
198         struct nl_cb *cb = NULL;
199         int ret, ctrl_id;
200         struct netconfig_netlink_scan_handler_args grp = { .group = group, .id = -ENOENT, };
201
202         msg = nlmsg_alloc();
203         if (!msg)
204                 return -ENOMEM;
205
206         cb = nl_cb_alloc(NL_CB_DEFAULT);
207         if (!cb) {
208                 ret = -ENOMEM;
209                 goto cb_fail;
210         }
211
212         ctrl_id = genl_ctrl_resolve(socket, "nlctrl");
213
214         genlmsg_put(msg, 0, 0, ctrl_id, 0, 0, CTRL_CMD_GETFAMILY, 0);
215
216         ret = -ENOBUFS;
217         NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
218
219         ret = nl_send_auto_complete(socket, msg);
220         if (ret < 0)
221                 goto out;
222
223         ret = 1;
224
225         nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &ret);
226         nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &ret);
227         nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, __netconfig_family_handler, &grp);
228
229         while (ret > 0)
230                 nl_recvmsgs(socket, cb);
231
232         if (ret == 0)
233                 ret = grp.id;
234
235 nla_put_failure:
236 out:
237         nl_cb_put(cb);
238 cb_fail:
239         nlmsg_free(msg);
240         return ret;
241 }
242
243 static void __netconfig_macaddress_str(char *bssid, unsigned char *user_data)
244 {
245         int i;
246
247         for (i = 0; i < 6; i++) {
248                 if (i == 0) {
249                         snprintf(bssid, 3, "%02x", user_data[i]);
250                         bssid += 2;
251                 } else {
252                         snprintf(bssid, 4, ":%02x", user_data[i]);
253                         bssid += 3;
254                 }
255         }
256 }
257
258 typedef enum {
259         WIFI_SECURITY_TYPE_NONE = 0,
260         WIFI_SECURITY_TYPE_WEP = 1,
261         WIFI_SECURITY_TYPE_WPA_PSK = 2,
262         WIFI_SECURITY_TYPE_WPA2_PSK = 3,
263         WIFI_SECURITY_TYPE_SAE = 4,
264         WIFI_SECURITY_TYPE_EAP = 5,
265 } wifi_security_type_e;
266
267 typedef enum {
268         WIFI_ENCRYPTION_TYPE_NONE = 0,
269         WIFI_ENCRYPTION_TYPE_WEP = 1,
270         WIFI_ENCRYPTION_TYPE_TKIP = 2,
271         WIFI_ENCRYPTION_TYPE_AES = 3,
272         WIFI_ENCRYPTION_TYPE_TKIP_AES_MIXED = 4,
273 } wifi_encryption_type_e;
274
275 static unsigned char ms_oui[3]      = { 0x00, 0x50, 0xf2 };
276 static unsigned char ieee80211_oui[3]   = { 0x00, 0x0f, 0xac };
277
278 static void __netconfig_get_security(unsigned char *bss_element, int length,
279                 wifi_security_type_e *sec_type, wifi_encryption_type_e *enc_type, int *pmf_required)
280 {
281         int i;
282         unsigned char *data;
283         uint8_t *t_data;
284         int len;
285         __u16 count;
286         gboolean ieee80211_psk = false;
287
288         *sec_type = WIFI_SECURITY_TYPE_NONE;
289         *enc_type = WIFI_ENCRYPTION_TYPE_NONE;
290
291         while (length >= 2 && length >= bss_element[1]) {
292                 if (bss_element[0] == 221 && (bss_element[1] >= 4 && memcmp(bss_element + 2, ms_oui, 3) == 0)) {
293                         data = bss_element + 2 + 4 + 2 + 4;
294                         len = bss_element[1] - 4 - 2 - 4;
295
296                         if (len < 2) {
297                                 length -= bss_element[1] + 2;
298                                 bss_element += bss_element[1] + 2;
299                                 continue;
300                         }
301
302                         count = data[0] | (data[1] << 8);
303
304                         if (2 + (count * 4) > len) {
305                                 length -= bss_element[1] + 2;
306                                 bss_element += bss_element[1] + 2;
307                                 continue;
308                         }
309
310                         for (i = 0; i < count; i++) {
311                                 t_data = (data + 2 + (i * 4));
312
313                                 if ((memcmp(t_data, ms_oui, 3) == 0) || (memcmp(t_data, ieee80211_oui, 3) == 0)) {
314                                         if (t_data[3] == 1 || t_data[3] == 5) { // 1 : WEP-40, 5 : WEP-104
315                                                 *sec_type = WIFI_SECURITY_TYPE_WEP;
316                                                 *enc_type = WIFI_ENCRYPTION_TYPE_WEP;
317                                                 return;
318                                         } else if (t_data[3] == 2) { // 2 : TKIP
319                                                 if (*sec_type != WIFI_SECURITY_TYPE_WPA2_PSK)
320                                                         *sec_type = WIFI_SECURITY_TYPE_WPA_PSK;
321                                                 if (*enc_type == WIFI_ENCRYPTION_TYPE_AES)
322                                                         *enc_type = WIFI_ENCRYPTION_TYPE_TKIP_AES_MIXED;
323                                                 else
324                                                         *enc_type = WIFI_ENCRYPTION_TYPE_TKIP;
325                                         } else if (t_data[3] == 4) { // 3 : CCMP
326                                                 if (*sec_type != WIFI_SECURITY_TYPE_WPA2_PSK)
327                                                         *sec_type = WIFI_SECURITY_TYPE_WPA_PSK;
328                                                 if (*enc_type == WIFI_ENCRYPTION_TYPE_TKIP)
329                                                         *enc_type = WIFI_ENCRYPTION_TYPE_TKIP_AES_MIXED;
330                                                 else
331                                                         *enc_type = WIFI_ENCRYPTION_TYPE_AES;
332                                         }
333                                 } //if
334                         } //for
335
336                         data += 2 + (count * 4);
337                         len -= 2 + (count * 4);
338
339                         if (len < 2) {
340                                 length -= bss_element[1] + 2;
341                                 bss_element += bss_element[1] + 2;
342                                 continue;
343                         }
344
345                         count = data[0] | (data[1] << 8);
346
347                         if (2 + (count * 4) > len) {
348                                 length -= bss_element[1] + 2;
349                                 bss_element += bss_element[1] + 2;
350                                 continue;
351                         }
352
353                         for (i = 0; i < count; i++) {
354                                 t_data = (data + 2 + (i * 4));
355
356                                 if ((memcmp(t_data, ms_oui, 3) == 0) || (memcmp(t_data, ieee80211_oui, 3) == 0)) {
357                                         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
358                                                 *sec_type = WIFI_SECURITY_TYPE_EAP;
359                                         } else if (t_data[3] == 2 || t_data[3] == 4 || t_data[3] == 6) {  // 2 : PSK, 4 : FT/PSK, 6 : PSK/SHA-256
360                                                 if (t_data[3] == 6)
361                                                         *pmf_required = 1;
362                                                 if (*sec_type != WIFI_SECURITY_TYPE_WPA2_PSK)
363                                                         *sec_type = WIFI_SECURITY_TYPE_WPA_PSK;
364                                         }
365                                 }
366                         }
367                 } else if (bss_element[0] == 48 && (bss_element[1] >= 2 && bss_element[1] <= 255)) {
368                         data = bss_element + 2 + 2 + 4;
369                         len = bss_element[1] - 2 - 4;
370
371                         if (len < 2) {
372                                 length -= bss_element[1] + 2;
373                                 bss_element += bss_element[1] + 2;
374                                 continue;
375                         }
376
377                         count = data[0] | (data[1] << 8);
378                         if (2 + (count + 4) > len) {
379                                 length -= bss_element[1] + 2;
380                                 bss_element += bss_element[1] + 2;
381                                 continue;
382                         }
383
384                         for (i = 0; i < count; i++) {
385                                 t_data = (data + 2 + (i * 4));
386
387                                 if ((memcmp(t_data, ms_oui, 3) == 0) || (memcmp(t_data, ieee80211_oui, 3) == 0)) {
388                                         if (t_data[3] == 1 || t_data[3] == 5) { // 1 : WEP-40, 5 : WEP-104
389                                                 *sec_type = WIFI_SECURITY_TYPE_WEP;
390                                                 *enc_type = WIFI_ENCRYPTION_TYPE_WEP;
391                                                 return;
392                                         } else if (t_data[3] == 2) { // 2 : TKIP
393                                                 *sec_type = WIFI_SECURITY_TYPE_WPA2_PSK;
394                                                 if (*enc_type == WIFI_ENCRYPTION_TYPE_AES)
395                                                         *enc_type = WIFI_ENCRYPTION_TYPE_TKIP_AES_MIXED;
396                                                 else
397                                                         *enc_type = WIFI_ENCRYPTION_TYPE_TKIP;
398                                         } else if (t_data[3] == 4) { // 3 : CCMP
399                                                 *sec_type = WIFI_SECURITY_TYPE_WPA2_PSK;
400                                                 if (*enc_type == WIFI_ENCRYPTION_TYPE_TKIP)
401                                                         *enc_type = WIFI_ENCRYPTION_TYPE_TKIP_AES_MIXED;
402                                                 else
403                                                         *enc_type = WIFI_ENCRYPTION_TYPE_AES;
404                                         }
405                                 }
406                         }
407
408                         data += 2 + (count * 4);
409                         len -= 2 + (count * 4);
410
411                         if (len < 2) {
412                                 length -= bss_element[1] + 2;
413                                 bss_element += bss_element[1] + 2;
414                                 continue;
415                         }
416
417                         count = data[0] | (data[1] << 8);
418                         if (2 + (count * 4) > len) {
419                                 length -= bss_element[1] + 2;
420                                 bss_element += bss_element[1] + 2;
421                                 continue;
422                         }
423
424                         for (i = 0; i < count; i++) {
425                                 t_data = (data + 2 + (i * 4));
426
427                                 if ((memcmp(t_data, ms_oui, 3) == 0) || (memcmp(t_data, ieee80211_oui, 3) == 0)) {
428                                         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
429                                                 *sec_type = WIFI_SECURITY_TYPE_EAP;
430                                         } else if (t_data[3] == 2 || t_data[3] == 4 || t_data[3] == 6) {  // 2 : PSK, 4 : FT/PSK, 6 : PSK/SHA-256
431                                                 if (t_data[3] == 6)
432                                                         *pmf_required = 1;
433                                                 *sec_type = WIFI_SECURITY_TYPE_WPA2_PSK;
434                                                 ieee80211_psk = true;
435                                         } else if (t_data[3] == 8) { // Add SAE security type for netlink scan
436                                                 if (ieee80211_psk != true)
437                                                         *sec_type = WIFI_SECURITY_TYPE_SAE;
438                                         }
439                                 }
440                         } //for
441                 } //else if
442
443                 length -= bss_element[1] + 2;
444                 bss_element += bss_element[1] + 2;
445         } //while
446
447         return;
448 }
449
450 static void __netconfig_get_vsie(unsigned char *bss_element, int length, GSList **dst)
451 {
452         unsigned char *vsie;
453         int vsie_len = 0;
454
455         if (length < 3) {
456                 DBG("Vendor specific data not available");
457                 return;
458         }
459
460         while (length >= 2 && length >= bss_element[1]) {
461                 if (bss_element[0] == NETCONFIG_VENDOR_SPECIFIC_ID) {
462                         vsie_len = bss_element[1]+2;
463                         vsie = (unsigned char *)g_try_malloc0(vsie_len);
464
465                         if (vsie) {
466                                 memcpy(vsie, bss_element, vsie_len);
467                                 *dst = g_slist_append(*dst, vsie);
468                         } else
469                                 DBG("Failed to allocate memory");
470                 }
471
472                 length -= bss_element[1] + 2;
473                 bss_element += bss_element[1] + 2;
474         }
475 }
476
477 static void __netconfig_found_ap(unsigned char *bss_element, int length, char *str)
478 {
479         uint8_t len;
480         uint8_t *data;
481         int i;
482
483         while (length >= 2 && length >= bss_element[1]) {
484                 if (bss_element[0] == 0 && bss_element[1] <= 32) {
485                         len = bss_element[1];
486                         data = bss_element + 2;
487                         for (i = 0; i < len; i++) {
488                                 if (isprint(data[i]) && data[i] != ' ' && data[i] != '\\')
489                                         snprintf(&str[i], 2, "%c", data[i]);
490                                 else if (data[i] == ' ' && (i != 0 && i != len -1))
491                                         snprintf(&str[i], 2, "%c", ' ');
492                                 else
493                                         snprintf(&str[i], 2, "%c", data[i]);
494                         }
495                         break;
496                 }
497                 length -= bss_element[1] + 2;
498                 bss_element += bss_element[1] + 2;
499         }
500 }
501
502 static int __netconfig_netlink_scan_cb(struct nl_msg *msg, void *user_data)
503 {
504         /** Called by the kernel with a dump of the successful scan's data. Called for each SSID. */
505         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
506         char bssid[NETCONFIG_BSSID_LEN+1];
507         char ssid[NETCONFIG_SSID_LEN+1] = {0, };
508         wifi_security_type_e sec_type = WIFI_SECURITY_TYPE_NONE;
509         wifi_encryption_type_e enc_type = WIFI_ENCRYPTION_TYPE_NONE;
510         int wep_check = 0;
511         GSList *vsie = NULL;
512         struct nlattr *tb[NL80211_ATTR_MAX + 1];
513         struct nlattr *bss[NL80211_BSS_MAX + 1];
514         struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
515                 [NL80211_BSS_FREQUENCY] = {.type = NLA_U32},
516                 [NL80211_BSS_BSSID] = { },
517                 [NL80211_BSS_CAPABILITY] = {.type = NLA_U16},
518                 [NL80211_BSS_INFORMATION_ELEMENTS] = { },
519                 [NL80211_BSS_SIGNAL_MBM] = {.type = NLA_U32},
520         };
521
522         int pmf_needed = 0;
523
524         /** Parse nl message and check error. */
525         nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
526         if (!tb[NL80211_ATTR_BSS]) {
527                 DBG("BSS info not available");
528                 return NL_SKIP;
529         }
530         if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], bss_policy)) {
531                 DBG("Failed to parse nested attributes");
532                 return NL_SKIP;
533         }
534         if ((!bss[NL80211_BSS_BSSID]) || (!bss[NL80211_BSS_INFORMATION_ELEMENTS]))
535                 return NL_SKIP;
536
537         /** Extract BSSID and AP info. */
538         __netconfig_macaddress_str(bssid, nla_data(bss[NL80211_BSS_BSSID]));
539         __netconfig_found_ap(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]), nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]), ssid);
540         __netconfig_get_vsie(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]), nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]), &vsie);
541
542         if (bss[NL80211_BSS_CAPABILITY]) {
543                 __u16 capa = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
544                 if (capa & WLAN_CAPABILITY_PRIVACY) {
545                         wep_check = 1;
546                 }
547         }
548         __netconfig_get_security(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
549                         nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]), &sec_type, &enc_type, &pmf_needed);
550
551         if (wep_check && sec_type == WIFI_SECURITY_TYPE_NONE) {
552                 sec_type = WIFI_SECURITY_TYPE_WEP;
553                 enc_type = WIFI_ENCRYPTION_TYPE_WEP;
554         }
555
556         if (sec_type == WIFI_SECURITY_TYPE_EAP) {
557                 g_slist_free_full(vsie, g_free);
558                 return NL_SKIP;
559         }
560         for (GSList *list = bss_info_list; list != NULL; list = list->next) {
561                 struct bss_scan_info_t *bss_info = (struct bss_scan_info_t *)list->data;
562                 if ((g_strcmp0(bss_info->ssid, ssid) == 0) && (bss_info->security_type == sec_type)
563                                 && (bss_info->encryption_type == enc_type)) {
564                         g_slist_free_full(vsie, g_free);
565                         return NL_SKIP;
566                 }
567         }
568
569         /** Create AP info list. */
570         if (ssid[0] != '\0') {
571                 struct bss_scan_info_t *bss_info;
572                 int signal;
573
574                 bss_info = g_try_new0(struct bss_scan_info_t, 1);
575                 if (bss_info == NULL) {
576                         g_slist_free_full(vsie, g_free);
577                         return NL_SKIP;
578                 }
579
580                 g_strlcpy(bss_info->bssid, bssid, strlen(bssid)+1);
581                 g_strlcpy(bss_info->ssid, ssid, strlen(ssid)+1);
582                 bss_info->vsie_list = vsie;
583                 bss_info->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
584
585                 if (bss[NL80211_BSS_SIGNAL_MBM]) {
586                         signal = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
587                         signal /= 100; /** mBm to dBm */
588                         bss_info->signal = signal;
589                 }
590
591                 bss_info->security_type = sec_type;
592                 bss_info->encryption_type = enc_type;
593                 bss_info->pmf_required = pmf_needed;
594                 SECURE_LOGD("%s %d %d %s %d %d %d ", bss_info->bssid, bss_info->freq,
595                                 bss_info->signal, bss_info->ssid, bss_info->security_type,
596                                 bss_info->encryption_type, bss_info->pmf_required);
597
598                 if (bss_info->ssid[0] == '\0')
599                         g_free(bss_info);
600                 else
601                         bss_info_list = g_slist_append(bss_info_list, bss_info);
602
603         } else
604                 g_slist_free_full(vsie, g_free);
605
606         return NL_SKIP;
607 }
608
609 static int __netconfig_netlink_scan_reply(struct nl_msg *msg, void *user_data)
610 {
611         /** Called by the kernel when the scan is done or has been aborted. */
612         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
613         struct netconfig_netlink_scan_results *results = user_data;
614
615         if (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS) {
616                 DBG("Received NL80211_CMD_NEW_SCAN_RESULTS in reply");
617                 results->done = 1;
618                 results->aborted = 0;
619         } else if (gnlh->cmd == NL80211_CMD_SCAN_ABORTED) {
620                 DBG("Received NL80211_CMD_SCAN_ABORTED in reply");
621                 results->done = 1;
622                 results->aborted = 1;
623         }
624
625         return NL_SKIP;
626 }
627
628 static int __netconfig_trigger_netlink_scan(struct nl_sock *socket,
629                 int if_index, int id, GSList *ssid_list, char *vsie)
630 {
631         struct netconfig_netlink_scan_results results = { .done = 0, .aborted = 0 };
632         struct nl_msg *msg = NULL;
633         struct nl_cb *cb = NULL;
634         struct nl_msg *ssids = NULL;
635         int err = 0;
636         int ret = 0;
637         unsigned char ies[NETCONFIG_MAX_VSIE_LEN+1] = {0x00, };
638         int ies_len = 0;
639         int mcid = __netconfig_get_multicast_id(socket, "nl80211", "scan");
640
641         DBG("");
642         ret = nl_socket_add_membership(socket, mcid);
643         if (ret < 0) {
644                 DBG("Failed to add membership, error: (%s)", nl_geterror(-ret));
645                 return ret;
646         }
647
648         msg = nlmsg_alloc();
649         if (!msg) {
650                 DBG("Failed to allocate msg");
651                 nl_socket_drop_membership(socket, mcid);
652                 return -ENOMEM;
653         }
654         ssids = nlmsg_alloc();
655         if (!ssids) {
656                 DBG("Failed to allocate ssids");
657                 nlmsg_free(msg);
658                 nl_socket_drop_membership(socket, mcid);
659                 return -ENOMEM;
660         }
661         cb = nl_cb_alloc(NL_CB_DEFAULT);
662         if (!cb) {
663                 DBG("Failed to allocate callbacks");
664                 nlmsg_free(msg);
665                 nlmsg_free(ssids);
666                 nl_socket_drop_membership(socket, mcid);
667                 return -ENOMEM;
668         }
669
670         /** Set nl message and callback functions. */
671         genlmsg_put(msg, 0, 0, id, 0, 0, NL80211_CMD_TRIGGER_SCAN, 0);
672         ret = nla_put_u32(msg, NL80211_ATTR_IFINDEX, if_index);
673         if (ret < 0) {
674                 DBG("Failed to add integer attribute to netlink message, error: (%s)", nl_geterror(-ret));
675                 goto out;
676         }
677
678         for (GSList *i = ssid_list; i; i = i->next) {
679                 char *ssid = (char *)i->data;
680                 ret = nla_put(ssids, 1, strlen(ssid), ssid);
681                 if (ret < 0) {
682                         DBG("Failed to add ssid to netlink message, error: (%s)", nl_geterror(-ret));
683                         goto out;
684                 }
685         }
686
687         if (g_slist_length(ssid_list) == 0) {
688                 DBG("Scan with no ssids");
689                 ret = nla_put(ssids, 1, 0, "");
690                 if (ret < 0) {
691                         DBG("nla_put error: (%s)", nl_geterror(-ret));
692                         goto out;
693                 }
694         }
695         nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
696
697         if (vsie) {
698                 int vsie_len = strlen(vsie);
699                 DBG("vsie: %s vsie_len: %d", vsie, vsie_len);
700                 ies_len = (vsie_len % 2) ? ((vsie_len / 2) + 1) : (vsie_len / 2);
701                 __netconfig_hex_str_to_bin(vsie, ies, ies_len);
702         }
703
704         if (ies[0] == NETCONFIG_VENDOR_SPECIFIC_ID && ies[1] >= 4) {
705                 DBG("ies_len: %d ies: %02x %02x %02x %02x %02x %02x %02x", ies_len,
706                                 ies[0], ies[1], ies[2], ies[3], ies[4], ies[5], ies[6]);
707                 ret = nla_put(msg, NL80211_ATTR_IE, ies_len, ies);
708                 if (ret < 0) {
709                         DBG("Failed to add vsie data to netlink message, error: (%s)", nl_geterror(-ret));
710                         goto out;
711                 }
712         }
713
714         err = 1;
715         nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, __netconfig_netlink_scan_reply, &results);
716         nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
717         nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
718         nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
719         nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
720         ret = nl_socket_set_nonblocking(socket);
721         DBG("Set the non-blocking mode [%d]", ret);
722
723         /** Send NL80211_CMD_TRIGGER_SCAN to start the scan. */
724         ret = nl_send_auto_complete(socket, msg);
725
726         if (ret < 0) {
727                 DBG("nl_send_auto_complete() error: (%s)", nl_geterror(-ret));
728                 goto out;
729         }
730
731         DBG("Sent %d bytes to the kernel", ret);
732
733         while (err > 0) {
734                 ret = nl_recvmsgs(socket, cb);
735                 if (ret < 0) {
736                         DBG("nl_recvmsgs() ret: %d (%s)", ret, nl_geterror(-ret));
737                         goto out;
738                 }
739         }
740
741         if (err < 0) {
742                 DBG("error code = %d", err);
743                 ret = -1;
744                 goto out;
745         }
746
747         while (!results.done) {
748                 ret = nl_recvmsgs(socket, cb);
749 #if !defined TIZEN_WEARABLE
750                 if (ret == -NLE_AGAIN && err >= 0)
751                         continue;
752 #endif
753                 if (ret < 0) {
754                         DBG("scan failed");
755                         goto out;
756                 }
757                 if (err < 0) {
758                         DBG("scan failed err: %d", err);
759                         ret = -1;
760                         goto out;
761                 }
762         }
763
764         if (results.aborted) {
765                 DBG("scan aborted");
766                 ret = -1;
767                 goto out;
768         }
769
770 out:
771         /** Release memory */
772         nlmsg_free(ssids);
773         nlmsg_free(msg);
774         nl_cb_put(cb);
775         nl_socket_drop_membership(socket, mcid);
776
777         if (ret < 0 || ret == 1)
778                 return ret;
779
780         DBG("Scan done");
781         return 0;
782 }
783
784 static int __netconfig_netlink_scan(netconfig_nl_global *global, GSList *ssid_list, char *vsie)
785 {
786         DBG("");
787         int ret = __netconfig_trigger_netlink_scan(global->socket, global->if_index, global->id, ssid_list, vsie);
788         if (ret == -NLE_AGAIN) {
789                 DBG("Try Again");
790                 ret = __netconfig_trigger_netlink_scan(global->socket, global->if_index, global->id, ssid_list, vsie);
791         }
792         return ret;
793 }
794
795 static int __netconfig_initialize_nl80211(netconfig_nl_global *global,
796                 const char *interface_name)
797 {
798         int err = 0;
799
800         global->if_index = __netconfig_get_interface_index(interface_name);
801         if (global->if_index < 0) {
802                 DBG("Failed to get interface index");
803                 return -1;
804         }
805
806         global->socket = nl_socket_alloc();
807         if (!global->socket) {
808                 DBG("Failed to allocate netlink socket.");
809                 return -ENOMEM;
810         }
811
812         if (genl_connect(global->socket)) {
813                 DBG("Failed to connect to generic netlink.");
814                 err = -ENOLINK;
815                 goto fail;
816         }
817
818         global->id = genl_ctrl_resolve(global->socket, "nl80211");
819         if (global->id < 0) {
820                 DBG("Failed to find the nl80211 driver");
821                 err = -ENOENT;
822                 goto fail;
823         }
824
825         return 0;
826
827 fail:
828         nl_socket_free(global->socket);
829         return err;
830 }
831
832 static void __netconfig_deinitialize_nl80211(netconfig_nl_global *global)
833 {
834         if (global == NULL)
835                 return;
836
837         if (global->socket) {
838                 nl_socket_free(global->socket);
839                 global->socket = NULL;
840         }
841 }
842
843 static int __netconfig_initialize_nl_msg(netconfig_nl_global *global)
844 {
845         int rv;
846
847         if (global == NULL) {
848                 DBG("Invalid parameter.");
849                 return -EINVAL;
850         }
851
852         global->msg = nlmsg_alloc();
853         if (global->msg == NULL) {
854                 DBG("Failed to allocate netlink message");
855                 return -ENOMEM;
856         }
857
858         /* Set command into message */
859         genlmsg_put(global->msg, 0, 0, global->id, 0, NLM_F_DUMP, NL80211_CMD_GET_SCAN, 0);
860         rv = nla_put_u32(global->msg, NL80211_ATTR_IFINDEX, global->if_index);
861         if (rv < 0) {
862                 DBG("Failed to add integer attribute to netlink message.");
863                 nlmsg_free(global->msg);
864                 return rv;
865         }
866         nl_socket_modify_cb(global->socket, NL_CB_VALID, NL_CB_CUSTOM, __netconfig_netlink_scan_cb, NULL);
867
868         return 0;
869 }
870
871 static void __netconfig_get_netlink_scan_parameters(GVariant *params, GSList *ssid_list, char **vsie)
872 {
873         GVariantIter *iter;
874         GVariant *value;
875         gchar *key;
876         g_variant_get(params, "a{sv}", &iter);
877         while (g_variant_iter_loop(iter, "{sv}", &key, &value)) {
878                 if (g_strcmp0(key, "SSID") == 0) {
879                         if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
880                                 char *ssid = g_strdup(g_variant_get_string(value, NULL));
881                                 DBG("ssid [%s]", ssid);
882                                 ssid_list = g_slist_append(ssid_list, ssid);
883                         }
884                 } else if (g_strcmp0(key, "VSIE") == 0) {
885                         if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING))
886                                 *vsie = g_strdup(g_variant_get_string(value, NULL));
887                 }
888         }
889         g_variant_iter_free(iter);
890 }
891
892 static int __netconfig_get_scan_results(netconfig_nl_global *global)
893 {
894         int ret = __netconfig_initialize_nl_msg(global);
895         if (ret < 0) {
896                 DBG("__netconfig_initialize_nl_msg() failed, error %d", ret);
897                 return ret;
898         }
899
900         ret = nl_send_auto_complete(global->socket, global->msg);
901         if (ret < 0) {
902                 DBG("nl_send_auto_complete() failed, error %d", ret);
903                 return ret;
904         }
905         DBG("NL80211_CMD_GET_SCAN sent %d bytes to the kernel", ret);
906
907         /** Receive the kernel message. */
908         ret = nl_recvmsgs_default(global->socket);
909         nlmsg_free(global->msg);
910         if (ret < 0) {
911                 DBG("nl_recvmsgs_default() failed. ret: %d (error: %s)", ret, nl_geterror(-ret));
912                 return ret;
913         }
914         return 0;
915 }
916
917 int handle_netlink_scan(Wifi *wifi, GDBusMethodInvocation *context,
918                 const gchar *ifname, GVariant *params)
919 {
920         DBG("");
921         netconfig_nl_global global = {
922                 .id = -1,
923                 .if_index = -1,
924                 .socket = NULL,
925                 .msg = NULL,
926         };
927
928         /** Initialize netlink socket */
929         int ret = __netconfig_initialize_nl80211(&global, ifname);
930         if (ret < 0) {
931                 DBG("__netconfig_initialize_nl80211() failed, error %d", ret);
932                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AccessDenied");
933                 return TRUE;
934         }
935
936         GSList *ssid_list = NULL;
937         char *vsie = NULL;
938         __netconfig_get_netlink_scan_parameters(params, ssid_list, &vsie);
939         /** Request NL80211_CMD_TRIGGER_SCAN to the kernel. */
940         ret = __netconfig_netlink_scan(&global, ssid_list, vsie);
941         g_slist_free_full(ssid_list, g_free);
942         g_free(vsie);
943
944         if (ret < 0) {
945                 DBG("__netconfig_netlink_scan() failed, error %d", ret);
946                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AccessDenied");
947                 __netconfig_deinitialize_nl80211(&global);
948                 return TRUE;
949         }
950
951         ret = __netconfig_get_scan_results(&global);
952         if (ret < 0) {
953                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AccessDenied");
954                 __netconfig_deinitialize_nl80211(&global);
955                 return TRUE;
956         }
957
958         wifi_complete_netlink_scan(wifi, context);
959         __netconfig_notify_netlink_scan_done(ifname);
960         __netconfig_deinitialize_nl80211(&global);
961
962         return TRUE;
963 }