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