Revise background scan routine
[platform/core/connectivity/net-config.git] / src / wifi-background-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 #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-background-scan.h"
29
30 struct bgscan_data {
31         guint time;
32         guint mode;
33         guint timer_id;
34         gboolean paused;
35 };
36
37 static gboolean netconfig_wifi_scanning = FALSE;
38
39 static gboolean __netconfig_wifi_bgscan_next_scan(gpointer data);
40
41 static struct bgscan_data *__netconfig_wifi_bgscan_get_data(void)
42 {
43         static struct bgscan_data data = {
44                 SCAN_EXPONENTIAL_MIN, WIFI_BGSCAN_MODE_EXPONENTIAL, 0, FALSE};
45
46         return &data;
47 }
48
49 static gboolean __netconfig_wifi_bgscan_set_mode(guint mode)
50 {
51         if (mode != WIFI_BGSCAN_MODE_EXPONENTIAL && mode != WIFI_BGSCAN_MODE_PERIODIC) {
52                 ERR("Invalid scan mode [%d]", mode);
53                 return FALSE;
54         }
55
56         struct bgscan_data *data = __netconfig_wifi_bgscan_get_data();
57         data->mode = mode;
58
59         return TRUE;
60 }
61
62 static gboolean _set_scan_reset_interval(guint interval)
63 {
64         if ((interval < SCAN_EXPONENTIAL_MIN) || (interval > SCAN_EXPONENTIAL_MAX)) {
65                 ERR("Invalid interval [%d]", interval);
66                 return FALSE;
67         }
68
69         struct bgscan_data *data = __netconfig_wifi_bgscan_get_data();
70         data->time = interval;
71         return TRUE;
72 }
73
74 static guint _get_scan_reset_interval(void)
75 {
76         struct bgscan_data *data = __netconfig_wifi_bgscan_get_data();
77
78         return data->time;;
79 }
80
81 static void __netconfig_wifi_scan_request_reply(GObject *source_object,
82                 GAsyncResult *res, gpointer user_data)
83 {
84         GVariant *reply;
85         GDBusConnection *conn = NULL;
86         GError *error = NULL;
87
88         conn = G_DBUS_CONNECTION(source_object);
89         reply = g_dbus_connection_call_finish(conn, res, &error);
90
91         if (reply == NULL) {
92                 if (error != NULL) {
93                         ERR("Fail to request status [%d: %s]", error->code, error->message);
94                         netconfig_wifi_set_scanning(FALSE);
95                         g_error_free(error);
96                 } else {
97                         ERR("Fail to request scan");
98                         netconfig_wifi_set_scanning(FALSE);
99                 }
100         } else {
101                 DBG("Successfully requested");
102                 g_variant_unref(reply);
103         }
104
105         netconfig_gdbus_pending_call_unref();
106 }
107
108 static gboolean __netconfig_wifi_bgscan_request_connman_scan(int retries)
109 {
110         gboolean reply = FALSE;
111
112         netconfig_wifi_set_scanning(TRUE);
113
114         reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
115                         CONNMAN_WIFI_TECHNOLOGY_PREFIX,
116                         CONNMAN_TECHNOLOGY_INTERFACE, "Scan", NULL, __netconfig_wifi_scan_request_reply);
117         if (reply != TRUE) {
118                 ERR("Failed to send Scan request to connman");
119                 netconfig_wifi_set_scanning(FALSE);
120         }
121
122         return reply;
123 }
124
125 static gboolean __netconfig_wifi_bgscan_immediate_scan(gpointer data)
126 {
127         static int retries = 0;
128         guint state = wifi_state_get_service_state();
129
130 #if !defined TIZEN_WEARABLE
131         if (netconfig_wifi_is_bgscan_paused()) {
132                 return FALSE;
133         }
134 #endif
135
136         if (state == NETCONFIG_WIFI_CONNECTED) {
137                 if (netconfig_wifi_bgscan_get_mode() == WIFI_BGSCAN_MODE_EXPONENTIAL) {
138                         DBG("Wi-Fi state is connected, scan is paused");
139                         return FALSE;
140                 }
141         } else if (state == NETCONFIG_WIFI_ASSOCIATION || state == NETCONFIG_WIFI_CONFIGURATION) {
142                 /* During WIFI connecting, WIFI can be disappeared.
143                  * After 1 sec, try scan even if connecting state */
144                 if (retries < 2) {
145                         retries++;
146                         return TRUE;
147                 }
148         }
149
150         if (__netconfig_wifi_bgscan_request_connman_scan(retries) == TRUE) {
151                 retries = 0;
152                 return FALSE;
153         } else if (retries > 2) {
154                 retries = 0;
155                 return FALSE;
156         }
157
158         retries++;
159
160         return TRUE;
161 }
162
163 static void __netconfig_wifi_bgscan_start_timer(gboolean immediate_scan)
164 {
165         struct bgscan_data *data = __netconfig_wifi_bgscan_get_data();
166
167         netconfig_stop_timer(&(data->timer_id));
168
169         switch (data->mode) {
170         case WIFI_BGSCAN_MODE_EXPONENTIAL:
171                 if (data->time < SCAN_EXPONENTIAL_MIN ||
172                         data->time == SCAN_PERIODIC_DELAY)
173                         data->time = SCAN_EXPONENTIAL_MIN;
174                 break;
175         case WIFI_BGSCAN_MODE_PERIODIC:
176                 data->time = SCAN_PERIODIC_DELAY;
177                 break;
178         default:
179                 DBG("Invalid Wi-Fi background scan mode[%d]", data->mode);
180                 return;
181         }
182
183         if (immediate_scan)
184                 DBG("Scan immediately[%d], mode[%d](0 exponential / 1 periodic)", immediate_scan, data->mode);
185         else
186                 DBG("Scan immediately[%d], mode[%d](0 exponential / 1 periodic), next[%d]", immediate_scan, data->mode, data->time);
187
188         if (immediate_scan)
189                 g_timeout_add(500, __netconfig_wifi_bgscan_immediate_scan, NULL);
190
191         netconfig_start_timer_seconds(data->time,
192                                 __netconfig_wifi_bgscan_next_scan, data, &(data->timer_id));
193         if (data->mode == WIFI_BGSCAN_MODE_EXPONENTIAL && immediate_scan) {
194                 data->time = data->time * 2;
195                 if (data->time > SCAN_EXPONENTIAL_MAX)
196                         data->time = SCAN_EXPONENTIAL_MAX;
197         }
198
199         //DBG("Scan immediately[%d], mode[%d](0 exponential / 1 periodic), next[%d]", immediate_scan, data->mode, data->time);
200 }
201
202 static void __netconfig_wifi_bgscan_stop_timer(struct bgscan_data *data)
203 {
204         if (data == NULL)
205                 return;
206
207         netconfig_stop_timer(&(data->timer_id));
208 }
209
210 static gboolean __netconfig_wifi_bgscan_next_scan(gpointer data)
211 {
212         int pm_state = VCONFKEY_PM_STATE_NORMAL;
213
214         /* In case of LCD off, we don't need Wi-Fi scan */
215         netconfig_vconf_get_int(VCONFKEY_PM_STATE, &pm_state);
216         if (pm_state >= VCONFKEY_PM_STATE_LCDOFF)
217                 return TRUE;
218
219         __netconfig_wifi_bgscan_start_timer(TRUE);
220
221         return FALSE;
222 }
223
224 void netconfig_wifi_set_bgscan_pause(gboolean pause)
225 {
226         struct bgscan_data *data = __netconfig_wifi_bgscan_get_data();
227         DBG("[%s] Wi-Fi background scan", pause ? "Pause" : "Resume");
228         data->paused = pause;
229 }
230
231 gboolean netconfig_wifi_is_bgscan_paused(void)
232 {
233         struct bgscan_data *data = __netconfig_wifi_bgscan_get_data();
234         DBG("Wi-Fi background scan is [%s]", data->paused ? "Paused" : "Runnable");
235         return data->paused;
236 }
237
238 void netconfig_wifi_bgscan_start(gboolean immediate_scan)
239 {
240         wifi_tech_state_e wifi_tech_state;
241         wifi_service_state_e wifi_service_state;
242         struct bgscan_data *data =
243                         __netconfig_wifi_bgscan_get_data();
244
245         if (data == NULL)
246                 return;
247
248         if (data->timer_id > 0)
249                 __netconfig_wifi_bgscan_stop_timer(data);
250
251         wifi_tech_state = wifi_state_get_technology_state();
252         wifi_service_state = wifi_state_get_service_state();
253         DBG("wifi tech state [%s] service state [%s]",
254                 _convert_wifi_technology_state_to_string(wifi_tech_state),
255                 _convert_wifi_service_state_to_string(wifi_service_state));
256
257         if (wifi_tech_state < NETCONFIG_WIFI_TECH_POWERED)
258                 return;
259
260         if (data->mode == WIFI_BGSCAN_MODE_EXPONENTIAL &&
261                 wifi_service_state == NETCONFIG_WIFI_CONNECTED)
262                 return;
263
264         DBG("Wi-Fi background scan started or re-started(%d)", immediate_scan);
265         __netconfig_wifi_bgscan_start_timer(immediate_scan);
266 }
267
268 void netconfig_wifi_bgscan_stop(void)
269 {
270         struct bgscan_data *data =
271                         __netconfig_wifi_bgscan_get_data();
272
273         if (data == NULL)
274                 return;
275
276         DBG("Wi-Fi background scan stop [mode:%d]", data->mode);
277
278         data->time = 0;
279
280         __netconfig_wifi_bgscan_stop_timer(data);
281 }
282
283 gboolean netconfig_wifi_get_bgscan_state(void)
284 {
285         struct bgscan_data *data =
286                         __netconfig_wifi_bgscan_get_data();
287         return ((data->timer_id > (guint)0) ? TRUE : FALSE);
288 }
289
290 guint netconfig_wifi_bgscan_get_mode(void)
291 {
292         struct bgscan_data *data = __netconfig_wifi_bgscan_get_data();
293
294         return data->mode;
295 }
296
297 gboolean netconfig_wifi_bgscan_set_interval(guint interval)
298 {
299         gboolean ret = FALSE;
300
301         ret = _set_scan_reset_interval(interval);
302
303         return ret;
304 }
305
306 void netconfig_wifi_bgscan_get_interval(guint *interval)
307 {
308         *interval = _get_scan_reset_interval();
309 }
310
311 gboolean netconfig_wifi_get_scanning(void)
312 {
313         return netconfig_wifi_scanning;
314 }
315
316 void netconfig_wifi_set_scanning(gboolean scanning)
317 {
318         if (netconfig_wifi_scanning != scanning)
319                 netconfig_wifi_scanning = scanning;
320 }
321
322 gboolean handle_set_bgscan(Wifi *wifi, GDBusMethodInvocation *context, guint scan_mode)
323 {
324         gint old_mode = 0;
325         int pm_state = VCONFKEY_PM_STATE_NORMAL;
326
327         old_mode = netconfig_wifi_bgscan_get_mode();
328         if (old_mode == scan_mode) {
329                 wifi_complete_set_bgscan(wifi, context);
330                 return TRUE;
331         }
332
333         if (__netconfig_wifi_bgscan_set_mode(scan_mode) != TRUE) {
334                 ERR("Invalid mode [%d]", scan_mode);
335                 netconfig_error_invalid_parameter(context);
336                 return TRUE;
337         }
338
339         INFO("scan mode is changed [%d]", scan_mode);
340
341         /* In case of LCD off, we don't need Wi-Fi scan right now */
342         netconfig_vconf_get_int(VCONFKEY_PM_STATE, &pm_state);
343         if (pm_state >= VCONFKEY_PM_STATE_LCDOFF)
344                 netconfig_wifi_bgscan_start(FALSE);
345         else
346                 netconfig_wifi_bgscan_start(TRUE);
347
348         wifi_complete_set_bgscan(wifi, context);
349         return TRUE;
350 }
351
352 gboolean handle_resume_bgscan(Wifi *wifi, GDBusMethodInvocation *context)
353 {
354         netconfig_wifi_set_bgscan_pause(FALSE);
355
356         wifi_complete_resume_bgscan(wifi, context);
357         return TRUE;
358 }
359
360 gboolean handle_pause_bgscan(Wifi *wifi, GDBusMethodInvocation *context)
361 {
362         netconfig_wifi_set_bgscan_pause(TRUE);
363
364         wifi_complete_pause_bgscan(wifi, context);
365         return TRUE;
366 }
367
368 gboolean handle_reset_bgscan_interval(Wifi *wifi, GDBusMethodInvocation *context)
369 {
370
371         _set_scan_reset_interval(SCAN_EXPONENTIAL_MIN);
372
373         wifi_complete_reset_bgscan_interval(wifi, context);
374         return TRUE;
375 }
376
377 gboolean handle_get_autoscan(Wifi *wifi, GDBusMethodInvocation *context)
378 {
379
380         gboolean autoscan = 0;
381
382         autoscan = netconfig_wifi_is_bgscan_paused();
383
384         wifi_complete_get_autoscan(wifi, context, autoscan);
385         return TRUE;
386 }
387
388 gboolean handle_get_autoscanmode(Wifi *wifi, GDBusMethodInvocation *context)
389 {
390         guint autoscanmode = 0;
391
392         autoscanmode = netconfig_wifi_bgscan_get_mode();
393
394         wifi_complete_get_autoscanmode(wifi, context, autoscanmode);
395         return TRUE;
396 }
397