Fixed memory related issues reported by valgrind.
[platform/core/connectivity/net-config.git] / src / wifi-bssid-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 "wifi-bssid-scan.h"
25 #include "util.h"
26 #include "wifi-power.h"
27 #include "wifi-state.h"
28 #include "wifi-background-scan.h"
29
30 #define NETCONFIG_SSID_LEN                                              32
31 #define NETCONFIG_BSSID_LEN                                             6
32
33 #define VCONF_WIFI_ALWAYS_ALLOW_SCANNING \
34         "file/private/wifi/always_allow_scanning"
35
36 static gboolean netconfig_is_bssid_scan_started = FALSE;
37 static gboolean netconfig_is_device_scanning = FALSE;
38 static gboolean netconfig_is_bssid_scan_aborted = FALSE;
39 static int bssid_list_count = 0;
40 static GSList *bssid_info_list = NULL;
41
42 struct bssid_scan_info_t {
43         unsigned char ssid[NETCONFIG_SSID_LEN + 1];
44         unsigned char bssid[NETCONFIG_BSSID_LEN + 1];
45         int ssid_len;
46         int rssi;
47         int mode;
48 };
49
50 gboolean netconfig_wifi_is_bssid_scan_started(void)
51 {
52         return netconfig_is_bssid_scan_started;
53 }
54
55 static void __netconfig_wifi_bssid_notify_scan_done(void)
56 {
57         GVariantBuilder *builder = NULL;
58         GVariantBuilder *builder1 = NULL;
59         GSList* list = NULL;
60         const char *prop_ssid = "ssid";
61         const char *prop_bssid = "bssid";
62         const char *prop_rssi = "rssi";
63         const char *prop_mode = "mode";
64
65         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
66         for (list = bssid_info_list; list != NULL; list = list->next) {
67                 struct bssid_scan_info_t *bss_info = (struct bssid_scan_info_t *)list->data;
68
69                 if (bss_info) {
70                         gchar bssid_buff[18] = { 0, };
71                         gchar *bssid_str = bssid_buff;
72                         unsigned char *ssid = (unsigned char *)bss_info->ssid;
73                         int ssid_len = (int)bss_info->ssid_len;
74                         int rssi = (int)bss_info->rssi;
75                         int mode = (int)bss_info->mode;
76                         int i = 0;
77                         g_snprintf(bssid_buff, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
78                                         bss_info->bssid[0], bss_info->bssid[1], bss_info->bssid[2],
79                                         bss_info->bssid[3], bss_info->bssid[4], bss_info->bssid[5]);
80
81                         DBG("BSS found; SSID %s, BSSID %s, RSSI %d MODE %d", ssid, bssid_str, rssi, mode);
82
83                         builder1 = g_variant_builder_new(G_VARIANT_TYPE("ay"));
84                         for (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_str));
90                         g_variant_builder_add(builder, "{sv}", prop_rssi, g_variant_new_int32(rssi));
91                         g_variant_builder_add(builder, "{sv}", prop_mode, g_variant_new_int32(mode));
92                 }
93         }
94
95         wifi_emit_bssid_scan_completed((Wifi *)get_wifi_object(), g_variant_builder_end(builder));
96         g_variant_builder_unref(builder);
97
98         if (bssid_info_list != NULL)
99                 g_slist_free_full(bssid_info_list, g_free);
100
101         bssid_info_list = NULL;
102         bssid_list_count = 0;
103         INFO("BSSIDScanCompleted");
104
105         return;
106 }
107
108 static void __netconfig_wifi_bssid_get_bss_info_result(
109                 GObject *source_object, GAsyncResult *res, gpointer user_data)
110 {
111         GVariant *reply = NULL;
112         GVariant *value;
113         GVariantIter *iter;
114         gchar *key;
115         struct bssid_scan_info_t *bss_info;
116         GDBusConnection *conn = NULL;
117         GError *error = NULL;
118
119         conn = G_DBUS_CONNECTION(source_object);
120         reply = g_dbus_connection_call_finish(conn, res, &error);
121
122         if (error != NULL) {
123                 ERR("Error code: [%d] Error message: [%s]", error->code, error->message);
124                 g_error_free(error);
125                 goto done;
126         }
127
128         bss_info = g_try_new0(struct bssid_scan_info_t, 1);
129         if (bss_info == NULL)
130                 goto done;
131
132         g_variant_get(reply, "(a{sv})", &iter);
133         while (g_variant_iter_loop(iter, "{sv}", &key, &value)) {
134                 if (key != NULL) {
135                         if (g_strcmp0(key, "BSSID") == 0) {
136                                 const guchar *bssid;
137                                 gsize bssid_len;
138
139                                 bssid = g_variant_get_fixed_array(value, &bssid_len, sizeof(guchar));
140                                 if (bssid_len == NETCONFIG_BSSID_LEN)
141                                         memcpy(bss_info->bssid, bssid, bssid_len);
142                         } else if (g_strcmp0(key, "SSID") == 0) {
143                                 const guchar *ssid;
144                                 gsize ssid_len;
145
146                                 ssid = g_variant_get_fixed_array(value, &ssid_len, sizeof(guchar));
147                                 if (ssid != NULL && ssid_len > 0 && ssid_len <= NETCONFIG_SSID_LEN) {
148                                         memcpy(bss_info->ssid, ssid, ssid_len);
149                                         bss_info->ssid_len = ssid_len;
150                                 } else {
151                                         memset(bss_info->ssid, 0, sizeof(bss_info->ssid));
152                                         bss_info->ssid_len = 0;
153                                 }
154                         } else if (g_strcmp0(key, "Mode") == 0) {
155                                 gchar *mode = NULL;
156
157                                 g_variant_get(value, "s", &mode);
158                                 if (mode == NULL)
159                                         bss_info->mode = 0;
160                                 else {
161                                         if (g_strcmp0(mode, "infrastructure") == 0)
162                                                 bss_info->mode = 1;
163                                         else if (g_strcmp0(mode, "ad-hoc") == 0)
164                                                 bss_info->mode = 2;
165                                         else
166                                                 bss_info->mode = 0;
167                                         g_free(mode);
168                                 }
169                         } else if (g_strcmp0(key, "Signal") == 0) {
170                                 gint16 signal;
171
172                                 signal = g_variant_get_int16(value);
173                                 bss_info->rssi = signal;
174                         }
175                 }
176         }
177
178         if (bss_info->ssid[0] == '\0')
179                 g_free(bss_info);
180         else
181                 bssid_info_list = g_slist_append(bssid_info_list, bss_info);
182
183         g_variant_iter_free(iter);
184 done:
185         if (reply)
186                 g_variant_unref(reply);
187
188         netconfig_gdbus_pending_call_unref();
189
190         bssid_list_count--;
191         if (bssid_list_count <= 0) {
192                 __netconfig_wifi_bssid_notify_scan_done();
193
194                 if (netconfig_is_bssid_scan_aborted == FALSE)
195                         wifi_power_driver_and_supplicant(FALSE);
196         }
197 }
198
199 static void __netconfig_wifi_bssid_get_bss_info(const char *path, int index)
200 {
201         gboolean reply = FALSE;
202         GVariant *param = NULL;
203
204         param = g_variant_new("(s)", SUPPLICANT_IFACE_BSS);
205
206         reply = netconfig_invoke_dbus_method_nonblock(SUPPLICANT_SERVICE,
207                         path, DBUS_INTERFACE_PROPERTIES,
208                         "GetAll", param, __netconfig_wifi_bssid_get_bss_info_result);
209         if (reply != TRUE)
210                 ERR("Fail to invoke_dbus_method_nonblock GetAll");
211
212         return;
213 }
214
215 static void __netconfig_wifi_bssid_get_bss_result(GObject *source_object,
216                 GAsyncResult *res, gpointer user_data)
217 {
218         GVariant *reply = NULL;
219         GVariant *value = NULL;
220         GVariantIter *iter = NULL;
221         GDBusConnection *conn = NULL;
222         gchar *path = NULL;
223         gboolean counter_flag = FALSE;
224         GError *error = NULL;
225
226         conn = G_DBUS_CONNECTION(source_object);
227         reply = g_dbus_connection_call_finish(conn, res, &error);
228         if (error != NULL) {
229                 ERR("Error code: [%d] Error message: [%s]", error->code, error->message);
230                 g_error_free(error);
231                 goto done;
232         }
233
234         g_variant_get(reply, "(v)", &value);
235         if (g_variant_is_of_type(value, G_VARIANT_TYPE_OBJECT_PATH_ARRAY)) {
236                 g_variant_get(value, "ao", &iter);
237                 while (g_variant_iter_next(iter, "o", &path)) {
238                         if (path != NULL && g_strcmp0(path, "/") != 0) {
239                                 __netconfig_wifi_bssid_get_bss_info(path, ++bssid_list_count);
240
241                                 counter_flag = TRUE;
242                         }
243
244                         if (path)
245                                 g_free(path);
246                 }
247         }
248
249         if (iter)
250                 g_variant_iter_free(iter);
251
252         if (value)
253                 g_variant_unref(value);
254
255 done:
256         if (reply)
257                 g_variant_unref(reply);
258
259         netconfig_gdbus_pending_call_unref();
260
261         /* Send BssidScanCompleted signal even when the BSS count is 0 */
262         if (bssid_list_count <= 0 && counter_flag == FALSE) {
263                 __netconfig_wifi_bssid_notify_scan_done();
264
265                 if (netconfig_is_bssid_scan_aborted == FALSE)
266                         wifi_power_driver_and_supplicant(FALSE);
267         }
268 }
269
270 static int _netconfig_wifi_bssid_get_bss(void)
271 {
272         gboolean reply = FALSE;
273         char *if_path = NULL;
274         GVariant *params = NULL;
275
276         if_path = netconfig_wifi_get_supplicant_interface();
277         if (if_path == NULL) {
278                 DBG("Fail to get wpa_supplicant DBus path");
279                 return -ESRCH;
280         }
281
282         params = g_variant_new("(ss)", SUPPLICANT_IFACE_INTERFACE, "BSSs");
283
284         reply = netconfig_invoke_dbus_method_nonblock(SUPPLICANT_SERVICE,
285                         if_path, DBUS_INTERFACE_PROPERTIES,
286                         "Get", params, __netconfig_wifi_bssid_get_bss_result);
287
288         g_free(if_path);
289         if (reply != TRUE) {
290                 ERR("Fail to method: Get");
291
292                 return -ESRCH;
293         }
294
295         return 0;
296 }
297
298
299 static void __netconfig_set_bssid_scan_mode(gboolean enable)
300 {
301         if (netconfig_is_bssid_scan_started == enable)
302                 return;
303
304         netconfig_is_bssid_scan_started = enable;
305 }
306
307 void netconfig_wifi_bssid_signal_scandone(void)
308 {
309         bssid_list_count = 0;
310         _netconfig_wifi_bssid_get_bss();
311
312         netconfig_is_device_scanning = FALSE;
313
314         __netconfig_set_bssid_scan_mode(FALSE);
315 }
316
317 void netconfig_wifi_bssid_signal_scanaborted(void)
318 {
319         bssid_list_count = 0;
320         netconfig_is_bssid_scan_aborted = TRUE;
321         _netconfig_wifi_bssid_get_bss();
322
323         netconfig_is_device_scanning = FALSE;
324
325         __netconfig_set_bssid_scan_mode(FALSE);
326 }
327
328 static void __netconfig_wifi_bssid_scan_request_reply(GObject *source_object,
329                 GAsyncResult *res, gpointer user_data)
330 {
331         GVariant *message;
332         GDBusConnection *conn = NULL;
333         GError *error = NULL;
334
335         conn = G_DBUS_CONNECTION(source_object);
336         message = g_dbus_connection_call_finish(conn, res, &error);
337
338         if (message == NULL) {
339                 if (error != NULL) {
340                         ERR("Fail to request status [%d: %s]", error->code, error->message);
341                         g_error_free(error);
342                 } else {
343                         ERR("Fail to request bssid scan");
344                 }
345         } else {
346                 DBG("Successfully requested bssid scan");
347                 g_variant_unref(message);
348         }
349
350         netconfig_gdbus_pending_call_unref();
351 }
352
353 static int __netconfig_wifi_bssid_request_scan(char *if_path)
354 {
355         GVariant *message = NULL;
356         GVariantBuilder *builder = NULL;
357         const char *key1 = "Type";
358         const char *val1 = "passive";
359         gboolean is_free_required = FALSE;
360         gboolean reply = FALSE;
361
362         if (if_path == NULL) {
363                 if_path = netconfig_wifi_get_supplicant_interface();
364                 is_free_required = TRUE;
365         }
366
367         if (if_path == NULL) {
368                 DBG("Fail to get wpa_supplicant DBus path");
369                 goto out;
370         }
371
372         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
373         g_variant_builder_add(builder, "{sv}", key1, g_variant_new_string(val1));
374         message = g_variant_new("(@a{sv})", g_variant_builder_end(builder));
375         g_variant_builder_unref(builder);
376
377         DBG("[net-config]: TizenMW-->WPAS: .Interface.Scan");
378         reply = netconfig_supplicant_invoke_dbus_method_nonblock(
379                         SUPPLICANT_SERVICE,
380                         if_path,
381                         SUPPLICANT_INTERFACE ".Interface",
382                         "Scan",
383                         message,
384                         (GAsyncReadyCallback) __netconfig_wifi_bssid_scan_request_reply);
385
386         if (reply != TRUE) {
387                 ERR("Fail to Scan");
388                 goto out;
389         }
390
391         netconfig_is_device_scanning = TRUE;
392
393 out:
394         if (is_free_required)
395                 g_free(if_path);
396
397         /* Clear bss_info_list for the next scan result */
398         if (bssid_info_list) {
399                 g_slist_free_full(bssid_info_list, g_free);
400                 bssid_info_list = NULL;
401         }
402
403         netconfig_is_bssid_scan_aborted = FALSE;
404
405         return 0;
406 }
407
408 static void __netconfig_wifi_interface_create_result(
409                 GObject *source_object, GAsyncResult *res, gpointer user_data)
410 {
411         GVariant *message = NULL;
412         gchar *path = NULL;
413         GDBusConnection *conn = NULL;
414         GError *error = NULL;
415
416         conn = G_DBUS_CONNECTION(source_object);
417
418         message = g_dbus_connection_call_finish(conn, res, &error);
419         if (error == NULL) {
420                 g_variant_get(message, "(o)", &path);
421
422                 if (path) {
423                         __netconfig_wifi_bssid_request_scan(path);
424                         g_free(path);
425                 }
426         } else if (NULL != strstr(error->message, ".InterfaceExists")) {
427                 INFO("Error Message %s %s", error->message, path);
428                 g_variant_get(message, "(o)", &path);
429                 if (path) {
430                         __netconfig_wifi_bssid_request_scan(path);
431                         g_free(path);
432                 } else
433                         __netconfig_wifi_bssid_request_scan(NULL);
434
435                 g_error_free(error);
436         } else {
437                 ERR("Failed to create interface, Error: %d[%s]", error->code, error->message);
438                 __netconfig_set_bssid_scan_mode(FALSE);
439                 wifi_power_driver_and_supplicant(FALSE);
440                 g_error_free(error);
441         }
442
443         g_variant_unref(message);
444         netconfig_gdbus_pending_call_unref();
445 }
446
447 static int  __netconfig_wifi_bssid_create_interface(void)
448 {
449         GVariant *message = NULL;
450         GVariantBuilder *builder = NULL;
451         const char *key = "Ifname";
452         const char *val = WIFI_IFNAME;
453         gboolean reply = FALSE;
454
455         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
456         g_variant_builder_add(builder, "{sv}", key, g_variant_new_string(val));
457         message = g_variant_new("(@a{sv})", g_variant_builder_end(builder));
458         g_variant_builder_unref(builder);
459
460         DBG("[net-config]: TizenMW-->WPAS: CreateInterface");
461         reply = netconfig_supplicant_invoke_dbus_method_nonblock(
462                         SUPPLICANT_SERVICE,
463                         SUPPLICANT_PATH,
464                         SUPPLICANT_INTERFACE,
465                         "CreateInterface",
466                         message,
467                         (GAsyncReadyCallback) __netconfig_wifi_interface_create_result);
468
469         if (reply != TRUE)
470                 ERR("Fail to CreateInterface");
471
472         return 0;
473 }
474
475 static int __netconfig_wifi_bssid_scan(void)
476 {
477         int err = 0;
478         wifi_tech_state_e wifi_tech_state;
479
480         if (netconfig_is_device_scanning == TRUE)
481                 return -EINPROGRESS;
482
483         wifi_tech_state = wifi_state_get_technology_state();
484         if (wifi_tech_state <= NETCONFIG_WIFI_TECH_OFF)
485                 err = wifi_power_driver_and_supplicant(TRUE);
486
487         if (err < 0 && err != -EALREADY)
488                 return err;
489
490         netconfig_is_device_scanning = TRUE;
491
492         DBG("BSSID scan requested");
493         if (wifi_tech_state >= NETCONFIG_WIFI_TECH_POWERED) {
494                 if (netconfig_wifi_get_scanning() == TRUE)
495                         return -EINPROGRESS;
496
497                 netconfig_wifi_bgscan_start(TRUE);
498
499                 if (wifi_tech_state == NETCONFIG_WIFI_TECH_CONNECTED)
500                         __netconfig_wifi_bssid_request_scan(NULL);
501         } else {
502                 err = __netconfig_wifi_bssid_create_interface();
503         }
504
505         return err;
506 }
507
508 gboolean handle_request_bssid_scan(Wifi *wifi, GDBusMethodInvocation *context)
509 {
510         int err, enabled = 0;
511         wifi_tech_state_e tech_state;
512
513         g_return_val_if_fail(wifi != NULL, TRUE);
514
515         if (netconfig_is_wifi_tethering_on() == TRUE) {
516                 ERR("Wi-Fi Tethering is enabled");
517                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_NO_SERVICE, "TetheringEnabled");
518                 return TRUE;
519         }
520
521 #if !defined TIZEN_WEARABLE
522         if (netconfig_wifi_is_bgscan_paused()) {
523                 ERR("Scan is paused");
524                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_NO_SERVICE, "ScanPaused");
525                 return TRUE;
526         }
527 #endif
528
529         tech_state = wifi_state_get_technology_state();
530         if (tech_state <= NETCONFIG_WIFI_TECH_OFF) {
531 #if !defined TIZEN_WEARABLE
532                 enabled = 1;
533 #else
534                 enabled = 0;
535 #endif
536
537                 if (enabled == 0) {
538                         netconfig_error_permission_denied(context);
539                         return TRUE;
540                 }
541         }
542
543         __netconfig_set_bssid_scan_mode(TRUE);
544
545         err = __netconfig_wifi_bssid_scan();
546         if (err < 0) {
547                 if (err == -EINPROGRESS)
548                         netconfig_error_inprogress(context);
549                 else
550                         netconfig_error_wifi_driver_failed(context);
551
552                 return TRUE;
553         }
554
555         wifi_complete_request_bssid_scan(wifi, context);
556         return TRUE;
557 }
558
559 gboolean handle_get_bssid_list(Wifi *wifi, GDBusMethodInvocation *context)
560 {
561         _netconfig_wifi_bssid_get_bss();
562         wifi_complete_get_bssid_list(wifi, context);
563         return TRUE;
564 }