Merge "Add dbus method for getting wifi passphrase" into tizen
[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                         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;
82
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);
88
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}"));
93                         GSList *list;
94                         unsigned char *net_vsie;
95                         unsigned int net_vsie_len;
96                         int count;
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;
101
102                                 for (count = 0; count < net_vsie_len; count++) {
103                                         g_variant_builder_add(builder2, "y", net_vsie[count]);
104                                 }
105
106                                 g_variant_builder_add(builder1, "{sv}", "Vsie", g_variant_builder_end(builder2));
107                                 g_variant_builder_unref(builder2);
108                         }
109                         g_variant_builder_add(builder, "{sv}", prop_vsie_list, g_variant_builder_end(builder1));
110                         g_variant_builder_unref(builder1);
111
112                         if (vsie_list != NULL)
113                                 g_slist_free_full(vsie_list, g_free);
114
115                         vsie_list = NULL;
116
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));
120                 }
121         }
122
123         wifi_emit_netlink_scan_completed((Wifi *)get_wifi_object(),
124                 interface_name, g_variant_builder_end(builder));
125         g_variant_builder_unref(builder);
126
127         if (bss_info_list != NULL)
128                 g_slist_free_full(bss_info_list, g_free);
129
130         bss_info_list = NULL;
131         INFO("NetlinkScanCompleted");
132
133         return;
134 }
135
136 static int ack_handler(struct nl_msg *msg, void *user_data)
137 {
138         int *err = user_data;
139         *err = 0;
140         DBG("");
141         return NL_STOP;
142 }
143
144 static int finish_handler(struct nl_msg *msg, void *user_data)
145 {
146         int *ret = user_data;
147         *ret = 0;
148
149         DBG("");
150         return NL_SKIP;
151 }
152
153 static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
154                          void *user_data)
155 {
156         int *ret = user_data;
157         *ret = err->error;
158
159         DBG("");
160         return NL_STOP;
161 }
162
163 static int no_seq_check(struct nl_msg *msg, void *user_data)
164 {
165         DBG("");
166         return NL_OK;
167 }
168
169 static int __netconfig_family_handler(struct nl_msg *msg, void *user_data)
170 {
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;
176         int rem_mc_grp;
177
178         nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
179
180         if (!tb[CTRL_ATTR_MCAST_GROUPS])
181                 return NL_SKIP;
182
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];
185
186                 nla_parse(tb_mc_grp, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mc_grp), nla_len(mc_grp), NULL);
187
188                 if (!tb_mc_grp[CTRL_ATTR_MCAST_GRP_NAME] || !tb_mc_grp[CTRL_ATTR_MCAST_GRP_ID])
189                         continue;
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])))
192                         continue;
193
194                 grp->id = nla_get_u32(tb_mc_grp[CTRL_ATTR_MCAST_GRP_ID]);
195                 break;
196         }
197
198         return NL_SKIP;
199 }
200
201 static int __netconfig_get_multicast_id(struct nl_sock *socket, const char *family, const char *group)
202 {
203         struct nl_msg *msg = NULL;
204         struct nl_cb *cb = NULL;
205         int ret, ctrl_id;
206         struct netconfig_netlink_scan_handler_args grp = { .group = group, .id = -ENOENT, };
207
208         msg = nlmsg_alloc();
209         if (!msg)
210                 return -ENOMEM;
211
212         cb = nl_cb_alloc(NL_CB_DEFAULT);
213         if (!cb) {
214                 ret = -ENOMEM;
215                 goto cb_fail;
216         }
217
218         ctrl_id = genl_ctrl_resolve(socket, "nlctrl");
219
220         genlmsg_put(msg, 0, 0, ctrl_id, 0, 0, CTRL_CMD_GETFAMILY, 0);
221
222         ret = -ENOBUFS;
223         NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
224
225         ret = nl_send_auto_complete(socket, msg);
226         if (ret < 0)
227                 goto out;
228
229         ret = 1;
230
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);
234
235         while (ret > 0)
236                 nl_recvmsgs(socket, cb);
237
238         if (ret == 0)
239                 ret = grp.id;
240
241 nla_put_failure:
242 out:
243         nl_cb_put(cb);
244 cb_fail:
245         nlmsg_free(msg);
246         return ret;
247 }
248
249 static void __netconfig_macaddress_str(char *bssid, unsigned char *user_data)
250 {
251         int i;
252
253         for (i = 0; i < 6; i++) {
254                 if (i == 0) {
255                         snprintf(bssid, 3, "%02x", user_data[i]);
256                         bssid += 2;
257                 } else {
258                         snprintf(bssid, 4, ":%02x", user_data[i]);
259                         bssid += 3;
260                 }
261         }
262 }
263
264 typedef enum {
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;
272
273 typedef enum {
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;
280
281 static unsigned char ms_oui[3]      = { 0x00, 0x50, 0xf2 };
282 static unsigned char ieee80211_oui[3]   = { 0x00, 0x0f, 0xac };
283
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)
286 {
287         int i;
288         unsigned char *data;
289         uint8_t *t_data;
290         int len;
291         __u16 count;
292         gboolean ieee80211_psk = false;
293
294         *sec_type = WIFI_SECURITY_TYPE_NONE;
295         *enc_type = WIFI_ENCRYPTION_TYPE_NONE;
296
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;
301
302                         if (len < 2) {
303                                 length -= bss_element[1] + 2;
304                                 bss_element += bss_element[1] + 2;
305                                 continue;
306                         }
307
308                         count = data[0] | (data[1] << 8);
309
310                         if (2 + (count * 4) > len) {
311                                 length -= bss_element[1] + 2;
312                                 bss_element += bss_element[1] + 2;
313                                 continue;
314                         }
315
316                         for (i = 0; i < count; i++) {
317                                 t_data = (data + 2 + (i * 4));
318
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;
323                                                 return;
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;
329                                                 else
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;
336                                                 else
337                                                         *enc_type = WIFI_ENCRYPTION_TYPE_AES;
338                                         }
339                                 } //if
340                         } //for
341
342                         data += 2 + (count * 4);
343                         len -= 2 + (count * 4);
344
345                         if (len < 2) {
346                                 length -= bss_element[1] + 2;
347                                 bss_element += bss_element[1] + 2;
348                                 continue;
349                         }
350
351                         count = data[0] | (data[1] << 8);
352
353                         if (2 + (count * 4) > len) {
354                                 length -= bss_element[1] + 2;
355                                 bss_element += bss_element[1] + 2;
356                                 continue;
357                         }
358
359                         for (i = 0; i < count; i++) {
360                                 t_data = (data + 2 + (i * 4));
361
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
366                                                 if (t_data[3] == 6)
367                                                         *pmf_required = 1;
368                                                 if (*sec_type != WIFI_SECURITY_TYPE_WPA2_PSK)
369                                                         *sec_type = WIFI_SECURITY_TYPE_WPA_PSK;
370                                         }
371                                 }
372                         }
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;
376
377                         if (len < 2) {
378                                 length -= bss_element[1] + 2;
379                                 bss_element += bss_element[1] + 2;
380                                 continue;
381                         }
382
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;
387                                 continue;
388                         }
389
390                         for (i = 0; i < count; i++) {
391                                 t_data = (data + 2 + (i * 4));
392
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;
397                                                 return;
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;
402                                                 else
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;
408                                                 else
409                                                         *enc_type = WIFI_ENCRYPTION_TYPE_AES;
410                                         }
411                                 }
412                         }
413
414                         data += 2 + (count * 4);
415                         len -= 2 + (count * 4);
416
417                         if (len < 2) {
418                                 length -= bss_element[1] + 2;
419                                 bss_element += bss_element[1] + 2;
420                                 continue;
421                         }
422
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;
427                                 continue;
428                         }
429
430                         for (i = 0; i < count; i++) {
431                                 t_data = (data + 2 + (i * 4));
432
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
437                                                 if (t_data[3] == 6)
438                                                         *pmf_required = 1;
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;
444                                         }
445                                 }
446                         } //for
447                 } //else if
448
449                 length -= bss_element[1] + 2;
450                 bss_element += bss_element[1] + 2;
451         } //while
452
453         return;
454 }
455
456 static void __netconfig_get_vsie(unsigned char *bss_element, int length, GSList **dst)
457 {
458         unsigned char *vsie;
459         int vsie_len = 0;
460
461         if (length < 3) {
462                 DBG("Vendor specific data not available");
463                 return;
464         }
465
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);
470
471                         if (vsie) {
472                                 memcpy(vsie, bss_element, vsie_len);
473                                 *dst = g_slist_append(*dst, vsie);
474                         } else
475                                 DBG("Failed to allocate memory");
476                 }
477
478                 length -= bss_element[1] + 2;
479                 bss_element += bss_element[1] + 2;
480         }
481 }
482
483 static void __netconfig_found_ap(unsigned char *bss_element, int length, char *str, int *ssid_len)
484 {
485         uint8_t len;
486         uint8_t *data;
487         int i;
488
489         *ssid_len = 0;
490
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);
497                                 (*ssid_len)++;
498                         }
499                         break;
500                 }
501                 length -= bss_element[1] + 2;
502                 bss_element += bss_element[1] + 2;
503         }
504 }
505
506 static int __netconfig_netlink_scan_cb(struct nl_msg *msg, void *user_data)
507 {
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, };
512         int ssid_len;
513         wifi_security_type_e sec_type = WIFI_SECURITY_TYPE_NONE;
514         wifi_encryption_type_e enc_type = WIFI_ENCRYPTION_TYPE_NONE;
515         int wep_check = 0;
516         GSList *vsie = NULL;
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},
525         };
526
527         int pmf_needed = 0;
528
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");
533                 return NL_SKIP;
534         }
535         if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], bss_policy)) {
536                 DBG("Failed to parse nested attributes");
537                 return NL_SKIP;
538         }
539         if ((!bss[NL80211_BSS_BSSID]) || (!bss[NL80211_BSS_INFORMATION_ELEMENTS]))
540                 return NL_SKIP;
541
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);
546
547         if (bss[NL80211_BSS_CAPABILITY]) {
548                 __u16 capa = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
549                 if (capa & WLAN_CAPABILITY_PRIVACY) {
550                         wep_check = 1;
551                 }
552         }
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);
555
556         if (wep_check && sec_type == WIFI_SECURITY_TYPE_NONE) {
557                 sec_type = WIFI_SECURITY_TYPE_WEP;
558                 enc_type = WIFI_ENCRYPTION_TYPE_WEP;
559         }
560
561         if (sec_type == WIFI_SECURITY_TYPE_EAP) {
562                 g_slist_free_full(vsie, g_free);
563                 return NL_SKIP;
564         }
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);
570                         return NL_SKIP;
571                 }
572         }
573
574         /** Create AP info list. */
575         if (ssid[0] != '\0') {
576                 struct bss_scan_info_t *bss_info;
577                 int signal;
578
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);
582                         return NL_SKIP;
583                 }
584
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]);
590
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;
595                 }
596
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);
603
604                 if (bss_info->ssid[0] == '\0')
605                         g_free(bss_info);
606                 else
607                         bss_info_list = g_slist_append(bss_info_list, bss_info);
608
609         } else
610                 g_slist_free_full(vsie, g_free);
611
612         return NL_SKIP;
613 }
614
615 static int __netconfig_netlink_scan_reply(struct nl_msg *msg, void *user_data)
616 {
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;
620
621         if (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS) {
622                 DBG("Received NL80211_CMD_NEW_SCAN_RESULTS in reply");
623                 results->done = 1;
624                 results->aborted = 0;
625         } else if (gnlh->cmd == NL80211_CMD_SCAN_ABORTED) {
626                 DBG("Received NL80211_CMD_SCAN_ABORTED in reply");
627                 results->done = 1;
628                 results->aborted = 1;
629         }
630
631         return NL_SKIP;
632 }
633
634 static int __netconfig_trigger_netlink_scan(struct nl_sock *socket,
635                 int if_index, int id, GSList *ssid_list, char *vsie)
636 {
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;
641         int err = 0;
642         int ret = 0;
643         unsigned char ies[NETCONFIG_MAX_VSIE_LEN+1] = {0x00, };
644         int ies_len = 0;
645         int mcid = __netconfig_get_multicast_id(socket, "nl80211", "scan");
646
647         DBG("");
648         ret = nl_socket_add_membership(socket, mcid);
649         if (ret < 0) {
650                 DBG("Failed to add membership, error: (%s)", nl_geterror(-ret));
651                 return ret;
652         }
653
654         msg = nlmsg_alloc();
655         if (!msg) {
656                 DBG("Failed to allocate msg");
657                 nl_socket_drop_membership(socket, mcid);
658                 return -ENOMEM;
659         }
660         ssids = nlmsg_alloc();
661         if (!ssids) {
662                 DBG("Failed to allocate ssids");
663                 nlmsg_free(msg);
664                 nl_socket_drop_membership(socket, mcid);
665                 return -ENOMEM;
666         }
667         cb = nl_cb_alloc(NL_CB_DEFAULT);
668         if (!cb) {
669                 DBG("Failed to allocate callbacks");
670                 nlmsg_free(msg);
671                 nlmsg_free(ssids);
672                 nl_socket_drop_membership(socket, mcid);
673                 return -ENOMEM;
674         }
675
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);
679         if (ret < 0) {
680                 DBG("Failed to add integer attribute to netlink message, error: (%s)", nl_geterror(-ret));
681                 goto out;
682         }
683
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);
687                 if (ret < 0) {
688                         DBG("Failed to add ssid to netlink message, error: (%s)", nl_geterror(-ret));
689                         goto out;
690                 }
691         }
692
693         if (g_slist_length(ssid_list) == 0) {
694                 DBG("Scan with no ssids");
695                 ret = nla_put(ssids, 1, 0, "");
696                 if (ret < 0) {
697                         DBG("nla_put error: (%s)", nl_geterror(-ret));
698                         goto out;
699                 }
700         }
701         nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
702
703         if (vsie) {
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);
708         }
709
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);
714                 if (ret < 0) {
715                         DBG("Failed to add vsie data to netlink message, error: (%s)", nl_geterror(-ret));
716                         goto out;
717                 }
718         }
719
720         err = 1;
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);
728
729         /** Send NL80211_CMD_TRIGGER_SCAN to start the scan. */
730         ret = nl_send_auto_complete(socket, msg);
731
732         if (ret < 0) {
733                 DBG("nl_send_auto_complete() error: (%s)", nl_geterror(-ret));
734                 goto out;
735         }
736
737         DBG("Sent %d bytes to the kernel", ret);
738
739         while (err > 0) {
740                 ret = nl_recvmsgs(socket, cb);
741                 if (ret < 0) {
742                         DBG("nl_recvmsgs() ret: %d (%s)", ret, nl_geterror(-ret));
743                         goto out;
744                 }
745         }
746
747         if (err < 0) {
748                 DBG("error code = %d", err);
749                 ret = -1;
750                 goto out;
751         }
752
753         while (!results.done) {
754                 ret = nl_recvmsgs(socket, cb);
755 #if !defined TIZEN_WEARABLE
756                 if (ret == -NLE_AGAIN && err >= 0)
757                         continue;
758 #endif
759                 if (ret < 0) {
760                         DBG("scan failed");
761                         goto out;
762                 }
763                 if (err < 0) {
764                         DBG("scan failed err: %d", err);
765                         ret = -1;
766                         goto out;
767                 }
768         }
769
770         if (results.aborted) {
771                 DBG("scan aborted");
772                 ret = -1;
773                 goto out;
774         }
775
776 out:
777         /** Release memory */
778         nlmsg_free(ssids);
779         nlmsg_free(msg);
780         nl_cb_put(cb);
781         nl_socket_drop_membership(socket, mcid);
782
783         if (ret < 0 || ret == 1)
784                 return ret;
785
786         DBG("Scan done");
787         return 0;
788 }
789
790 static int __netconfig_netlink_scan(netconfig_nl_global *global, GSList *ssid_list, char *vsie)
791 {
792         DBG("");
793         int ret = __netconfig_trigger_netlink_scan(global->socket, global->if_index, global->id, ssid_list, vsie);
794         if (ret == -NLE_AGAIN) {
795                 DBG("Try Again");
796                 ret = __netconfig_trigger_netlink_scan(global->socket, global->if_index, global->id, ssid_list, vsie);
797         }
798         return ret;
799 }
800
801 static int __netconfig_initialize_nl80211(netconfig_nl_global *global,
802                 const char *interface_name)
803 {
804         int err = 0;
805
806         global->if_index = __netconfig_get_interface_index(interface_name);
807         if (global->if_index < 0) {
808                 DBG("Failed to get interface index");
809                 return -1;
810         }
811
812         global->socket = nl_socket_alloc();
813         if (!global->socket) {
814                 DBG("Failed to allocate netlink socket.");
815                 return -ENOMEM;
816         }
817
818         if (genl_connect(global->socket)) {
819                 DBG("Failed to connect to generic netlink.");
820                 err = -ENOLINK;
821                 goto fail;
822         }
823
824         global->id = genl_ctrl_resolve(global->socket, "nl80211");
825         if (global->id < 0) {
826                 DBG("Failed to find the nl80211 driver");
827                 err = -ENOENT;
828                 goto fail;
829         }
830
831         return 0;
832
833 fail:
834         nl_socket_free(global->socket);
835         return err;
836 }
837
838 static void __netconfig_deinitialize_nl80211(netconfig_nl_global *global)
839 {
840         if (global == NULL)
841                 return;
842
843         if (global->socket) {
844                 nl_socket_free(global->socket);
845                 global->socket = NULL;
846         }
847 }
848
849 static int __netconfig_initialize_nl_msg(netconfig_nl_global *global)
850 {
851         int rv;
852
853         if (global == NULL) {
854                 DBG("Invalid parameter.");
855                 return -EINVAL;
856         }
857
858         global->msg = nlmsg_alloc();
859         if (global->msg == NULL) {
860                 DBG("Failed to allocate netlink message");
861                 return -ENOMEM;
862         }
863
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);
867         if (rv < 0) {
868                 DBG("Failed to add integer attribute to netlink message.");
869                 nlmsg_free(global->msg);
870                 return rv;
871         }
872         nl_socket_modify_cb(global->socket, NL_CB_VALID, NL_CB_CUSTOM, __netconfig_netlink_scan_cb, NULL);
873
874         return 0;
875 }
876
877 static void __netconfig_get_netlink_scan_parameters(GVariant *params, GSList *ssid_list, char **vsie)
878 {
879         GVariantIter *iter;
880         GVariant *value;
881         gchar *key;
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);
889                         }
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));
893                 }
894         }
895         g_variant_iter_free(iter);
896 }
897
898 static int __netconfig_get_scan_results(netconfig_nl_global *global)
899 {
900         int ret = __netconfig_initialize_nl_msg(global);
901         if (ret < 0) {
902                 DBG("__netconfig_initialize_nl_msg() failed, error %d", ret);
903                 return ret;
904         }
905
906         ret = nl_send_auto_complete(global->socket, global->msg);
907         if (ret < 0) {
908                 DBG("nl_send_auto_complete() failed, error %d", ret);
909                 return ret;
910         }
911         DBG("NL80211_CMD_GET_SCAN sent %d bytes to the kernel", ret);
912
913         /** Receive the kernel message. */
914         ret = nl_recvmsgs_default(global->socket);
915         nlmsg_free(global->msg);
916         if (ret < 0) {
917                 DBG("nl_recvmsgs_default() failed. ret: %d (error: %s)", ret, nl_geterror(-ret));
918                 return ret;
919         }
920         return 0;
921 }
922
923 int handle_netlink_scan(Wifi *wifi, GDBusMethodInvocation *context,
924                 const gchar *ifname, GVariant *params)
925 {
926         DBG("");
927         netconfig_nl_global global = {
928                 .id = -1,
929                 .if_index = -1,
930                 .socket = NULL,
931                 .msg = NULL,
932         };
933
934         /** Initialize netlink socket */
935         int ret = __netconfig_initialize_nl80211(&global, ifname);
936         if (ret < 0) {
937                 DBG("__netconfig_initialize_nl80211() failed, error %d", ret);
938                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AccessDenied");
939                 return TRUE;
940         }
941
942         GSList *ssid_list = NULL;
943         char *vsie = 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);
948         g_free(vsie);
949
950         if (ret < 0) {
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);
954                 return TRUE;
955         }
956
957         ret = __netconfig_get_scan_results(&global);
958         if (ret < 0) {
959                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "AccessDenied");
960                 __netconfig_deinitialize_nl80211(&global);
961                 return TRUE;
962         }
963
964         wifi_complete_netlink_scan(wifi, context);
965         __netconfig_notify_netlink_scan_done(ifname);
966         __netconfig_deinitialize_nl80211(&global);
967
968         return TRUE;
969 }