Merge "[net-config] Use wrapper function to get vconfkeys value." into tizen
[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 "log.h"
21 #include "util.h"
22 #include "neterror.h"
23 #include "netdbus.h"
24 #include "netsupplicant.h"
25 #include "wifi-ssid-scan.h"
26 #include "wifi-background-scan.h"
27
28 typedef enum {
29         WIFI_SECURITY_UNKNOWN = 0x00,
30         WIFI_SECURITY_NONE = 0x01,
31         WIFI_SECURITY_WEP = 0x02,
32         WIFI_SECURITY_PSK = 0x03,
33         WIFI_SECURITY_IEEE8021X = 0x04,
34 } wifi_security_e;
35
36 typedef struct {
37         unsigned char ssid[33];
38         wifi_security_e security;
39         gboolean privacy;
40         gboolean wps;
41 } bss_info_t;
42
43 static gboolean g_ssid_scan_state = FALSE;
44 static GSList *bss_info_list = NULL;
45 static guint ssid_scan_timer = 0;
46 static char *g_ssid = NULL;
47
48 static void __check_security(const char *str_keymgmt, bss_info_t *bss_info)
49 {
50         INFO("keymgmt : %s", str_keymgmt);
51
52         if (g_strcmp0(str_keymgmt, "ieee8021x") == 0)
53                 bss_info->security = WIFI_SECURITY_IEEE8021X;
54         else if (g_strcmp0(str_keymgmt, "wpa-psk") == 0)
55                 bss_info->security = WIFI_SECURITY_PSK;
56         else if (g_strcmp0(str_keymgmt, "wpa-psk-sha256") == 0)
57                 bss_info->security = WIFI_SECURITY_PSK;
58         else if (g_strcmp0(str_keymgmt, "wpa-ft-psk") == 0)
59                 bss_info->security = WIFI_SECURITY_PSK;
60         else if (g_strcmp0(str_keymgmt, "wpa-ft-eap") == 0)
61                 bss_info->security = WIFI_SECURITY_IEEE8021X;
62         else if (g_strcmp0(str_keymgmt, "wpa-eap") == 0)
63                 bss_info->security = WIFI_SECURITY_IEEE8021X;
64         else if (g_strcmp0(str_keymgmt, "wpa-eap-sha256") == 0)
65                 bss_info->security = WIFI_SECURITY_IEEE8021X;
66         else if (g_strcmp0(str_keymgmt, "wps") == 0)
67                 bss_info->wps = TRUE;
68 }
69
70 static gboolean __ssid_scan_timeout(gpointer data)
71 {
72         wifi_ssid_scan_emit_scan_completed();
73
74         return FALSE;
75 }
76
77 static void _start_ssid_scan_timer(void)
78 {
79         INFO("Wi-Fi SSID scan started");
80         g_ssid_scan_state = TRUE;
81
82         netconfig_start_timer_seconds(5, __ssid_scan_timeout, NULL, &ssid_scan_timer);
83 }
84
85 static void _stop_ssid_scan_timer(void)
86 {
87         INFO("Wi-Fi SSID scan finished");
88         g_ssid_scan_state = FALSE;
89
90         netconfig_stop_timer(&ssid_scan_timer);
91 }
92
93 static void _parse_keymgmt_message(GVariant *param, bss_info_t *bss_info)
94 {
95         GVariantIter *iter1;
96         GVariant *var;
97         gchar *key;
98
99         g_variant_get(param, "a{sv}", &iter1);
100         while (g_variant_iter_loop(iter1, "{sv}", &key, &var)) {
101                 if (g_strcmp0(key, "KeyMgmt") == 0) {
102                         GVariantIter *iter2;
103                         g_variant_get(var, "as", &iter2);
104                         char *str;
105                         while (g_variant_iter_loop(iter2, "s", &str)) {
106                                 if (str == NULL)
107                                         break;
108                                 __check_security(str, bss_info);
109                         }
110                         g_variant_iter_free(iter2);
111                 }
112         }
113
114         g_variant_iter_free(iter1);
115
116         return;
117 }
118
119 static gboolean _request_ssid_scan(const char *object_path, const char *ssid)
120 {
121         /* TODO: Revise following code */
122
123         GDBusConnection *connection = NULL;
124         GVariant *reply = NULL;
125         GVariant *params = NULL;
126         GError *error = NULL;
127         GVariantBuilder *builder1 = NULL;
128         GVariantBuilder *builder2 = NULL;
129         GVariantBuilder *builder3 = NULL;
130         const gchar *key1 = "Type";
131         const gchar *val1 = "active";
132         const gchar *key2 = "SSIDs";
133         int i = 0;
134
135         connection = netdbus_get_connection();
136         if (connection == NULL) {
137                 DBG("Failed to get GDBusconnection");
138                 return FALSE;
139         }
140
141         builder1 = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
142         g_variant_builder_add(builder1, "{sv}", key1, g_variant_new_string(val1));
143
144         builder2 = g_variant_builder_new(G_VARIANT_TYPE("aay"));
145         builder3 = g_variant_builder_new(G_VARIANT_TYPE("ay"));
146
147         for (i = 0; i < strlen(ssid); i++)
148                 g_variant_builder_add(builder3, "y", ssid[i]);
149
150         g_variant_builder_add(builder2, "@ay", g_variant_builder_end(builder3));
151         g_variant_builder_add(builder1, "{sv}", key2, g_variant_builder_end(builder2));
152
153         params = g_variant_new("(@a{sv})", g_variant_builder_end(builder1));
154
155         g_variant_builder_unref(builder1);
156         g_variant_builder_unref(builder2);
157         g_variant_builder_unref(builder3);
158
159         reply = g_dbus_connection_call_sync(
160                         connection,
161                         SUPPLICANT_SERVICE,
162                         object_path,
163                         SUPPLICANT_INTERFACE ".Interface",
164                         "Scan",
165                         params,
166                         NULL,
167                         G_DBUS_CALL_FLAGS_NONE,
168                         NETCONFIG_DBUS_REPLY_TIMEOUT,
169                         netdbus_get_cancellable(),
170                         &error);
171
172         if (reply == NULL) {
173                 if (error != NULL) {
174                         ERR("Error!!! dbus_connection_send_with_reply_and_block() failed. "
175                                         "DBus error [%d: %s]", error->code, error->message);
176                         g_error_free(error);
177                 } else
178                         ERR("Error!!! Failed to get properties");
179
180                 return FALSE;
181         }
182
183         if (g_ssid != NULL)
184                 g_free(g_ssid);
185
186         g_ssid = g_strdup(ssid);
187
188         g_variant_unref(reply);
189
190         return TRUE;
191 }
192
193 static void _emit_ssid_scan_completed(void)
194 {
195         GVariantBuilder *builder = NULL;
196         GSList* list = NULL;
197         const char *prop_ssid = "ssid";
198         const char *prop_security = "security";
199         const char *prop_wps = "wps";
200
201         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
202         for (list = bss_info_list; list != NULL; list = list->next) {
203                 bss_info_t *bss_info = (bss_info_t *)list->data;
204                 if (bss_info && g_strcmp0((char *)bss_info->ssid, g_ssid) == 0) {
205                         const gchar *ssid = (char *)bss_info->ssid;
206                         wifi_security_e security = bss_info->security;
207                         gboolean wps = bss_info->wps;
208                         DBG("BSS found; SSID:%s security:%d WPS:%d", ssid, security, wps);
209                         g_variant_builder_add(builder, "{sv}", prop_ssid, g_variant_new_string(ssid));
210                         g_variant_builder_add(builder, "{sv}", prop_security, g_variant_new_int32(security));
211                         /* WPS */
212                         g_variant_builder_add(builder, "{sv}", prop_wps, g_variant_new_boolean(wps));
213                 }
214         }
215
216         wifi_emit_specific_scan_completed((Wifi *)get_wifi_object(), g_variant_builder_end(builder));
217
218         if (builder)
219                 g_variant_builder_unref(builder);
220
221         if (bss_info_list != NULL) {
222                 g_slist_free_full(bss_info_list, g_free);
223                 bss_info_list = NULL;
224         }
225
226         if (g_ssid != NULL) {
227                 g_free(g_ssid);
228                 g_ssid = NULL;
229         }
230
231         INFO("SpecificScanCompleted");
232
233         return;
234 }
235
236 gboolean wifi_ssid_scan(const char *ssid)
237 {
238         const char *if_path;
239         static char *scan_ssid = NULL;
240
241         netconfig_wifi_bgscan_stop();
242
243         if (ssid != NULL) {
244                 if (scan_ssid != NULL)
245                         g_free(scan_ssid);
246                 scan_ssid = g_strdup(ssid);
247         }
248
249         if (scan_ssid == NULL)
250                 goto error;
251
252         if_path = netconfig_wifi_get_supplicant_interface();
253         if (if_path == NULL) {
254                 DBG("Fail to get wpa_supplicant DBus path");
255                 goto error;
256         }
257
258         if (netconfig_wifi_get_scanning() == TRUE) {
259                 DBG("Wi-Fi scan in progress, %s scan will be delayed", scan_ssid);
260                 g_free(scan_ssid);
261                 return TRUE;
262         }
263
264         if (bss_info_list) {
265                 g_slist_free_full(bss_info_list, g_free);
266                 bss_info_list = NULL;
267         }
268
269         INFO("Start Wi-Fi scan with %s(%d)", scan_ssid, strlen(scan_ssid));
270         if (_request_ssid_scan(if_path, (const char *)scan_ssid) == TRUE) {
271                 _start_ssid_scan_timer();
272                 g_free(scan_ssid);
273                 scan_ssid = NULL;
274                 return TRUE;
275         }
276
277 error:
278         if (scan_ssid != NULL) {
279                 g_free(scan_ssid);
280                 scan_ssid = NULL;
281         }
282
283         netconfig_wifi_bgscan_start(FALSE);
284
285         return FALSE;
286 }
287
288 gboolean wifi_ssid_scan_get_state(void)
289 {
290         return g_ssid_scan_state;
291 }
292
293 void wifi_ssid_scan_emit_scan_completed(void)
294 {
295         if (g_ssid_scan_state != TRUE)
296                 return;
297
298         _stop_ssid_scan_timer();
299         _emit_ssid_scan_completed();
300 }
301
302 void wifi_ssid_scan_add_bss(GVariant *message)
303 {
304         GVariantIter *iter;
305         GVariant *value;
306         gchar *path = NULL;
307         gchar *key;
308         bss_info_t *bss_info;
309
310         if (g_ssid_scan_state != TRUE)
311                 return;
312
313         INFO("NEW BSS added");
314
315         if (message == NULL) {
316                 DBG("Message does not have parameters");
317                 return;
318         }
319
320         if (path != NULL)
321                 INFO("Object path of BSS added is %s", path);
322
323         bss_info = g_try_new0(bss_info_t, 1);
324         if (bss_info == NULL)
325                 return;
326
327         g_variant_get(message, "(oa{sv})", &path, &iter);
328         while (g_variant_iter_loop(iter, "{sv}", &key, &value)) {
329                 if (g_strcmp0(key, "SSID") == 0) {
330                         const guchar *ssid;
331                         gsize ssid_len;
332                         ssid = g_variant_get_fixed_array(value, &ssid_len, sizeof(guchar));
333                         if (ssid != NULL && ssid_len > 0 && ssid_len < 33)
334                                 memcpy(bss_info->ssid, ssid, ssid_len);
335                         else
336                                 memset(bss_info->ssid, 0, sizeof(bss_info->ssid));
337                 } else if (g_strcmp0(key, "Privacy") == 0) {
338                         gboolean privacy = FALSE;
339                         privacy = g_variant_get_boolean(value);
340                         bss_info->privacy = privacy;
341                 } else if ((g_strcmp0(key, "RSN") == 0) || (g_strcmp0(key, "WPA") == 0)) {
342                         _parse_keymgmt_message(value, bss_info);
343                 } else if (g_strcmp0(key, "IEs") == 0) {
344                         const guchar *ie;
345                         gsize ie_len;
346                         ie = g_variant_get_fixed_array(value, &ie_len, sizeof(guchar));
347                         DBG("The IE : %s", ie);
348                 }
349         }
350
351         g_variant_iter_free(iter);
352         if (path)
353                 g_free(path);
354
355         if (bss_info->ssid[0] == '\0') {
356                 g_free(bss_info);
357                 return;
358         }
359
360         if (bss_info->security == WIFI_SECURITY_UNKNOWN) {
361                 if (bss_info->privacy == TRUE)
362                         bss_info->security = WIFI_SECURITY_WEP;
363                 else
364                         bss_info->security = WIFI_SECURITY_NONE;
365         }
366
367         bss_info_list = g_slist_append(bss_info_list, bss_info);
368 }
369
370 gboolean handle_request_specific_scan(Wifi *wifi,
371                 GDBusMethodInvocation *context, const gchar *ssid)
372 {
373         gboolean result = FALSE;
374
375         g_return_val_if_fail(wifi != NULL, FALSE);
376         g_return_val_if_fail(ssid != NULL, FALSE);
377
378         result = wifi_ssid_scan((const char *)ssid);
379
380         if (result != TRUE)
381                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "FailSpecificScan");
382         else
383                 wifi_complete_request_specific_scan(wifi, context);
384
385         return result;
386 }