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