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