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