Add the privilege for VSIE API
[platform/core/connectivity/net-config.git] / src / wifi-ssid-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 <stdio.h>
21
22 #include "log.h"
23 #include "util.h"
24 #include "neterror.h"
25 #include "netdbus.h"
26 #include "netsupplicant.h"
27 #include "wifi-ssid-scan.h"
28 #include "wifi-background-scan.h"
29
30 #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
31 #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
32
33 #define WIFI_KEYMGMT_NONE                       (1 << 0)
34 #define WIFI_KEYMGMT_IEEE8021X          (1 << 1)
35 #define WIFI_KEYMGMT_WPA_NONE           (1 << 2)
36 #define WIFI_KEYMGMT_WPA_PSK            (1 << 3)
37 #define WIFI_KEYMGMT_WPA_PSK_256        (1 << 4)
38 #define WIFI_KEYMGMT_WPA_FT_PSK         (1 << 5)
39 #define WIFI_KEYMGMT_WPA_FT_EAP         (1 << 6)
40 #define WIFI_KEYMGMT_WPA_EAP            (1 << 7)
41 #define WIFI_KEYMGMT_WPA_EAP_256        (1 << 8)
42 #define WIFI_KEYMGMT_WPS                        (1 << 9)
43
44 #define WIFI_PAIRWISE_NONE                      (1 << 0)
45 #define WIFI_PAIRWISE_TKIP                      (1 << 1)
46 #define WIFI_PAIRWISE_CCMP                      (1 << 2)
47
48 typedef struct {
49         const char *str;
50         unsigned int val;
51 } strval_s;
52
53 static strval_s wifi_keymgmt[] = {
54         { "none",                       WIFI_KEYMGMT_NONE },
55         { "ieee8021x",          WIFI_KEYMGMT_IEEE8021X },
56         { "wpa-none",           WIFI_KEYMGMT_WPA_NONE },
57         { "wpa-psk",            WIFI_KEYMGMT_WPA_PSK },
58         { "wpa-psk-sha256",     WIFI_KEYMGMT_WPA_PSK_256 },
59         { "wpa-ft-psk",         WIFI_KEYMGMT_WPA_FT_PSK },
60         { "wpa-ft-eap",         WIFI_KEYMGMT_WPA_FT_EAP },
61         { "wpa-eap",            WIFI_KEYMGMT_WPA_EAP },
62         { "wpa-eap-sha256",     WIFI_KEYMGMT_WPA_EAP_256 },
63         { "wps",                        WIFI_KEYMGMT_WPS },
64         { }
65 };
66
67 static strval_s wifi_pairwise[] = {
68         { "none",                       WIFI_PAIRWISE_NONE },
69         { "tkip",                       WIFI_PAIRWISE_TKIP },
70         { "ccmp",                       WIFI_PAIRWISE_CCMP },
71         { }
72 };
73
74 typedef enum {
75         WIFI_SECURITY_UNKNOWN = 0x00,
76         WIFI_SECURITY_NONE,
77         WIFI_SECURITY_WEP,
78         WIFI_SECURITY_PSK,
79         WIFI_SECURITY_PSK2,
80         WIFI_SECURITY_IEEE8021X,
81 } wifi_security_e;
82
83 typedef struct {
84         unsigned char ssid[33];
85         unsigned char bssid[6];
86         wifi_security_e security;
87         unsigned int wpa_keymgmt;
88         unsigned int wpa_pairwise;
89         unsigned int rsn_keymgmt;
90         unsigned int rsn_pairwise;
91         gboolean rsn_selected;
92         gboolean privacy;
93         gboolean wps;
94         int ssid_len;
95 } bss_info_t;
96
97 static gboolean g_ssid_scan_state = FALSE;
98 static GSList *bss_info_list = NULL;
99 static guint ssid_scan_timer = 0;
100 static char *g_ssid = NULL;
101
102 static void __check_keymgmt(const char *str_keymgmt, unsigned int *key_info)
103 {
104         int i;
105
106         for (i = 0; wifi_keymgmt[i].str; i++) {
107                 if (g_strcmp0(str_keymgmt, wifi_keymgmt[i].str) == 0) {
108                         INFO("keymgmt : %s", str_keymgmt);
109                         *key_info |= wifi_keymgmt[i].val;
110                         break;
111                 }
112         }
113 }
114
115 static void __check_pairwise(const char *str_pairwise, unsigned int *pairwise_info)
116 {
117         int i;
118
119         for (i = 0; wifi_pairwise[i].str; i++) {
120                 if (g_strcmp0(str_pairwise, wifi_pairwise[i].str) == 0) {
121                         INFO("pairwise : %s", str_pairwise);
122                         *pairwise_info |= wifi_pairwise[i].val;
123                         break;
124                 }
125         }
126 }
127
128 static wifi_security_e __check_security(bss_info_t *bss_info)
129 {
130         gboolean ieee8021x = FALSE;
131         gboolean psk = FALSE;
132         gboolean ft_ieee8021x = FALSE;
133         gboolean ft_psk = FALSE;
134         unsigned int keymgmt = bss_info->rsn_keymgmt | bss_info->wpa_keymgmt;
135
136         if (keymgmt & (WIFI_KEYMGMT_WPA_EAP | WIFI_KEYMGMT_WPA_EAP_256))
137                 ieee8021x = TRUE;
138         else if (keymgmt & WIFI_KEYMGMT_WPA_FT_EAP)
139                 ft_ieee8021x = TRUE;
140
141         if (keymgmt & (WIFI_KEYMGMT_WPA_PSK | WIFI_KEYMGMT_WPA_PSK_256))
142                 psk = TRUE;
143         else if (keymgmt & WIFI_KEYMGMT_WPA_FT_PSK)
144                 ft_psk = TRUE;
145
146         if (ieee8021x || ft_ieee8021x)
147                 bss_info->security = WIFI_SECURITY_IEEE8021X;
148         else if (psk || ft_psk)
149                 bss_info->security = WIFI_SECURITY_PSK;
150         else if (bss_info->privacy)
151                 bss_info->security = WIFI_SECURITY_WEP;
152         else
153                 bss_info->security = WIFI_SECURITY_NONE;
154
155         if (bss_info->rsn_selected) {
156                 unsigned int pairwise = bss_info->rsn_pairwise | bss_info->wpa_pairwise;
157                 if ((pairwise & WIFI_PAIRWISE_CCMP) ||
158                         (pairwise & (WIFI_PAIRWISE_CCMP | WIFI_PAIRWISE_TKIP)))
159                         bss_info->security = WIFI_SECURITY_PSK2;
160         }
161
162         return bss_info->security;
163 }
164
165 static gboolean __ssid_scan_timeout(gpointer data)
166 {
167         wifi_ssid_scan_emit_scan_completed();
168
169         return FALSE;
170 }
171
172 static void _start_ssid_scan_timer(void)
173 {
174         INFO("Wi-Fi SSID scan started");
175         g_ssid_scan_state = TRUE;
176
177         netconfig_start_timer_seconds(5, __ssid_scan_timeout, NULL, &ssid_scan_timer);
178 }
179
180 static void _stop_ssid_scan_timer(void)
181 {
182         INFO("Wi-Fi SSID scan finished");
183         g_ssid_scan_state = FALSE;
184
185         netconfig_stop_timer(&ssid_scan_timer);
186 }
187
188 static void _parse_wpa_message(GVariant *param, bss_info_t *bss_info)
189 {
190         GVariantIter *iter1;
191         GVariant *var;
192         gchar *key;
193
194         g_variant_get(param, "a{sv}", &iter1);
195         while (g_variant_iter_loop(iter1, "{sv}", &key, &var)) {
196                 if (g_strcmp0(key, "KeyMgmt") == 0) {
197                         GVariantIter *iter2;
198                         g_variant_get(var, "as", &iter2);
199                         char *str;
200                         while (g_variant_iter_loop(iter2, "s", &str)) {
201                                 if (str == NULL)
202                                         break;
203                                 unsigned int key_info = 0;
204                                 __check_keymgmt(str, &key_info);
205                                 if (bss_info->rsn_selected)
206                                         bss_info->rsn_keymgmt = key_info;
207                                 else
208                                         bss_info->wpa_keymgmt = key_info;
209                         }
210                         g_variant_iter_free(iter2);
211                 } else if (g_strcmp0(key, "Pairwise") == 0) {
212                         GVariantIter *iter2;
213                         g_variant_get(var, "as", &iter2);
214                         char *str;
215                         while (g_variant_iter_loop(iter2, "s", &str)) {
216                                 if (str == NULL)
217                                         break;
218                                 unsigned int pairwise_info = 0;
219                                 __check_pairwise(str, &pairwise_info);
220                                 if (bss_info->rsn_selected)
221                                         bss_info->rsn_pairwise = pairwise_info;
222                                 else
223                                         bss_info->wpa_pairwise = pairwise_info;
224                         }
225                         g_variant_iter_free(iter2);
226                 }
227         }
228
229         g_variant_iter_free(iter1);
230
231         return;
232 }
233
234 static gboolean _request_ssid_scan(const char *object_path, const char *ssid)
235 {
236         /* TODO: Revise following code */
237
238         GDBusConnection *connection = NULL;
239         GVariant *reply = NULL;
240         GVariant *params = NULL;
241         GError *error = NULL;
242         GVariantBuilder *builder1 = NULL;
243         GVariantBuilder *builder2 = NULL;
244         GVariantBuilder *builder3 = NULL;
245         const gchar *key1 = "Type";
246         const gchar *val1 = "active";
247         const gchar *key2 = "SSIDs";
248         int i = 0;
249
250         connection = netdbus_get_connection();
251         if (connection == NULL) {
252                 DBG("Failed to get GDBusconnection");
253                 return FALSE;
254         }
255
256         builder1 = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
257         g_variant_builder_add(builder1, "{sv}", key1, g_variant_new_string(val1));
258
259         builder2 = g_variant_builder_new(G_VARIANT_TYPE("aay"));
260         builder3 = g_variant_builder_new(G_VARIANT_TYPE("ay"));
261
262         for (i = 0; i < strlen(ssid); i++)
263                 g_variant_builder_add(builder3, "y", ssid[i]);
264
265         g_variant_builder_add(builder2, "@ay", g_variant_builder_end(builder3));
266         g_variant_builder_add(builder1, "{sv}", key2, g_variant_builder_end(builder2));
267
268         params = g_variant_new("(@a{sv})", g_variant_builder_end(builder1));
269
270         g_variant_builder_unref(builder1);
271         g_variant_builder_unref(builder2);
272         g_variant_builder_unref(builder3);
273
274         reply = g_dbus_connection_call_sync(
275                         connection,
276                         SUPPLICANT_SERVICE,
277                         object_path,
278                         SUPPLICANT_INTERFACE ".Interface",
279                         "Scan",
280                         params,
281                         NULL,
282                         G_DBUS_CALL_FLAGS_NONE,
283                         NETCONFIG_DBUS_REPLY_TIMEOUT,
284                         netdbus_get_cancellable(),
285                         &error);
286
287         if (reply == NULL) {
288                 if (error != NULL) {
289                         ERR("Error!!! dbus_connection_send_with_reply_and_block() failed. "
290                                         "DBus error [%d: %s]", error->code, error->message);
291                         g_error_free(error);
292                 } else
293                         ERR("Error!!! Failed to get properties");
294
295                 return FALSE;
296         }
297
298         if (g_ssid != NULL)
299                 g_free(g_ssid);
300
301         g_ssid = g_strdup(ssid);
302
303         g_variant_unref(reply);
304
305         return TRUE;
306 }
307
308 static void _emit_ssid_scan_completed(void)
309 {
310         GVariantBuilder *builder = NULL;
311         GSList* list = NULL;
312         const char *prop_ssid = "ssid";
313         const char *prop_bssid = "bssid";
314         char bssid_buf[18] = {0,};
315         char *bssid_str = bssid_buf;
316         const char *prop_security = "security";
317         const char *prop_wps = "wps";
318         GVariantBuilder *rawssid_builder = NULL;
319         const char *prop_raw_ssid = "raw_ssid";
320
321         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
322         for (list = bss_info_list; list != NULL; list = list->next) {
323                 bss_info_t *bss_info = (bss_info_t *)list->data;
324                 if (bss_info && g_strcmp0((char *)bss_info->ssid, g_ssid) == 0) {
325                         const gchar *ssid = (char *)bss_info->ssid;
326                         int ssid_len = bss_info->ssid_len;
327                         const gchar *bssid = (gchar *)&bss_info->bssid[0];
328                         int i = 0;
329
330                         wifi_security_e security = __check_security(bss_info);
331                         gboolean wps = bss_info->wps;
332                         DBG("BSS found; SSID:%s security:%d WPS:%d", ssid, security, wps);
333
334                         if (bssid) {
335                                 snprintf(bssid_str, sizeof(bssid_buf), MACSTR, MAC2STR(bssid));
336                                 DBG("BSSID: %s", bssid_str);
337                         }
338
339                         g_variant_builder_add(builder, "{sv}", prop_ssid, g_variant_new_string(ssid));
340
341                         /* append raw SSID in bytes to the specific
342                            scan completed signal here */
343                         rawssid_builder = g_variant_builder_new(G_VARIANT_TYPE("ay"));
344                         for (i = 0; i < ssid_len; i++)
345                                 g_variant_builder_add(rawssid_builder, "y", ssid[i]);
346                         g_variant_builder_add(builder, "{sv}", prop_raw_ssid, g_variant_new("ay", rawssid_builder));
347                         g_variant_builder_unref(rawssid_builder);
348
349                         g_variant_builder_add(builder, "{sv}", prop_bssid,
350                                                 g_variant_new_string(bssid));
351                         g_variant_builder_add(builder, "{sv}", prop_security, g_variant_new_int32(security));
352                         /* WPS */
353                         g_variant_builder_add(builder, "{sv}", prop_wps, g_variant_new_boolean(wps));
354                 }
355         }
356
357         wifi_emit_specific_scan_completed((Wifi *)get_wifi_object(), g_variant_builder_end(builder));
358
359         if (builder)
360                 g_variant_builder_unref(builder);
361
362         if (bss_info_list != NULL) {
363                 g_slist_free_full(bss_info_list, g_free);
364                 bss_info_list = NULL;
365         }
366
367         if (g_ssid != NULL) {
368                 g_free(g_ssid);
369                 g_ssid = NULL;
370         }
371
372         INFO("SpecificScanCompleted");
373
374         return;
375 }
376
377 gboolean wifi_ssid_scan(const char *ssid)
378 {
379         const char *if_path;
380         static char *scan_ssid = NULL;
381
382         netconfig_wifi_bgscan_stop();
383
384         if (ssid != NULL) {
385                 if (scan_ssid != NULL)
386                         g_free(scan_ssid);
387                 scan_ssid = g_strdup(ssid);
388         }
389
390         if (scan_ssid == NULL)
391                 goto error;
392
393         if_path = netconfig_wifi_get_supplicant_interface();
394         if (if_path == NULL) {
395                 DBG("Fail to get wpa_supplicant DBus path");
396                 goto error;
397         }
398
399         if (netconfig_wifi_get_scanning() == TRUE) {
400                 DBG("Wi-Fi scan in progress, %s scan will be delayed", scan_ssid);
401                 return TRUE;
402         }
403
404         if (bss_info_list) {
405                 g_slist_free_full(bss_info_list, g_free);
406                 bss_info_list = NULL;
407         }
408
409         INFO("Start Wi-Fi scan with %s(%d)", scan_ssid, strlen(scan_ssid));
410         if (_request_ssid_scan(if_path, (const char *)scan_ssid) == TRUE) {
411                 _start_ssid_scan_timer();
412                 g_free(scan_ssid);
413                 scan_ssid = NULL;
414                 return TRUE;
415         }
416
417 error:
418         if (scan_ssid != NULL) {
419                 g_free(scan_ssid);
420                 scan_ssid = NULL;
421         }
422
423         netconfig_wifi_bgscan_start(FALSE);
424
425         return FALSE;
426 }
427
428 gboolean wifi_ssid_scan_get_state(void)
429 {
430         return g_ssid_scan_state;
431 }
432
433 void wifi_ssid_scan_emit_scan_completed(void)
434 {
435         if (g_ssid_scan_state != TRUE)
436                 return;
437
438         _stop_ssid_scan_timer();
439         _emit_ssid_scan_completed();
440         netconfig_wifi_bgscan_start(FALSE);
441 }
442
443 void wifi_ssid_scan_add_bss(GVariant *message)
444 {
445         GVariantIter *iter;
446         GVariant *value;
447         gchar *path = NULL;
448         gchar *key;
449         bss_info_t *bss_info;
450
451         if (g_ssid_scan_state != TRUE)
452                 return;
453
454         INFO("NEW BSS added");
455
456         if (message == NULL) {
457                 DBG("Message does not have parameters");
458                 return;
459         }
460
461         if (path != NULL)
462                 INFO("Object path of BSS added is %s", path);
463
464         bss_info = g_try_new0(bss_info_t, 1);
465         if (bss_info == NULL)
466                 return;
467
468         g_variant_get(message, "(oa{sv})", &path, &iter);
469         while (g_variant_iter_loop(iter, "{sv}", &key, &value)) {
470                 if (g_strcmp0(key, "SSID") == 0) {
471                         const guchar *ssid;
472                         gsize ssid_len;
473                         ssid = g_variant_get_fixed_array(value, &ssid_len, sizeof(guchar));
474                         if (ssid != NULL && ssid_len > 0 && ssid_len < 33) {
475                                 memcpy(bss_info->ssid, ssid, ssid_len);
476                                 bss_info->ssid_len = ssid_len;
477                         } else {
478                                 memset(bss_info->ssid, 0, sizeof(bss_info->ssid));
479                                 bss_info->ssid_len = 0;
480                         }
481                 } else if (g_strcmp0(key, "Privacy") == 0) {
482                         gboolean privacy = FALSE;
483                         privacy = g_variant_get_boolean(value);
484                         bss_info->privacy = privacy;
485                 } else if (g_strcmp0(key, "RSN") == 0) {
486                         bss_info->rsn_selected = TRUE;
487                         _parse_wpa_message(value, bss_info);
488                 } else if (g_strcmp0(key, "WPA") == 0) {
489                         bss_info->rsn_selected = FALSE;
490                         _parse_wpa_message(value, bss_info);
491                 } else if (g_strcmp0(key, "IEs") == 0) {
492                         const guchar *ie;
493                         gsize ie_len;
494                         ie = g_variant_get_fixed_array(value, &ie_len, sizeof(guchar));
495                         DBG("The IE : %s", ie);
496                 } else if (g_strcmp0(key, "BSSID") == 0) {
497                         const guchar *bssid;
498                         gsize bssid_len;
499
500                         bssid = g_variant_get_fixed_array(value, &bssid_len, sizeof(guchar));
501                         if (bssid != NULL && bssid_len == 6)
502                                 memcpy(bss_info->bssid, bssid, bssid_len);
503                 }
504         }
505
506         g_variant_iter_free(iter);
507         if (path)
508                 g_free(path);
509
510         if (bss_info->ssid[0] == '\0') {
511                 g_free(bss_info);
512                 return;
513         }
514
515         if (bss_info->security == WIFI_SECURITY_UNKNOWN) {
516                 if (bss_info->privacy == TRUE)
517                         bss_info->security = WIFI_SECURITY_WEP;
518                 else
519                         bss_info->security = WIFI_SECURITY_NONE;
520         }
521
522         bss_info_list = g_slist_append(bss_info_list, bss_info);
523 }
524
525 gboolean handle_request_specific_scan(Wifi *wifi,
526                 GDBusMethodInvocation *context, const gchar *ssid)
527 {
528         gboolean result = FALSE;
529
530         g_return_val_if_fail(wifi != NULL, FALSE);
531         g_return_val_if_fail(ssid != NULL, FALSE);
532
533         result = wifi_ssid_scan((const char *)ssid);
534
535         if (result != TRUE)
536                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "FailSpecificScan");
537         else
538                 wifi_complete_request_specific_scan(wifi, context);
539
540         return result;
541 }