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