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