Handle Time update policy based on vconfkey value
[platform/core/connectivity/net-config.git] / src / wifi-scan.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2020 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 #include <vconf.h>
22 #include <vconf-keys.h>
23
24 #include "log.h"
25 #include "util.h"
26 #include "netdbus.h"
27 #include "wifi-state.h"
28 #include "wifi-scan.h"
29
30 typedef struct {
31         const char *interface_name;
32
33         /* background scan */
34         guint bg_exp_interval;
35         guint bg_periodic_interval;
36         guint bg_mode;
37         guint bg_timer_id;
38         gboolean bg_paused;
39
40         /* bssid scan*/
41         gboolean bssid_enabled;
42         gboolean bssid_aborted;
43         gboolean bssid_scanning;
44
45         /* scan */
46         gboolean scanning;
47 } scan_data_s;
48
49 static GSList *g_scan_list = NULL;
50
51 static scan_data_s *__wifi_scan_create_data(const char *interface_name)
52 {
53         scan_data_s *scan_data = g_try_malloc0(sizeof(scan_data_s));
54         if (!scan_data) {
55                 ERR("Memory allocation failed");
56                 return NULL;
57         }
58
59         scan_data->interface_name = g_strdup(interface_name);
60
61         scan_data->scanning = FALSE;
62
63         scan_data->bg_exp_interval = SCAN_EXPONENTIAL_MIN;
64         scan_data->bg_periodic_interval = SCAN_PERIODIC_DELAY;
65         scan_data->bg_mode = WIFI_BGSCAN_MODE_EXPONENTIAL;
66         scan_data->bg_timer_id = 0;
67         scan_data->bg_paused = FALSE;
68
69         scan_data->bssid_enabled = FALSE;
70         scan_data->bssid_aborted = FALSE;
71         scan_data->bssid_scanning = FALSE;
72
73         g_scan_list = g_slist_append(g_scan_list, scan_data);
74
75         return scan_data;
76 }
77
78 static scan_data_s *__wifi_scan_get_data(const char *interface_name)
79 {
80         GSList *list;
81         scan_data_s *scan_data;
82
83         for (list = g_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 = __wifi_scan_create_data(interface_name);
90         return scan_data;
91 }
92
93 void netconfig_wifi_scan_set_scanning(const char *interface_name, gboolean scanning)
94 {
95         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
96
97         if (!scan_data)
98                 return;
99
100         scan_data->scanning = scanning;
101 }
102
103 guint netconfig_wifi_scan_get_scanning(const char *interface_name)
104 {
105         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
106
107         if (!scan_data)
108                 return FALSE;
109
110         return scan_data->scanning;;
111 }
112
113 gboolean netconfig_wifi_bgscan_set_mode(const char *interface_name, guint mode)
114 {
115         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
116
117         if (!scan_data)
118                 return FALSE;
119
120         if (mode != WIFI_BGSCAN_MODE_EXPONENTIAL && mode != WIFI_BGSCAN_MODE_PERIODIC) {
121                 ERR("Invalid scan mode [%d]", mode);
122                 return FALSE;
123         }
124
125         scan_data->bg_mode = mode;
126
127         return TRUE;
128 }
129
130 guint netconfig_wifi_bgscan_get_mode(const char *interface_name)
131 {
132         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
133
134         if (!scan_data)
135                 return 0;
136
137         return scan_data->bg_mode;
138 }
139
140 guint netconfig_wifi_bgscan_get_periodic_interval(const char *interface_name)
141 {
142         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
143
144         if (!scan_data)
145                 return 0;
146
147         return scan_data->bg_periodic_interval;
148 }
149
150 gboolean netconfig_wifi_bgscan_set_periodic_interval(const char *interface_name, guint interval)
151 {
152         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
153
154         if (!scan_data)
155                 return FALSE;
156
157         if ((interval < SCAN_PERIODIC_DELAY_MIN) || (interval > SCAN_PERIODIC_DELAY_MAX)) {
158                 ERR("Invalid interval [%d]", interval);
159                 return FALSE;
160         }
161
162         scan_data->bg_periodic_interval = interval;
163
164         return TRUE;
165 }
166
167 void netconfig_wifi_bgscan_set_timer_id(const char *interface_name, guint timer_id)
168 {
169         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
170
171         if (!scan_data)
172                 return;
173
174         scan_data->bg_timer_id = timer_id;
175 }
176
177 guint netconfig_wifi_bgscan_get_timer_id(const char *interface_name)
178 {
179         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
180
181         if (!scan_data)
182                 return 0;
183
184         return scan_data->bg_timer_id;
185 }
186
187 gboolean netconfig_wifi_bgscan_set_exp_interval(const char *interface_name, guint interval)
188 {
189         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
190
191         if (!scan_data)
192                 return FALSE;
193
194         if ((interval < SCAN_EXPONENTIAL_MIN) || (interval > SCAN_EXPONENTIAL_MAX)) {
195                 ERR("Invalid interval [%d]", interval);
196                 return FALSE;
197         }
198
199         scan_data->bg_exp_interval = interval;
200
201         return TRUE;
202 }
203
204 guint netconfig_wifi_bgscan_get_exp_interval(const char *interface_name)
205 {
206         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
207
208         if (!scan_data)
209                 return SCAN_EXPONENTIAL_MIN;
210
211         return scan_data->bg_exp_interval;
212 }
213
214 void netconfig_wifi_bgscan_set_pause(const char *interface_name, gboolean pause)
215 {
216         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
217         if (!scan_data)
218                 return;
219
220         scan_data->bg_paused = pause;
221
222         DBG("[%s] Wi-Fi background scan [%s]", interface_name,
223                         pause ? "Pause" : "Resume");
224 }
225
226 gboolean netconfig_wifi_bgscan_is_paused(const char *interface_name)
227 {
228         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
229         if (!scan_data)
230                 return FALSE;
231
232         DBG("[%s] Wi-Fi background scan is [%s]", interface_name,
233                         scan_data->bg_paused ? "Paused" : "Runnable");
234
235         return scan_data->bg_paused;
236 }
237
238 static void __wifi_scan_request_reply(GObject *source_object,
239                 GAsyncResult *res, gpointer user_data)
240 {
241         GVariant *reply;
242         GDBusConnection *conn = NULL;
243         GError *error = NULL;
244         char *interface_name = user_data;
245
246         conn = G_DBUS_CONNECTION(source_object);
247         reply = g_dbus_connection_call_finish(conn, res, &error);
248
249         if (reply == NULL) {
250                 if (error != NULL) {
251                         ERR("Fail to request status [%d: %s]", error->code, error->message);
252                         netconfig_wifi_scan_set_scanning(interface_name, FALSE);
253                         g_error_free(error);
254                 } else {
255                         ERR("Fail to request scan");
256                         netconfig_wifi_scan_set_scanning(interface_name, FALSE);
257                 }
258         } else {
259                 DBG("Successfully requested");
260                 g_variant_unref(reply);
261         }
262
263         netconfig_gdbus_pending_call_unref();
264         g_free(interface_name);
265 }
266
267 static gboolean __wifi_scan_request_connman_scan(const char *interface_name)
268 {
269         GVariant *params = NULL;
270         gboolean reply = FALSE;
271
272         netconfig_wifi_scan_set_scanning(interface_name, TRUE);
273
274         params = g_variant_new("(s)", interface_name);
275
276         reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
277                         CONNMAN_WIFI_TECHNOLOGY_PREFIX,
278                         CONNMAN_TECHNOLOGY_INTERFACE, "ScanDevice", params,
279                         __wifi_scan_request_reply, g_strdup(interface_name));
280         if (reply != TRUE) {
281                 ERR("Failed to send Scan request to connman");
282                 netconfig_wifi_scan_set_scanning(interface_name, FALSE);
283         }
284
285         return reply;
286 }
287
288 static gboolean __wifi_bgscan_immediate_scan(gpointer data)
289 {
290         static int retries = 0;
291         scan_data_s *scan_data = data;
292         guint state = 0;
293         int ug_state = VCONFKEY_WIFI_UG_RUN_STATE_OFF;
294         guint bg_mode = WIFI_BGSCAN_MODE_EXPONENTIAL;
295
296         if (!scan_data)
297                 return FALSE;
298
299         netconfig_vconf_get_int(VCONFKEY_WIFI_UG_RUN_STATE, &ug_state);
300
301         state = wifi_state_get_service_state(scan_data->interface_name);
302
303 #if !defined TIZEN_WEARABLE
304         if (netconfig_wifi_bgscan_is_paused(scan_data->interface_name)) {
305                 return FALSE;
306         }
307 #endif
308
309         if (state == NETCONFIG_WIFI_CONNECTED) {
310                 bg_mode = netconfig_wifi_bgscan_get_mode(scan_data->interface_name);
311                 if (bg_mode == WIFI_BGSCAN_MODE_EXPONENTIAL ||
312                                 (bg_mode == WIFI_BGSCAN_MODE_PERIODIC &&
313                                  ug_state != VCONFKEY_WIFI_UG_RUN_STATE_ON_FOREGROUND)) {
314                         DBG("[%s] Wi-Fi state is connected, scan is paused", scan_data->interface_name);
315                         return FALSE;
316                 }
317         } else if (state == NETCONFIG_WIFI_ASSOCIATION || state == NETCONFIG_WIFI_CONFIGURATION) {
318                 /* During WIFI connecting, WIFI can be disappeared.
319                  * After 1 sec, try scan even if connecting state */
320                 if (retries < 2) {
321                         retries++;
322                         return TRUE;
323                 }
324         }
325
326         if (__wifi_scan_request_connman_scan(scan_data->interface_name) == TRUE) {
327                 retries = 0;
328                 return FALSE;
329         } else if (retries > 2) {
330                 retries = 0;
331                 return FALSE;
332         }
333
334         retries++;
335
336         return TRUE;
337 }
338
339 static gboolean __wifi_bgscan_next_scan(gpointer data)
340 {
341         int pm_state = VCONFKEY_PM_STATE_NORMAL;
342         scan_data_s *scan_data = data;
343
344         if (!scan_data)
345                 return FALSE;
346
347         if (scan_data->bg_mode == WIFI_BGSCAN_MODE_EXPONENTIAL) {
348                 scan_data->bg_exp_interval = scan_data->bg_exp_interval * 2;
349                 if (scan_data->bg_exp_interval > SCAN_EXPONENTIAL_MAX)
350                         scan_data->bg_exp_interval = SCAN_EXPONENTIAL_MAX;
351         }
352
353         /* In case of LCD off, we don't need Wi-Fi scan */
354         netconfig_vconf_get_int(VCONFKEY_PM_STATE, &pm_state);
355         if (pm_state >= VCONFKEY_PM_STATE_LCDOFF)
356                 return TRUE;
357
358         netconfig_wifi_bgscan_start_timer(scan_data->interface_name, TRUE);
359
360         return FALSE;
361 }
362
363 void netconfig_wifi_bgscan_start_timer(const char *interface_name, gboolean immediate_scan)
364 {
365         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
366         guint bg_interval = 0;
367
368         if (!scan_data)
369                 return;
370
371         netconfig_stop_timer(&(scan_data->bg_timer_id));
372
373         switch (scan_data->bg_mode) {
374         case WIFI_BGSCAN_MODE_EXPONENTIAL:
375                 if (scan_data->bg_exp_interval < SCAN_EXPONENTIAL_MIN)
376                         scan_data->bg_exp_interval = SCAN_EXPONENTIAL_MIN;
377
378                 bg_interval = scan_data->bg_exp_interval;
379                 break;
380         case WIFI_BGSCAN_MODE_PERIODIC:
381                 bg_interval = scan_data->bg_periodic_interval;
382                 break;
383         default:
384                 DBG("Invalid Wi-Fi background scan mode[%d]", scan_data->bg_mode);
385                 return;
386         }
387
388         if (immediate_scan)
389                 DBG("[%s] Scan immediately[%d], mode[%d](0 exponential / 1 periodic), next[%d]",
390                         interface_name, immediate_scan, scan_data->bg_mode, bg_interval);
391         else
392                 DBG("[%s] Scan immediately[%d], mode[%d](0 exponential / 1 periodic), next[%d]",
393                         interface_name, immediate_scan, scan_data->bg_mode, bg_interval);
394
395         if (immediate_scan)
396                 g_timeout_add(500, __wifi_bgscan_immediate_scan, scan_data);
397
398         netconfig_start_timer_seconds(bg_interval,
399                 __wifi_bgscan_next_scan, scan_data, &(scan_data->bg_timer_id));
400
401 }
402
403 void netconfig_wifi_bgscan_stop_timer(const char *interface_name)
404 {
405         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
406
407         if (scan_data)
408                 return;
409
410         netconfig_stop_timer(&(scan_data->bg_timer_id));
411 }
412
413 void netconfig_wifi_bssidscan_set_mode(const char *interface_name, gboolean enable)
414 {
415         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
416         if (!scan_data)
417                 return;
418
419         scan_data->bssid_enabled = enable;
420 }
421
422 gboolean netconfig_wifi_bssidscan_get_mode(const char *interface_name)
423 {
424         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
425         if (!scan_data)
426                 return FALSE;
427
428         return scan_data->bssid_enabled;
429 }
430
431 void netconfig_wifi_bssidscan_set_aborted(const char *interface_name, gboolean abort)
432 {
433         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
434         if (!scan_data)
435                 return;
436
437         scan_data->bssid_aborted = abort;
438 }
439
440 gboolean netconfig_wifi_bssidscan_get_aborted(const char *interface_name)
441 {
442         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
443         if (!scan_data)
444                 return FALSE;
445
446         return scan_data->bssid_aborted;
447 }
448
449 void netconfig_wifi_bssidscan_set_scanning(const char *interface_name, gboolean scanning)
450 {
451         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
452
453         if (!scan_data)
454                 return;
455
456         scan_data->bssid_scanning = scanning;
457 }
458
459 guint netconfig_wifi_bssidscan_get_scanning(const char *interface_name)
460 {
461         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
462
463         if (!scan_data)
464                 return FALSE;
465
466         return scan_data->bssid_scanning;;
467 }