Release Tizen 2.0 beta
[framework/connectivity/net-config.git] / src / wifi-power.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 <stdio.h>
21 #include <unistd.h>
22 #include <vconf.h>
23 #include <vconf-keys.h>
24 #include <wifi-direct.h>
25
26 #include "log.h"
27 #include "wifi.h"
28 #include "util.h"
29 #include "netdbus.h"
30 #include "neterror.h"
31 #include "netconfig.h"
32 #include "emulator.h"
33 #include "network-statistics.h"
34 #include "wifi-state.h"
35 #include "wifi-ssid-scan.h"
36 #include "wifi-background-scan.h"
37 #include "mdm-private.h"
38
39 gboolean netconfig_iface_wifi_load_driver(NetconfigWifi *wifi, GError **error);
40 gboolean netconfig_iface_wifi_remove_driver(NetconfigWifi *wifi, GError **error);
41
42 #include "netconfig-iface-wifi-glue.h"
43
44 #define WLAN_DRIVER_SCRIPT "/usr/bin/wlan.sh"
45
46 #define PROP_DEFAULT            FALSE
47 #define PROP_DEFAULT_STR        NULL
48
49 enum {
50         PROP_O,
51         PROP_WIFI_CONN,
52         PROP_WIFI_PATH,
53 };
54
55 enum {
56         SIG_WIFI_DRIVER,
57         SIG_LAST
58 };
59
60 struct NetconfigWifiClass {
61         GObjectClass parent;
62
63         /* method and signals */
64         void (*driver_loaded) (NetconfigWifi *wifi, gchar *mac);
65 };
66
67 struct NetconfigWifi {
68         GObject parent;
69
70         /* member variable */
71         DBusGConnection *conn;
72         gchar *path;
73 };
74
75 static guint32 signals[SIG_LAST] = { 0, };
76
77 G_DEFINE_TYPE(NetconfigWifi, netconfig_wifi, G_TYPE_OBJECT);
78
79
80 static void __netconfig_wifi_gobject_get_property(GObject *object, guint prop_id,
81                 GValue *value, GParamSpec *pspec)
82 {
83         return;
84 }
85
86 static void __netconfig_wifi_gobject_set_property(GObject *object, guint prop_id,
87                 const GValue *value, GParamSpec *pspec)
88 {
89         NetconfigWifi *wifi = NETCONFIG_WIFI(object);
90
91         switch (prop_id) {
92         case PROP_WIFI_CONN:
93         {
94                 wifi->conn = g_value_get_boxed(value);
95                 INFO("wifi(%p) set conn(%p)", wifi, wifi->conn);
96                 break;
97         }
98
99         case PROP_WIFI_PATH:
100         {
101                 if (wifi->path)
102                         g_free(wifi->path);
103
104                 wifi->path = g_value_dup_string(value);
105                 INFO("wifi(%p) path(%s)", wifi, wifi->path);
106
107                 break;
108         }
109
110         default:
111                 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
112         }
113 }
114
115 static void netconfig_wifi_init(NetconfigWifi *wifi)
116 {
117         DBG("wifi initialize");
118
119         wifi->conn = NULL;
120         wifi->path = g_strdup(PROP_DEFAULT_STR);
121 }
122
123 static void netconfig_wifi_class_init(NetconfigWifiClass *klass)
124 {
125         GObjectClass *object_class = G_OBJECT_CLASS(klass);
126
127         DBG("class initialize");
128
129         object_class->get_property = __netconfig_wifi_gobject_get_property;
130         object_class->set_property = __netconfig_wifi_gobject_set_property;
131
132         /* DBus register */
133         dbus_g_object_type_install_info(NETCONFIG_TYPE_WIFI,
134                         &dbus_glib_netconfig_iface_wifi_object_info);
135
136         /* property */
137         g_object_class_install_property(object_class, PROP_WIFI_CONN,
138                         g_param_spec_boxed("conn", "CONNECTION", "DBus connection",
139                                 DBUS_TYPE_G_CONNECTION,
140                                 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
141
142         g_object_class_install_property(object_class, PROP_WIFI_PATH,
143                         g_param_spec_string("path", "PATH", "Object Path",
144                                 PROP_DEFAULT_STR,
145                                 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
146
147         /* signal */
148         signals[SIG_WIFI_DRIVER] = g_signal_new("driver-loaded",
149                         G_OBJECT_CLASS_TYPE(klass),
150                         G_SIGNAL_RUN_LAST,
151                         G_STRUCT_OFFSET(NetconfigWifiClass,
152                                 driver_loaded),
153                         NULL, NULL,
154                         g_cclosure_marshal_VOID__STRING,
155                         G_TYPE_NONE, 1, G_TYPE_STRING);
156 }
157
158
159 static gboolean __netconfig_wifi_enable_technology(void)
160 {
161         DBusMessage *reply = NULL;
162         char path[DBUS_PATH_MAX_BUFLEN] = "/";
163         char param1[] = "string:wifi";
164         char *param_array[] = {NULL, NULL};
165
166         param_array[0] = param1;
167
168         reply = netconfig_invoke_dbus_method(CONNMAN_SERVICE, path,
169                         CONNMAN_MANAGER_INTERFACE, "EnableTechnology", param_array);
170
171         if (reply == NULL) {
172                 ERR("Error! Request failed");
173                 return FALSE;
174         }
175
176         dbus_message_unref(reply);
177
178         return TRUE;
179 }
180
181 static gboolean __netconfig_wifi_disable_technology(void)
182 {
183         DBusMessage *reply = NULL;
184         char path[DBUS_PATH_MAX_BUFLEN] = "/";
185         char param1[] = "string:wifi";
186         char *param_array[] = {NULL, NULL};
187
188         param_array[0] = param1;
189
190         reply = netconfig_invoke_dbus_method(CONNMAN_SERVICE, path,
191                         CONNMAN_MANAGER_INTERFACE, "DisableTechnology", param_array);
192
193         if (reply == NULL) {
194                 ERR("Error! Request failed");
195                 return FALSE;
196         }
197
198         dbus_message_unref(reply);
199
200         return TRUE;
201 }
202
203 static gboolean __netconfig_wifi_load_driver(void)
204 {
205         gboolean rv = FALSE;
206         const char *path = WLAN_DRIVER_SCRIPT;
207         char *const args[] = { "wlan.sh", "start" };
208         char *const envs[] = { NULL };
209
210         if (netconfig_emulator_is_emulated() == TRUE)
211                 return rv;
212
213         rv = netconfig_execute_file(path, args, envs);
214         if (rv != TRUE) {
215                 DBG("Failed to load wireless device driver");
216                 return FALSE;
217         }
218
219         DBG("Successfully loaded wireless device drivers");
220         return TRUE;
221 }
222
223 static gboolean __netconfig_wifi_remove_driver(void)
224 {
225         gboolean rv = FALSE;
226         const char *path = WLAN_DRIVER_SCRIPT;
227         char *const args[] = { "wlan.sh", "stop" };
228         char *const env[] = { NULL };
229
230         if (netconfig_emulator_is_emulated() == TRUE)
231                 return rv;
232
233         rv = netconfig_execute_file(path, args, env);
234         if (rv != TRUE) {
235                 DBG("Failed to remove(unload) driver for wireless device");
236                 return FALSE;
237         }
238
239         DBG("Successfully removed(unloaded) wireless driver");
240         return TRUE;
241 }
242
243 static gboolean __netconfig_wifi_try_to_load_driver(void);
244 static gboolean __netconfig_wifi_try_to_remove_driver(void);
245
246 static void __netconfig_wifi_direct_state_cb(int error_code,
247                 wifi_direct_device_state_e device_state, void *user_data)
248 {
249         wifi_direct_unset_device_state_changed_cb();
250         wifi_direct_deinitialize();
251
252         if (device_state == WIFI_DIRECT_DEVICE_STATE_DEACTIVATED) {
253                 __netconfig_wifi_try_to_load_driver();
254
255                 return;
256         }
257
258         /* TODO: error report */
259 }
260
261 static gboolean __netconfig_wifi_direct_power_off(void)
262 {
263         DBG("Wi-Fi direct is turning off");
264
265         if (wifi_direct_initialize() < 0)
266                 return FALSE;
267
268         if (wifi_direct_set_device_state_changed_cb(
269                         __netconfig_wifi_direct_state_cb, NULL) < 0)
270                 return FALSE;
271
272         if (wifi_direct_deactivate() < 0)
273                 return FALSE;
274
275         return TRUE;
276 }
277
278 static gboolean __netconfig_wifi_try_to_load_driver(void)
279 {
280         int count = 0;
281         gchar *wifi_tech_state = NULL;
282
283         if (netconfig_is_wifi_allowed() != TRUE)
284                 return FALSE;
285
286         if (netconfig_is_wifi_tethering_on() == TRUE) {
287                 /* TODO: Wi-Fi tethering turns off here */
288                 /* return TRUE; */
289                 return FALSE;
290         }
291
292         if (netconfig_is_wifi_direct_on() == TRUE) {
293                 if (__netconfig_wifi_direct_power_off() == TRUE)
294                         return TRUE;
295                 else
296                         return FALSE;
297         }
298
299         if (__netconfig_wifi_load_driver() != TRUE) {
300                 __netconfig_wifi_remove_driver();
301
302                 return FALSE;
303         }
304
305         for (count = 0; count < 3; count++) {
306                 __netconfig_wifi_enable_technology();
307
308                 wifi_tech_state = netconfig_wifi_get_technology_state();
309
310                 if (wifi_tech_state == NULL) {
311                         DBG("Failed to get Wi-Fi technology state");
312                         continue;
313                 }
314
315                 if (g_str_equal(wifi_tech_state, "EnabledTechnologies") == TRUE) {
316                         netconfig_wifi_update_power_state(TRUE);
317
318                         netconfig_wifi_device_picker_service_start();
319
320                         g_free(wifi_tech_state);
321                         wifi_tech_state = NULL;
322
323                         return TRUE;
324                 }
325
326                 g_free(wifi_tech_state);
327                 wifi_tech_state = NULL;
328         }
329
330         __netconfig_wifi_try_to_remove_driver();
331
332         return FALSE;
333 }
334
335 static gboolean __netconfig_wifi_try_to_remove_driver(void)
336 {
337         int count = 0;
338         gchar *wifi_tech_state = NULL;
339
340         netconfig_wifi_device_picker_service_stop();
341
342         netconfig_wifi_statistics_update_powered_off();
343
344         for (count = 0; count < 3; count++) {
345                 __netconfig_wifi_disable_technology();
346
347                 wifi_tech_state = netconfig_wifi_get_technology_state();
348
349                 if (wifi_tech_state == NULL) {
350                         DBG("Failed to get Wi-Fi technology state");
351                         continue;
352                 }
353
354                 if (g_str_equal(wifi_tech_state, "EnabledTechnologies") != TRUE) {
355                         g_free(wifi_tech_state);
356                         wifi_tech_state = NULL;
357
358                         break;
359                 }
360
361                 g_free(wifi_tech_state);
362                 wifi_tech_state = NULL;
363         }
364
365         if (__netconfig_wifi_remove_driver() == TRUE) {
366                 netconfig_wifi_update_power_state(FALSE);
367                 return TRUE;
368         }
369
370         return FALSE;
371 }
372
373 static void __netconfig_wifi_airplane_mode(keynode_t* node,
374                 void* user_data)
375 {
376         int value = 0;
377         int wifi_state = 0;
378         static gboolean powered_off_by_flightmode = FALSE;
379
380         vconf_get_bool(VCONFKEY_SETAPPL_FLIGHT_MODE_BOOL, &value);
381         vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
382
383         DBG("flight mode %s", value > 0 ? "ON" : "OFF");
384         DBG("Wi-Fi state %d, Wi-Fi was off by flight mode %s",
385                         wifi_state, powered_off_by_flightmode == TRUE ? "Yes" : "No");
386
387         if (value > 0) {
388                 /* flight mode enabled */
389                 if (wifi_state == VCONFKEY_WIFI_OFF)
390                         return;
391
392                 DBG("Turning Wi-Fi off");
393
394                 __netconfig_wifi_try_to_remove_driver();
395
396                 powered_off_by_flightmode = TRUE;
397         } else if (value == 0) {
398                 /* flight mode disabled */
399                 if (wifi_state > VCONFKEY_WIFI_OFF)
400                         return;
401
402                 if (powered_off_by_flightmode != TRUE)
403                         return;
404
405                 __netconfig_wifi_try_to_load_driver();
406
407                 powered_off_by_flightmode = FALSE;
408         } else
409                 DBG("Invalid value (%d)", value);
410 }
411
412 static void __netconfig_wifi_pm_state_mode(keynode_t* node,
413                 void* user_data)
414 {
415         int value = -1;
416         int wifi_state = 0;
417         static int prev_state = VCONFKEY_PM_STATE_NORMAL;
418
419         /*** vconf-keys.h ***
420          *              VCONFKEY_PM_STATE_NORMAL = 1,
421          *              VCONFKEY_PM_STATE_LCDDIM,
422          *              VCONFKEY_PM_STATE_LCDOFF,
423          *              VCONFKEY_PM_STATE_SLEEP
424          */
425
426         if(vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state) == 0) {
427                 DBG("wifi state : %d (0 off / 1 on / 2 connected)", wifi_state);
428                 if(wifi_state <= VCONFKEY_WIFI_OFF)
429                         return;
430         }
431
432         if(vconf_get_int(VCONFKEY_PM_STATE, &value) < 0) {
433                 ERR("VCONFKEY_PM_STATE get failed");
434                 return;
435         }
436
437         DBG("Old state: %d, current: %d", prev_state, value);
438
439         if((value == VCONFKEY_PM_STATE_NORMAL) && (prev_state >= VCONFKEY_PM_STATE_LCDOFF)) {
440                 DBG("PM state : Wake UP!");
441
442                 netconfig_wifi_bgscan_stop();
443                 netconfig_wifi_bgscan_start();
444         }
445
446         prev_state = value;
447 }
448
449 static void __netconfig_wifi_power_configuration(void)
450 {
451         int wifi_last_power_state = 0;
452
453         vconf_notify_key_changed(VCONFKEY_SETAPPL_FLIGHT_MODE_BOOL,
454                         __netconfig_wifi_airplane_mode, NULL);
455
456         vconf_notify_key_changed(VCONFKEY_PM_STATE,
457                         __netconfig_wifi_pm_state_mode, NULL);
458
459         vconf_get_int(VCONF_WIFI_LAST_POWER_STATE, &wifi_last_power_state);
460
461         if (wifi_last_power_state == WIFI_POWER_ON) {
462                 DBG("Turn Wi-Fi on automatically");
463
464                 __netconfig_wifi_try_to_load_driver();
465         }
466 }
467
468 static void __netconfig_wifi_notify_power_completed(gboolean power_on)
469 {
470         DBusMessage *signal;
471         DBusConnection *connection = NULL;
472         DBusError error;
473         char *sig_name =  NULL;
474
475         if (power_on)
476                 sig_name = "PowerOnCompleted";
477         else
478                 sig_name = "PowerOffCompleted";
479
480         dbus_error_init(&error);
481
482         connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
483         if (connection == NULL) {
484                 ERR("Error!!! Failed to get system DBus, error [%s]", error.message);
485                 dbus_error_free(&error);
486                 return;
487         }
488
489         signal = dbus_message_new_signal(NETCONFIG_WIFI_PATH,
490                                                         NETCONFIG_WIFI_INTERFACE, sig_name);
491         if (signal == NULL)
492                 return;
493
494         dbus_connection_send(connection, signal, NULL);
495
496         dbus_message_unref(signal);
497         dbus_connection_unref(connection);
498
499         INFO("(%s)", sig_name);
500 }
501
502 gpointer netconfig_wifi_create_and_init(DBusGConnection *conn)
503 {
504         GObject *object;
505
506         g_return_val_if_fail(conn != NULL, NULL);
507
508         object = g_object_new(NETCONFIG_TYPE_WIFI, "conn", conn, "path",
509                         NETCONFIG_WIFI_PATH, NULL);
510
511         INFO("create wifi(%p)", object);
512
513         dbus_g_connection_register_g_object(conn, NETCONFIG_WIFI_PATH, object);
514
515         INFO("wifi(%p) register DBus path(%s)", object, NETCONFIG_WIFI_PATH);
516
517         __netconfig_wifi_power_configuration();
518
519         return object;
520 }
521
522 gboolean netconfig_iface_wifi_load_driver(NetconfigWifi *wifi, GError **error)
523 {
524         DBG("Wi-Fi turned on");
525
526         g_return_val_if_fail(wifi != NULL, FALSE);
527
528         if (netconfig_is_wifi_allowed() != TRUE) {
529                 netconfig_error_security_restricted(error);
530
531                 return FALSE;
532         }
533
534         if (__netconfig_wifi_try_to_load_driver() != TRUE) {
535                 netconfig_error_wifi_driver_failed(error);
536
537                 return FALSE;
538         }
539
540         __netconfig_wifi_notify_power_completed(TRUE);
541         return TRUE;
542 }
543
544 gboolean netconfig_iface_wifi_remove_driver(NetconfigWifi *wifi, GError **error)
545 {
546         DBG("Wi-Fi turned off");
547
548         g_return_val_if_fail(wifi != NULL, FALSE);
549
550         if (__netconfig_wifi_try_to_remove_driver() != TRUE) {
551                 netconfig_error_wifi_driver_failed(error);
552
553                 return FALSE;
554         }
555
556         __netconfig_wifi_notify_power_completed(FALSE);
557         return TRUE;
558 }