Add dbus methods for setting bg scan interval
[platform/core/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 <errno.h>
21 #include <vconf.h>
22 #include <vconf-keys.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <glib.h>
26 #include <tzplatform_config.h>
27 #include <net/if.h>
28 #include <sys/ioctl.h>
29
30 #include "log.h"
31 #include "util.h"
32 #include "setting.h"
33 #include "netdbus.h"
34 #include "neterror.h"
35 #include "wifi-wps.h"
36 #include "wifi-scan.h"
37 #include "wifi-bssid-scan.h"
38 #include "wifi-power.h"
39 #include "wifi-state.h"
40 #include "netsupplicant.h"
41 #include "network-state.h"
42 #include "network-dpm.h"
43 #include "wifi-firmware.h"
44 #include "wifi-background-scan.h"
45
46 #define WLAN_SUPPLICANT_SCRIPT          "/usr/bin/wpa_supp.sh"
47 #define P2P_SUPPLICANT_SCRIPT           "/usr/bin/p2p_supp.sh"
48
49 #if !defined TIZEN_WEARABLE
50 #define VCONFKEY_SETAPPL_NETWORK_PERMIT_WITH_LCD_OFF_LIMIT      "db/setting/network_with_lcd_off_limit"
51 #endif
52
53 #define WLAN_MAC_ADDR_MAX 20
54 #define ETH_MAC_ADDR_SIZE 6
55 #define NET_EXEC_PATH "/sbin/ifconfig"
56 #define OS_RANDOM_FILE "/dev/urandom"
57
58 #define NETCONFIG_TECH_WAITING_INTERVAL 500
59 #define NETCONFIG_TECH_WAITING_COUNT 6
60 #define MAX_DRV_CMD_SIZE 248
61 #define WLAN_IOCTL_SUSPEND (SIOCDEVPRIVATE + 1)
62
63 typedef struct {
64         char *buf;
65         int used_len;
66         int total_len;
67 } netconfig_wifi_priv_cmd;
68
69 static gboolean wifi_firmware_recovery_mode = FALSE;
70 static int airplane_mode = 0;
71 gboolean is_supplicant_running = FALSE;
72
73 static gboolean __is_wifi_restricted(void)
74 {
75 #if defined TIZEN_WEARABLE
76         return FALSE;
77 #endif
78         int restricted_mode = 0;
79
80         netconfig_vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE, &restricted_mode);
81         if (restricted_mode != 0) {
82                 DBG("network restricted mode[%d]", restricted_mode);
83                 return TRUE;
84         }
85
86         return FALSE;
87 }
88
89 static void __technology_reply(GObject *source_object, GAsyncResult *res, gpointer user_data)
90 {
91         GVariant *reply;
92         GDBusConnection *conn = NULL;
93         GError *error = NULL;
94         char *interface_name = user_data;
95
96         conn = G_DBUS_CONNECTION(source_object);
97         reply = g_dbus_connection_call_finish(conn, res, &error);
98
99         if (reply == NULL) {
100                 if (error != NULL) {
101                         if (g_strstr_len(error->message, strlen(error->message),
102                                         CONNMAN_ERROR_INTERFACE ".AlreadyEnabled") != NULL) {
103                                 wifi_state_update_power_state(interface_name, TRUE);
104                         } else if (g_strstr_len(error->message, strlen(error->message),
105                                         CONNMAN_ERROR_INTERFACE ".AlreadyDisabled") != NULL) {
106                                 wifi_state_update_power_state(interface_name, FALSE);
107                         } else {
108                                 ERR("Fail to request status [%d: %s]", error->code, error->message);
109                                 wifi_state_update_power_state(interface_name, FALSE);
110                         }
111                         g_error_free(error);
112                 } else {
113                         ERR("Fail to request status");
114                         wifi_state_update_power_state(interface_name, FALSE);
115                 }
116         } else {
117                 DBG("Successfully requested");
118                 g_variant_unref(reply);
119         }
120
121         netconfig_gdbus_pending_call_unref();
122         g_free(interface_name);
123 }
124
125 void __mark_supplicant_stopped(void)
126 {
127         is_supplicant_running = FALSE;
128 }
129
130 int __execute_supplicant(gboolean enable)
131 {
132         /*
133          * TODO: [EAP on Ethernet] Temporary blocked wpa_supp.sh stop
134          * untill ConnMan adds logic to trigger/control wpa_supplicant interface.
135          */
136         int rv = 0;
137         const char *path = WLAN_SUPPLICANT_SCRIPT;
138         char *const args_enable[] = { "/usr/bin/wpa_supp.sh", "start", NULL };
139 #if 0
140         char *const args_disable[] = { "/usr/bin/wpa_supp.sh", "stop", NULL };
141 #endif
142         char *const envs[] = { NULL };
143
144         if (is_supplicant_running == enable)
145                 return -EALREADY;
146
147         if (enable == TRUE)
148                 rv = netconfig_execute_file(path, args_enable, envs);
149 #if 0
150         else
151                 rv = netconfig_execute_file(path, args_disable, envs);
152 #endif
153         if (rv < 0)
154                 return -EIO;
155
156         DBG("wpa_supplicant %s", enable == TRUE ? "started" : "stopped");
157
158         if (enable)
159                 is_supplicant_running = enable;
160
161         return 0;
162 }
163
164 static int _load_driver_and_supplicant(const char *interface_name)
165 {
166         int err = 0;
167         wifi_tech_state_e tech_state;
168
169         tech_state = wifi_state_get_technology_state(interface_name);
170         if (tech_state > NETCONFIG_WIFI_TECH_OFF)
171                 return -EALREADY;
172
173         err = __execute_supplicant(TRUE);
174         if (err < 0 && err != -EALREADY)
175                 return err;
176
177         err = netconfig_wifi_firmware(NETCONFIG_WIFI_STA, interface_name, TRUE);
178         if (err < 0 && err != -EALREADY) {
179                 __execute_supplicant(FALSE);
180                 return err;
181         }
182
183         wifi_state_set_technology_state(interface_name, NETCONFIG_WIFI_TECH_WPS_ONLY);
184
185         return 0;
186 }
187
188 static int _remove_driver_and_supplicant(const char *interface_name)
189 {
190         int err = 0;
191
192         DBG("remove driver and supplicant");
193         if (wifi_firmware_recovery_mode != TRUE &&
194                 netconfig_wifi_bssidscan_get_mode(interface_name) == TRUE) {
195                 DBG("Wi-Fi WPS mode");
196                 return 0;
197         }
198
199         err = netconfig_wifi_firmware(NETCONFIG_WIFI_STA, interface_name, FALSE);
200         if (err < 0 && err != -EALREADY)
201                 return err;
202
203         err = __execute_supplicant(FALSE);
204         if (err < 0 && err != -EALREADY)
205                 return err;
206
207         wifi_state_set_technology_state(interface_name, NETCONFIG_WIFI_TECH_OFF);
208
209         // reset service state
210         wifi_state_set_service_state(interface_name, NULL, NETCONFIG_WIFI_IDLE);
211
212         if (wifi_firmware_recovery_mode == TRUE) {
213                 if (wifi_power_on(interface_name) < 0)
214                         ERR("Failed to recover Wi-Fi firmware");
215
216                 wifi_firmware_recovery_mode = FALSE;
217         }
218
219         return 0;
220 }
221
222 static gboolean __check_and_set_technology_enable(gpointer data)
223 {
224         static int retry_count = NETCONFIG_TECH_WAITING_COUNT;
225         wifi_tech_state_e tech_state = NETCONFIG_WIFI_TECH_UNKNOWN;
226         gboolean value_enable = TRUE;
227         gboolean reply = FALSE;
228         GVariant *params = NULL;
229         char *interface_name = data;
230
231         tech_state = wifi_state_get_technology_state(interface_name);
232         if (tech_state == NETCONFIG_WIFI_TECH_UNKNOWN) {
233                 retry_count--;
234                 if (retry_count > 0)
235                         return TRUE;
236         }
237
238         params = g_variant_new("(sb)", interface_name, value_enable);
239
240         reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
241                                         CONNMAN_WIFI_TECHNOLOGY_PREFIX,
242                                         CONNMAN_TECHNOLOGY_INTERFACE,
243                                         "SetDevicePower", params,
244                                         __technology_reply,
245                                         g_strdup(interface_name));
246
247         if (reply != TRUE) {
248                 ERR("Fail to set technology enable");
249                 wifi_state_update_power_state(interface_name, FALSE);
250
251                 retry_count = NETCONFIG_TECH_WAITING_COUNT;
252                 g_free(interface_name);
253                 return FALSE;
254         }
255
256         retry_count = NETCONFIG_TECH_WAITING_COUNT;
257         g_free(interface_name);
258         return FALSE;
259 }
260
261 static int _set_connman_technology_power(const char *interface_name, gboolean enable)
262 {
263         gboolean reply = FALSE;
264         GVariant *params = NULL;
265         gboolean value_enable = TRUE;
266         gboolean value_disable = FALSE;
267         gboolean powered = FALSE;
268         wifi_tech_state_e tech_state = NETCONFIG_WIFI_TECH_UNKNOWN;
269
270         DBG("Set %s technology [%s]", interface_name, enable == TRUE ? "enable" : "disable");
271
272         powered = wifi_state_get_powered(interface_name);
273         if (powered == enable) {
274                 DBG("Already %s", enable ? "enabled" : "disabled");
275                 return -EALREADY;
276         }
277
278         if (enable == TRUE) {
279                 tech_state = wifi_state_get_technology_state(interface_name);
280                 if (tech_state == NETCONFIG_WIFI_TECH_UNKNOWN) {
281                         netconfig_start_timer(NETCONFIG_TECH_WAITING_INTERVAL,
282                                 __check_and_set_technology_enable, g_strdup(interface_name), NULL);
283                         wifi_state_set_powered(interface_name, enable);
284                         return 0;
285                 }
286         }
287
288         params = g_variant_new("(sb)", interface_name, (enable == TRUE) ? value_enable : value_disable);
289
290         reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
291                 CONNMAN_WIFI_TECHNOLOGY_PREFIX, CONNMAN_TECHNOLOGY_INTERFACE,
292                 "SetDevicePower", params, __technology_reply, g_strdup(interface_name));
293
294         if (reply != TRUE) {
295                 ERR("Fail to set technology %s", enable == TRUE ? "enable" : "disable");
296                 return -ESRCH;
297         }
298
299         /* To be keep safe, early disable Wi-Fi tech state */
300         if (enable != TRUE)
301                 wifi_state_set_technology_state(interface_name, NETCONFIG_WIFI_TECH_WPS_ONLY);
302
303         return 0;
304 }
305
306 #if !defined TIZEN_WEARABLE
307 static void __netconfig_wifi_restrict_mode(keynode_t *node, void *user_data)
308 {
309         int wifi_state = 0, restricted = 0;
310         GSList *list = NULL;
311
312         netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
313
314         if (node != NULL)
315                 restricted = vconf_keynode_get_bool(node);
316         else
317                 netconfig_vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE, &restricted);
318
319         DBG("network restricted mode %s", restricted > 0 ? "ON" : "OFF");
320         DBG("wifi state: %d (0 off / 1 on / 2 connected)", wifi_state);
321
322         if (restricted > 0) {
323                 /* network restricted on */
324                 GSList *device_list = NULL;
325
326                 if (wifi_state == VCONFKEY_WIFI_OFF)
327                         return;
328
329                 device_list = wifi_state_get_device_list();
330                 for (list = device_list; list; list = list->next) {
331                         wifi_device_data_s *device_data = list->data;
332                         wifi_power_off(device_data->interface_name);
333                         netconfig_setting_update_interface_off_for_restricted(device_data->interface_name, TRUE);
334                 }
335
336                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, 1, TRUE);
337         } else {
338                 /* network restricted off */
339                 GSList *ifname_list = NULL;
340
341                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, 0, TRUE);
342
343                 ifname_list = netconfig_setting_get_interfaces_off_by_restricted();
344                 for (list = ifname_list; list; list = list->next) {
345                         char *interface_name = list->data;
346
347                         if (wifi_state_get_technology_state(interface_name) > NETCONFIG_WIFI_TECH_OFF)
348                                 continue;
349
350                         netconfig_setting_update_interface_off_for_restricted(interface_name, FALSE);
351                         wifi_power_on(interface_name);
352                 }
353         }
354 }
355 #endif
356
357 static void __netconfig_wifi_airplane_mode(keynode_t *node, void *user_data)
358 {
359         int wifi_state = 0, airplane_state = 0;
360         GSList *list = NULL;
361
362         netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
363
364         if (node != NULL)
365                 airplane_state = vconf_keynode_get_bool(node);
366         else
367                 netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &airplane_state);
368
369         DBG("airplane mode %s (prev:%d)", airplane_state > 0 ? "ON" : "OFF", airplane_mode);
370         DBG("wifi state: %d (0 off / 1 on / 2 connected)", wifi_state);
371
372         if (airplane_mode == airplane_state)
373                 return;
374
375         airplane_mode = airplane_state;
376
377         if (airplane_state > 0) {
378                 /* airplane mode on */
379                 GSList *device_list = NULL;
380
381                 if (wifi_state == VCONFKEY_WIFI_OFF)
382                         return;
383
384                 device_list = wifi_state_get_device_list();
385                 for (list = device_list; list; list = list->next) {
386                         wifi_device_data_s *device_data = list->data;
387                         if (device_data->tech_state > NETCONFIG_WIFI_TECH_OFF) {
388                                 wifi_power_off(device_data->interface_name);
389                                 netconfig_setting_update_interface_off_for_airplane(device_data->interface_name, TRUE);
390                         }
391                 }
392
393                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 1, TRUE);
394         } else {
395                 /* airplane mode off */
396                 GSList *ifname_list = NULL;
397
398                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0, TRUE);
399
400                 ifname_list = netconfig_setting_get_interfaces_off_by_airplane();
401                 for (list = ifname_list; list; list = list->next) {
402                         char *interface_name = list->data;
403
404                         if (wifi_state_get_technology_state(interface_name) > NETCONFIG_WIFI_TECH_OFF)
405                                 continue;
406
407                         netconfig_setting_update_interface_off_for_airplane(interface_name, FALSE);
408                         wifi_power_on(interface_name);
409                 }
410         }
411 }
412
413 static void __emergency_mode_changed_cb(keynode_t *node, void *user_data)
414 {
415         int wifi_state = 0, emergency = 0;
416         GSList *list = NULL;
417 #if !defined TIZEN_WEARABLE
418         int emergency_by_fmm = 0;
419 #endif
420
421         netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
422
423 #if !defined TIZEN_WEARABLE
424         netconfig_vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_PERMIT_WITH_LCD_OFF_LIMIT, &emergency_by_fmm);
425         DBG("emergency mode by Find My Mobile (%d)", emergency_by_fmm);
426         if (emergency_by_fmm == 1)
427                 return;
428 #endif
429
430         if (node != NULL)
431                 emergency = vconf_keynode_get_int(node);
432         else
433                 netconfig_vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &emergency);
434
435         DBG("emergency mode %s", emergency > SETTING_PSMODE_POWERFUL ? "ON" : "OFF");
436         DBG("wifi state: %d (0 off / 1 on / 2 connected)", wifi_state);
437
438 #if defined TIZEN_WEARABLE
439         if (emergency == SETTING_PSMODE_WEARABLE) {
440                 /* basic power saving mode on */
441         } else if (emergency == SETTING_PSMODE_WEARABLE_ENHANCED) {
442                 /* enhanced power saving mode on */
443                 GSList *device_list = NULL;
444
445                 if (wifi_state == VCONFKEY_WIFI_OFF)
446                         return;
447
448                 device_list = wifi_state_get_device_list();
449                 for (list = device_list; list; list = list->next) {
450                         wifi_device_data_s *device_data = list->data;
451                         wifi_power_off(device_data->interface_name);
452                         netconfig_setting_update_interface_off_for_emergency(device_data->interface_name, TRUE);
453                 }
454
455                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 1, TRUE);
456         } else {
457                 /* power saving mode off */
458                 GSList *ifname_list = NULL;
459
460                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 0, TRUE);
461                 ifname_list = netconfig_setting_get_interfaces_off_by_emergency();
462                 for (list = ifname_list; list; list = list->next) {
463                         char *interface_name = list->data;
464
465                         if (wifi_state_get_technology_state(interface_name) > NETCONFIG_WIFI_TECH_OFF)
466                                 continue;
467
468                         netconfig_setting_update_interface_off_for_emergency(interface_name, FALSE);
469                         wifi_power_on_wearable(interface_name, TRUE);
470                 }
471         }
472 #else
473         if (emergency > SETTING_PSMODE_POWERFUL) {
474                 /* emergency mode on */
475                 GSList *device_list = NULL;
476
477                 if (wifi_state == VCONFKEY_WIFI_OFF)
478                         return;
479
480                 device_list = wifi_state_get_device_list();
481                 for (list = device_list; list; list = list->next) {
482                         wifi_device_data_s *device_data = list->data;
483                         wifi_power_off(device_data->interface_name);
484                         netconfig_setting_update_interface_off_for_emergency(device_data->interface_name, TRUE);
485                 }
486
487                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 1, TRUE);
488         } else {
489                 /* emergency mode off */
490                 GSList *ifname_list = NULL;
491
492                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 0, TRUE);
493
494                 ifname_list = netconfig_setting_get_interfaces_off_by_emergency();
495                 for (list = ifname_list; list; list = list->next) {
496                         char *interface_name = list->data;
497
498                         if (wifi_state_get_technology_state(interface_name) > NETCONFIG_WIFI_TECH_OFF)
499                                 continue;
500
501                         netconfig_setting_update_interface_off_for_emergency(interface_name, FALSE);
502                         wifi_power_on(interface_name);
503                 }
504         }
505 #endif
506
507 }
508
509 void wifi_set_early_suspend(const char *interface_name, gboolean value)
510 {
511         static gboolean old_state = FALSE;
512         struct ifreq ifr;
513         char buf[MAX_DRV_CMD_SIZE];
514         netconfig_wifi_priv_cmd priv_cmd;
515         int ret = 0;
516         int ioctl_sock = 0;
517         int pm_state = 0;
518         wifi_service_state_e wifi_state;
519         char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, };
520
521         if (old_state == value) {
522                 DBG("Old and new states are same");
523                 return;
524         }
525
526         if (netconfig_vconf_get_int(VCONFKEY_PM_STATE, &pm_state) < 0)
527                 ERR("Fail to get VCONFKEY_PM_STATE");
528
529         wifi_state = wifi_state_get_service_state(interface_name);
530
531         if (value == TRUE &&
532                         (pm_state < VCONFKEY_PM_STATE_LCDOFF ||
533                          wifi_state == NETCONFIG_WIFI_ASSOCIATION ||
534                          wifi_state == NETCONFIG_WIFI_CONFIGURATION)){
535                 DBG("");
536                 return;
537         }
538
539         memset(buf, 0, sizeof(buf));
540         snprintf(buf, sizeof(buf), "SETSUSPENDMODE %d", value);
541
542         memset(&ifr, 0, sizeof(struct ifreq));
543         g_strlcpy((char *)ifr.ifr_name, interface_name, IFNAMSIZ);
544
545         DBG("Early suspend command: [%s]", buf);
546
547         memset(&priv_cmd, 0, sizeof(priv_cmd));
548         priv_cmd.buf = buf;
549         priv_cmd.used_len = sizeof(buf);
550         priv_cmd.total_len = sizeof(buf);
551         ifr.ifr_data = (char *)&priv_cmd;
552
553         ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
554         if (ioctl_sock < 0) {
555                 DBG("socket(PF_INET,SOCK_DGRAM) failed: %s",
556                                 strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER));
557                 return;
558         }
559
560         ret = ioctl(ioctl_sock, WLAN_IOCTL_SUSPEND, &ifr);
561         if (ret < 0) {
562                 ERR("Fail to issue private commands: %d. %s", ret,
563                                 strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER));
564         } else {
565                 old_state = value;
566         }
567
568         close(ioctl_sock);
569 }
570
571 static void __pm_state_changed_cb(keynode_t* node, void* user_data)
572 {
573         int new_state = -1;
574         int wifi_state = 0;
575         static int prev_state = VCONFKEY_PM_STATE_NORMAL;
576         GSList *list = NULL, *device_list = NULL;
577
578         if (netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state) < 0) {
579                 ERR("Fail to get VCONFKEY_WIFI_STATE");
580                 return;
581         }
582
583         /* PM state
584          *      VCONFKEY_PM_STATE_NORMAL = 1,
585          *      VCONFKEY_PM_STATE_LCDDIM,
586          *      VCONFKEY_PM_STATE_LCDOFF,
587          *      VCONFKEY_PM_STATE_SLEEP
588          */
589         if (node != NULL)
590                 new_state = vconf_keynode_get_int(node);
591         else
592                 netconfig_vconf_get_int(VCONFKEY_PM_STATE, &new_state);
593
594         DBG("wifi state: %d (0 off / 1 on / 2 connected)", wifi_state);
595         DBG("Old PM state: %d, current: %d (1 normal / 2 lcddim / 3 lcdoff / 4 sleep)", prev_state, new_state);
596
597         if ((new_state == VCONFKEY_PM_STATE_NORMAL) && (prev_state >= VCONFKEY_PM_STATE_LCDOFF)) {
598                 /* Send early suspend mode based on LCD state and disallow early suspend count */
599                 device_list = wifi_state_get_device_list();
600                 for (list = device_list; list; list = list->next) {
601                         wifi_device_data_s *device_data = list->data;
602                         if (device_data->powered == TRUE) {
603                                 wifi_set_early_suspend(device_data->interface_name, FALSE);
604                                 DBG("Unset early suspend [%s]", device_data->interface_name);
605                         }
606                         netconfig_wifi_bgscan_stop(device_data->interface_name);
607                         netconfig_wifi_bgscan_set_exp_interval(device_data->interface_name, SCAN_EXPONENTIAL_MIN);
608                         netconfig_wifi_bgscan_start(device_data->interface_name, TRUE);
609                 }
610         } else if ((new_state == VCONFKEY_PM_STATE_LCDOFF) && (prev_state < VCONFKEY_PM_STATE_LCDOFF) && (wifi_state != VCONFKEY_WIFI_OFF)) {
611                 device_list = wifi_state_get_device_list();
612                 for (list = device_list; list; list = list->next) {
613                         wifi_device_data_s *device_data = list->data;
614                         wifi_set_early_suspend(device_data->interface_name, TRUE);
615                         DBG("Set early suspend [%s]", device_data->interface_name);
616                 }
617         }
618
619         prev_state = new_state;
620 }
621
622 static void __netconfig_telephony_ready_changed_cb(keynode_t *node, void *data)
623 {
624         int telephony_ready = 0;
625         char *interface_name = data;
626
627         if (node != NULL)
628                 telephony_ready = vconf_keynode_get_bool(node);
629         else
630                 netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_READY, &telephony_ready);
631
632         if (telephony_ready != 0) {
633                 if (netconfig_tapi_check_sim_state() == FALSE) {
634                         DBG("Sim is not initialized yet.");
635
636                         goto done;
637                 }
638         } else
639                 return;
640
641         DBG("Turn Wi-Fi on automatically");
642
643 #if defined TIZEN_WEARABLE
644         wifi_power_on_wearable(interface_name, TRUE);
645 #else
646         wifi_power_on(interface_name);
647 #endif
648
649 done:
650         vconf_ignore_key_changed(VCONFKEY_TELEPHONY_READY, __netconfig_telephony_ready_changed_cb);
651         g_free(interface_name);
652 }
653
654 int wifi_power_driver_and_supplicant(const char *interface_name, gboolean enable)
655 {
656         /* There are 3 thumb rules for Wi-Fi power management
657          *   1. Do not make exposed API to control wpa_supplicant and driver directly.
658          *      It probably breaks ConnMan technology operation.
659          *
660          *   2. Do not remove driver and wpa_supplicant if ConnMan already enabled.
661          *      It breaks ConnMan technology operation.
662          *
663          *   3. Final the best rule: make it as simple as possible.
664          *      Simple code enables easy maintenance and reduces logical errors.
665          */
666
667         if (enable == TRUE) {
668                 return _load_driver_and_supplicant(interface_name);
669         } else {
670                 if (wifi_state_get_powered(interface_name) == TRUE)
671                         return -ENOSYS;
672
673                 return _remove_driver_and_supplicant(interface_name);
674         }
675 }
676
677 void wifi_power_recover_firmware(const char *interface_name)
678 {
679         wifi_firmware_recovery_mode = TRUE;
680
681         netconfig_wifi_bgscan_stop(interface_name);
682
683         wifi_power_off(interface_name);
684 }
685
686 int wifi_power_on(const char *interface_name)
687 {
688         int err = 0;
689         wifi_tech_state_e tech_state;
690
691         tech_state = wifi_state_get_technology_state(interface_name);
692         if (tech_state >= NETCONFIG_WIFI_TECH_POWERED) {
693                 INFO("Net-Config WiFi connman technology state %d", tech_state);
694                 return -EALREADY;
695         }
696
697         if (__is_wifi_restricted() == TRUE)
698                 return -EPERM;
699
700         if (netconfig_is_wifi_tethering_on() == TRUE) {
701                 /* TODO: Wi-Fi tethering turns off here */
702                 /* return TRUE; */
703                 ERR("Failed to turn tethering off");
704                 return -EBUSY;
705         }
706
707         err = wifi_power_driver_and_supplicant(interface_name, TRUE);
708         if (err < 0 && err != -EALREADY)
709                 return err;
710
711         err = _set_connman_technology_power(interface_name, TRUE);
712         if (err < 0 && err != -EALREADY)
713                 wifi_power_driver_and_supplicant(interface_name, FALSE);
714
715         return err;
716 }
717
718 int wifi_power_off(const char *interface_name)
719 {
720         int err;
721
722         err = _set_connman_technology_power(interface_name, FALSE);
723         if (err == -EALREADY)
724                 wifi_state_update_power_state(interface_name, FALSE);
725
726         return err;
727 }
728
729 #if defined TIZEN_WEARABLE
730 int wifi_power_on_wearable(const char *interface_name, gboolean device_picker_test)
731 {
732         int err = 0;
733         wifi_tech_state_e tech_state;
734
735         tech_state = wifi_state_get_technology_state(interface_name);
736         if (tech_state >= NETCONFIG_WIFI_TECH_POWERED)
737                 return -EALREADY;
738
739         err = wifi_power_driver_and_supplicant(interface_name, TRUE);
740         if (err < 0 && err != -EALREADY)
741                 return err;
742
743         err = _set_connman_technology_power(interface_name, TRUE);
744         if (err < 0 && err != -EALREADY) {
745                 wifi_power_driver_and_supplicant(interface_name, FALSE);
746                 return err;
747         }
748
749         if (device_picker_test == TRUE)
750                 netconfig_wifi_enable_device_picker_test();
751
752         return err;
753 }
754 #endif
755
756 void wifi_power_initialize(void)
757 {
758         GSList *interface_list = NULL;
759
760         /* Initialize Airplane mode */
761         netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &airplane_mode);
762         DBG("Airplane[%s]", airplane_mode > 0 ? "ON" : "OFF");
763
764         /* Update the last Wi-Fi power state */
765         interface_list = netconfig_setting_get_interfaces_for_last_powered();
766         for (; interface_list; interface_list = interface_list->next) {
767                 const char *interface_name = interface_list->data;
768
769                 if (TIZEN_TELEPHONY_ENABLE) {
770                         int telephony_ready = 0;
771                         netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_READY, &telephony_ready);
772                         if (telephony_ready == 0) {
773                                 DBG("Telephony API is not initialized yet");
774                                 vconf_notify_key_changed(VCONFKEY_TELEPHONY_READY,
775                                         __netconfig_telephony_ready_changed_cb,
776                                         g_strdup(interface_name));
777                         } else {
778                                 if (netconfig_tapi_check_sim_state() == FALSE)
779                                         DBG("SIM is not initialized yet");
780                         }
781                 }
782                 DBG("Turn Wi-Fi on automatically");
783 #if defined TIZEN_WEARABLE
784                 wifi_power_on_wearable(interface_name, TRUE);
785 #else
786                 wifi_power_on(interface_name);
787 #endif
788         }
789
790 #if defined TIZEN_WEARABLE
791         vconf_notify_key_changed(VCONFKEY_TELEPHONY_FLIGHT_MODE,
792                         __netconfig_wifi_airplane_mode, NULL);
793 #else
794         vconf_notify_key_changed(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE,
795                         __netconfig_wifi_restrict_mode, NULL);
796         vconf_notify_key_changed(VCONFKEY_TELEPHONY_FLIGHT_MODE,
797                         __netconfig_wifi_airplane_mode, NULL);
798 #endif
799
800         vconf_notify_key_changed(VCONFKEY_SETAPPL_PSMODE,
801                 __emergency_mode_changed_cb, NULL);
802         vconf_notify_key_changed(VCONFKEY_PM_STATE, __pm_state_changed_cb, NULL);
803 }
804
805 void wifi_power_deinitialize(void)
806 {
807 }
808
809 gboolean handle_load_driver(Wifi *wifi,
810                 GDBusMethodInvocation *context,
811                 const gchar *ifname, gboolean device_picker_test)
812 {
813         int err;
814
815         DBG("Wi-Fi power on requested [%s]", ifname);
816
817         g_return_val_if_fail(wifi != NULL, TRUE);
818
819         if (!netconfig_dpm_update_from_wifi()) {
820                 DBG("DPM policy restricts Wi-Fi");
821                 netconfig_error_permission_denied(context);
822                 return TRUE;
823         }
824
825         if (TIZEN_WLAN_BOARD_SPRD)
826                 wifi_firmware_download();
827
828 #if defined TIZEN_WEARABLE
829         err = wifi_power_on_wearable(ifname, device_picker_test);
830 #else
831         err = wifi_power_on(ifname);
832
833         if (device_picker_test == TRUE)
834                 netconfig_wifi_enable_device_picker_test();
835 #endif
836         if (err < 0) {
837                 if (err == -EALREADY)
838                         netconfig_error_already_exists(context);
839                 else if (err == -EPERM)
840                         netconfig_error_permission_denied(context);
841                 else
842                         netconfig_error_wifi_driver_failed(context);
843
844                 return TRUE;
845         }
846
847
848         netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0, TRUE);
849
850         wifi_complete_load_driver(wifi, context);
851         return TRUE;
852 }
853
854 gboolean handle_remove_driver(Wifi *wifi, GDBusMethodInvocation *context,
855                         const gchar *ifname)
856 {
857         int err;
858
859         DBG("Wi-Fi power off requested [%s]", ifname);
860
861         g_return_val_if_fail(wifi != NULL, TRUE);
862
863         err = wifi_power_off(ifname);
864         if (err < 0) {
865                 if (err == -EALREADY)
866                         netconfig_error_already_exists(context);
867                 else if (err == -EPERM)
868                         netconfig_error_permission_denied(context);
869                 else
870                         netconfig_error_wifi_driver_failed(context);
871                 return TRUE;
872         }
873
874         netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0, TRUE);
875
876         wifi_complete_remove_driver(wifi, context);
877         return TRUE;
878 }
879
880 gboolean handle_load_p2p_driver(Wifi *wifi, GDBusMethodInvocation *context)
881 {
882         ERR("Deprecated");
883
884         wifi_complete_load_p2p_driver(wifi, context);
885         return TRUE;
886 }
887
888 gboolean handle_remove_p2p_driver(Wifi *wifi, GDBusMethodInvocation *context)
889 {
890         ERR("Deprecated");
891
892         wifi_complete_remove_p2p_driver(wifi, context);
893         return TRUE;
894 }
895
896 static int __netconfig_get_random_mac(unsigned char *mac_buf, int mac_len)
897 {
898         DBG("Generate Random Mac address of ethernet");
899         FILE *fp;
900         int rc;
901
902         fp = fopen(OS_RANDOM_FILE, "rb");
903
904         if (fp == NULL) {
905                 ERR("Could not open /dev/urandom");
906                 return -1;
907         }
908         rc = fread(mac_buf, 1, mac_len, fp);
909         if (fp)
910                 fclose(fp);
911
912         return rc != mac_len ? -1 : 0;
913 }
914
915 void __netconfig_set_ether_macaddr()
916 {
917         DBG("Set wired Mac address ");
918         char *mac_addr = NULL;
919         char rand_addr[WLAN_MAC_ADDR_MAX];
920         int rv = -1;
921
922         mac_addr = vconf_get_str(VCONF_ETH_MAC_ADDRESS);
923         if (mac_addr == NULL) {
924                 DBG("vconf_get_str Failed\n");
925                 return;
926         }
927         /* Checking Invalid MAC Address */
928         if ((strlen(mac_addr) == 0)) {
929                 ERR("Failed to get valid MAC Address from vconf");
930                 /*Generate the Random Mac address*/
931                 unsigned char rand_mac_add[ETH_MAC_ADDR_SIZE+1];
932
933                 if (__netconfig_get_random_mac(rand_mac_add, ETH_MAC_ADDR_SIZE) == -1) {
934
935                         ERR("Could not generate the Random Mac address");
936                         free(mac_addr);
937                         return;
938                 }
939
940                 rand_mac_add[0] &= 0xFE; /*Clear multicase bit*/
941                 rand_mac_add[0] |= 0x02; /*set local assignment bit*/
942
943                 /*Set the Mac address in Vconf*/
944                 snprintf(rand_addr, WLAN_MAC_ADDR_MAX, "%x:%x:%x:%x:%x:%x",
945                                 rand_mac_add[0], rand_mac_add[1],
946                                 rand_mac_add[2], rand_mac_add[3],
947                                 rand_mac_add[4], rand_mac_add[5]);
948
949                 netconfig_set_vconf_str(VCONF_ETH_MAC_ADDRESS, rand_addr, TRUE);
950         } else { /* Valid MAC address */
951                 g_strlcpy(rand_addr, mac_addr, WLAN_MAC_ADDR_MAX);
952         }
953
954         DBG("MAC Address of eth0 [%s]", rand_addr);
955         const char *path = NET_EXEC_PATH;
956         char *const args[] = { "/sbin/ifconfig", "eth0", "hw",
957                 "ether", rand_addr, "up", NULL};
958         char *const envs[] = { NULL };
959         rv = netconfig_execute_file(path, args, envs);
960
961         if (rv < 0)
962                 ERR("Unable to execute system command");
963         free(mac_addr);
964
965 }