Initialize Tizen 2.3
[framework/connectivity/net-config.git] / mobile / src / wifi-power.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2012-2013 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 <stdio.h>
21 #include <unistd.h>
22 #include <vconf.h>
23 #include <vconf-keys.h>
24 #include <wifi-direct.h>
25
26 #include "wifi.h"
27 #include "log.h"
28 #include "wifi.h"
29 #include "util.h"
30 #include "netdbus.h"
31 #include "neterror.h"
32 #include "netconfig.h"
33 #include "emulator.h"
34 #include "network-statistics.h"
35 #include "wifi-background-scan.h"
36 #include "wifi-power.h"
37 #include "wifi-state.h"
38 #include "wifi-agent.h"
39 #include "wifi-eap-config.h"
40
41
42 #define WLAN_DRIVER_SCRIPT "/usr/bin/wlan.sh"
43
44 static gboolean power_in_progress = FALSE;
45 static gboolean fm_waiting = FALSE;
46
47 static void __netconfig_wifi_technology_reply(DBusPendingCall *call, void *data)
48 {
49         DBusMessage *message;
50
51         message = dbus_pending_call_steal_reply(call);
52
53         if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
54                 ERR("%s", dbus_message_get_error_name(message));
55
56                 if (dbus_message_is_error(message,
57                                 CONNMAN_ERROR_INTERFACE ".AlreadyEnabled") == TRUE) {
58                         netconfig_wifi_update_power_state(TRUE);
59                         power_in_progress = FALSE;
60                 } else if (dbus_message_is_error(message,
61                                 CONNMAN_ERROR_INTERFACE ".AlreadyDisabled") == TRUE) {
62                         netconfig_wifi_update_power_state(FALSE);
63                         power_in_progress = FALSE;
64                 }
65         } else {
66                 DBG("Successfully requested");
67         }
68
69         dbus_message_unref(message);
70         dbus_pending_call_unref(call);
71 }
72
73 static gboolean __netconfig_wifi_enable_technology(void)
74 {
75         gboolean reply = FALSE;
76         char param0[] = "string:Powered";
77         char param1[] = "variant:boolean:true";
78         char *param_array[] = { NULL, NULL, NULL };
79
80         param_array[0] = param0;
81         param_array[1] = param1;
82
83         reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
84                         CONNMAN_WIFI_TECHNOLOGY_PREFIX, CONNMAN_TECHNOLOGY_INTERFACE,
85                         "SetProperty", param_array, __netconfig_wifi_technology_reply);
86
87         if (reply != TRUE)
88                 ERR("Fail to enable Wi-Fi");
89
90         return reply;
91 }
92
93 static gboolean __netconfig_wifi_disable_technology(void)
94 {
95         gboolean reply = FALSE;
96         char param0[] = "string:Powered";
97         char param1[] = "variant:boolean:false";
98         char *param_array[] = { NULL, NULL, NULL };
99
100         param_array[0] = param0;
101         param_array[1] = param1;
102
103         reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
104                         CONNMAN_WIFI_TECHNOLOGY_PREFIX, CONNMAN_TECHNOLOGY_INTERFACE,
105                         "SetProperty", param_array, __netconfig_wifi_technology_reply);
106
107         if (reply != TRUE)
108                 ERR("Fail to disable Wi-Fi");
109
110         return reply;
111 }
112
113 static gboolean __netconfig_wifi_load_driver(void)
114 {
115         gboolean rv = FALSE;
116         const char *path = WLAN_DRIVER_SCRIPT;
117         char *const args[] = { "wlan.sh", "start", NULL };
118         char *const envs[] = { NULL };
119
120         if (netconfig_emulator_is_emulated() == TRUE)
121                 return rv;
122
123         rv = netconfig_execute_file(path, args, envs);
124         if (rv != TRUE) {
125                 DBG("Failed to load wireless device driver");
126                 return FALSE;
127         }
128
129         DBG("Successfully loaded wireless device driver");
130         return TRUE;
131 }
132
133 gboolean netconfig_wifi_remove_driver(void)
134 {
135         gboolean rv = FALSE;
136         const char *path = WLAN_DRIVER_SCRIPT;
137         char *const args[] = { "wlan.sh", "stop", NULL };
138         char *const env[] = { NULL };
139
140         if (netconfig_emulator_is_emulated() == TRUE)
141                 return rv;
142
143         rv = netconfig_execute_file(path, args, env);
144         if (rv != TRUE) {
145                 DBG("Failed to remove wireless device driver");
146                 return FALSE;
147         }
148
149         DBG("Successfully removed wireless device driver");
150         return TRUE;
151 }
152
153 static int __netconfig_wifi_try_to_load_driver(void);
154 static gboolean __netconfig_wifi_try_to_remove_driver(void);
155
156 void netconfig_wifi_notify_power_completed(gboolean power_on)
157 {
158         DBusMessage *signal;
159         DBusConnection *connection;
160         DBusError error;
161         char *sig_name;
162
163         if (power_on)
164                 sig_name = "PowerOnCompleted";
165         else
166                 sig_name = "PowerOffCompleted";
167
168         dbus_error_init(&error);
169
170         connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
171         if (connection == NULL) {
172                 ERR("Error!!! Failed to get system DBus, error [%s]", error.message);
173                 dbus_error_free(&error);
174                 return;
175         }
176
177         signal = dbus_message_new_signal(NETCONFIG_WIFI_PATH,
178                                         NETCONFIG_WIFI_INTERFACE, sig_name);
179         if (signal == NULL)
180                 return;
181
182         dbus_connection_send(connection, signal, NULL);
183
184         dbus_message_unref(signal);
185         dbus_connection_unref(connection);
186
187         INFO("(%s)", sig_name);
188 }
189
190 static void __netconfig_wifi_direct_state_cb(int error_code,
191                 wifi_direct_device_state_e device_state, void *user_data)
192 {
193         wifi_direct_unset_device_state_changed_cb();
194         wifi_direct_deinitialize();
195
196         if (device_state == WIFI_DIRECT_DEVICE_STATE_DEACTIVATED) {
197                 if (__netconfig_wifi_try_to_load_driver() < 0) {
198                         power_in_progress = FALSE;
199
200                         /* TODO: error report */
201
202                         return;
203                 }
204         }
205 }
206
207 static gboolean __netconfig_wifi_direct_power_off(void)
208 {
209         DBG("Wi-Fi direct is turning off");
210
211         if (wifi_direct_initialize() < 0)
212                 return FALSE;
213
214         if (wifi_direct_set_device_state_changed_cb(
215                         __netconfig_wifi_direct_state_cb, NULL) < 0)
216                 return FALSE;
217
218         if (wifi_direct_deactivate() < 0)
219                 return FALSE;
220
221         return TRUE;
222 }
223
224 gboolean netconfig_is_wifi_allowed(void)
225 {
226         return TRUE;
227 }
228
229 static int __netconfig_wifi_try_to_load_driver(void)
230 {
231         if (netconfig_is_wifi_allowed() != TRUE)
232                 return -EPERM;
233
234         if (netconfig_is_wifi_tethering_on() == TRUE) {
235                 /* TODO: Wi-Fi tethering turns off here */
236                 /* return TRUE; */
237                 return -EBUSY;
238         }
239
240         if (netconfig_is_wifi_direct_on() == TRUE) {
241                 if (__netconfig_wifi_direct_power_off() == TRUE) {
242                         power_in_progress = TRUE;
243                         return -EINPROGRESS;
244                 } else
245                         return -EBUSY;
246         }
247
248         if (__netconfig_wifi_load_driver() != TRUE) {
249                 netconfig_wifi_remove_driver();
250
251                 return -EIO;
252         }
253
254         if (__netconfig_wifi_enable_technology() != TRUE) {
255                 netconfig_wifi_remove_driver();
256                 return -EIO;
257         }
258
259         power_in_progress = TRUE;
260
261         return 0;
262 }
263
264 static gboolean __netconfig_wifi_try_to_remove_driver(void)
265 {
266         netconfig_wifi_device_picker_service_stop();
267
268         netconfig_wifi_statistics_update_powered_off();
269
270         if (__netconfig_wifi_disable_technology() != TRUE)
271                 return FALSE;
272
273         power_in_progress = TRUE;
274
275         return TRUE;
276 }
277
278 static void __netconfig_wifi_airplane_mode(keynode_t* node,
279                 void* user_data)
280 {
281         int value = 0;
282         int wifi_state = 0;
283         static gboolean powered_off_by_flightmode = FALSE;
284
285         if (power_in_progress) {
286                 fm_waiting = TRUE;
287                 return;
288         }
289
290         fm_waiting = FALSE;
291
292         vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &value);
293         vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
294
295         DBG("flight mode %s", value > 0 ? "ON" : "OFF");
296         DBG("Wi-Fi state %d, Wi-Fi was off by flight mode %s",
297                         wifi_state, powered_off_by_flightmode == TRUE ? "Yes" : "No");
298
299         if (value > 0) {
300                 /* flight mode enabled */
301                 if (wifi_state == VCONFKEY_WIFI_OFF)
302                         return;
303
304                 DBG("Turning Wi-Fi off");
305
306                 __netconfig_wifi_try_to_remove_driver();
307
308                 powered_off_by_flightmode = TRUE;
309         } else if (value == 0) {
310                 /* flight mode disabled */
311                 if (wifi_state > VCONFKEY_WIFI_OFF)
312                         return;
313
314                 if (powered_off_by_flightmode != TRUE)
315                         return;
316
317                 __netconfig_wifi_try_to_load_driver();
318
319                 powered_off_by_flightmode = FALSE;
320         } else
321                 DBG("Invalid value (%d)", value);
322 }
323
324 static void __netconfig_wifi_pm_state_mode(keynode_t* node,
325                 void* user_data)
326 {
327         int value = -1;
328         int wifi_state = 0;
329         static int prev_state = VCONFKEY_PM_STATE_NORMAL;
330
331         /*** vconf-keys.h ***
332          *              VCONFKEY_PM_STATE_NORMAL = 1,
333          *              VCONFKEY_PM_STATE_LCDDIM,
334          *              VCONFKEY_PM_STATE_LCDOFF,
335          *              VCONFKEY_PM_STATE_SLEEP
336          */
337
338         if(vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state) == 0) {
339                 DBG("wifi state : %d (0 off / 1 on / 2 connected)", wifi_state);
340                 if(wifi_state <= VCONFKEY_WIFI_OFF)
341                         return;
342         }
343
344         if(vconf_get_int(VCONFKEY_PM_STATE, &value) < 0) {
345                 ERR("VCONFKEY_PM_STATE get failed");
346                 return;
347         }
348
349         DBG("Old state: %d, current: %d", prev_state, value);
350
351         if((value == VCONFKEY_PM_STATE_NORMAL) && (prev_state >= VCONFKEY_PM_STATE_LCDOFF)) {
352                 DBG("PM state : Wake UP!");
353
354                 netconfig_wifi_bgscan_stop();
355                 netconfig_wifi_bgscan_start();
356         }
357
358         prev_state = value;
359 }
360
361 void netconfig_set_power_in_progress(gboolean in_progress)
362 {
363         power_in_progress = in_progress;
364 }
365
366 void netconfig_check_fm_waiting(void)
367 {
368         if (fm_waiting)
369                 __netconfig_wifi_airplane_mode(NULL, NULL);
370 }
371
372 void netconfig_wifi_power_configuration(void)
373 {
374         int wifi_last_power_state = 0;
375
376         vconf_notify_key_changed(VCONFKEY_TELEPHONY_FLIGHT_MODE,
377                         __netconfig_wifi_airplane_mode, NULL);
378
379         vconf_notify_key_changed(VCONFKEY_PM_STATE,
380                         __netconfig_wifi_pm_state_mode, NULL);
381
382         vconf_get_int(VCONF_WIFI_LAST_POWER_STATE, &wifi_last_power_state);
383
384         if (wifi_last_power_state == WIFI_POWER_ON) {
385                 DBG("Turn Wi-Fi on automatically");
386
387                 __netconfig_wifi_try_to_load_driver();
388         }
389 }
390
391 gboolean netconfig_iface_wifi_load_driver(NetconfigWifi *wifi, GError **error)
392 {
393         DBG("Wi-Fi power on requested");
394
395         g_return_val_if_fail(wifi != NULL, FALSE);
396
397         int err;
398
399         if (netconfig_is_wifi_allowed() != TRUE) {
400                 netconfig_error_security_restricted(error);
401
402                 return FALSE;
403         }
404
405         if (power_in_progress) {
406                 netconfig_error_wifi_driver_failed(error);
407                 return FALSE;
408         }
409
410         err = __netconfig_wifi_try_to_load_driver();
411         if (err < 0) {
412                 if (err == -EINPROGRESS)
413                         netconfig_error_wifi_load_inprogress(error);
414                 else
415                         netconfig_error_wifi_driver_failed(error);
416
417                 return FALSE;
418         }
419
420         return TRUE;
421 }
422
423 gboolean netconfig_iface_wifi_remove_driver(NetconfigWifi *wifi, GError **error)
424 {
425         DBG("Wi-Fi power off requested");
426
427         g_return_val_if_fail(wifi != NULL, FALSE);
428
429         if (power_in_progress) {
430                 netconfig_error_wifi_driver_failed(error);
431                 return FALSE;
432         }
433
434         if (__netconfig_wifi_try_to_remove_driver() != TRUE) {
435                 netconfig_error_wifi_driver_failed(error);
436
437                 return FALSE;
438         }
439
440         return TRUE;
441 }