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