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