Merge "Add a file path to check mac address #2" into tizen
[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 <ITapiSim.h>
24 #include <TapiUtility.h>
25 #include <stdio.h>
26 #include <tzplatform_config.h>
27
28 #if defined TIZEN_P2P_ENABLE && !defined WLAN_CONCURRENT_MODE
29 #include <wifi-direct.h>
30 #endif
31
32 #include "log.h"
33 #include "util.h"
34 #include "netdbus.h"
35 #include "neterror.h"
36 #include "wifi-wps.h"
37 #include "wifi-power.h"
38 #include "wifi-state.h"
39 #include "wifi-tel-intf.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
47 #define WLAN_SUPPLICANT_SCRIPT          "/usr/sbin/wpa_supp.sh"
48 #define P2P_SUPPLICANT_SCRIPT           "/usr/sbin/p2p_supp.sh"
49
50 #define VCONF_WIFI_OFF_STATE_BY_AIRPLANE        "file/private/wifi/wifi_off_by_airplane"
51 #define VCONF_WIFI_OFF_STATE_BY_RESTRICTED      "file/private/wifi/wifi_off_by_restricted"
52 #define VCONF_WIFI_OFF_STATE_BY_EMERGENCY       "file/private/wifi/wifi_off_by_emergency"
53 #if defined TIZEN_WEARABLE
54 #define VCONF_WIFI_WEARABLE_WIFI_USE                    "db/private/wifi/wearable_wifi_use"
55 #endif
56 #if !defined TIZEN_WEARABLE
57 #define VCONFKEY_SETAPPL_NETWORK_PERMIT_WITH_LCD_OFF_LIMIT      "db/setting/network_with_lcd_off_limit"
58 #endif
59
60 #define WLAN_MAC_INFO               tzplatform_mkpath(TZ_SYS_ETC, "/.mac.info")
61 #define WLAN_MAC_ADDRESS_FILEPATH   "/sys/class/net/wlan0/address"
62 #define WLAN_MAC_ADDR_MAX           20
63 #define VCONF_WIFI_BSSID_ADDRESS        "db/wifi/bssid_address"
64
65 #if defined TIZEN_TV
66 #define ETH_MAC_ADDR_SIZE 6
67 #define VCONF_ETH_MAC_ADDRESS  "db/dnet/mac_address"
68 #define NET_EXEC_PATH "/sbin/ifconfig"
69 #define OS_RANDOM_FILE "/dev/urandom"
70 #endif
71
72 static gboolean connman_wifi_technology_state = FALSE;
73 static gboolean wifi_firmware_recovery_mode = FALSE;
74 static int airplane_mode = 0;
75
76 #if defined TIZEN_WEARABLE
77 static int psmode_wifi_use = 1;
78 #endif
79
80 static gboolean __is_wifi_restricted(void)
81 {
82 #if defined TIZEN_WEARABLE
83         return FALSE;
84 #endif
85         int restricted_mode = 0;
86
87         netconfig_vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE, &restricted_mode);
88         if (restricted_mode != 0) {
89                 DBG("network restricted mode[%d]", restricted_mode);
90                 return TRUE;
91         }
92
93         return FALSE;
94 }
95
96 static void __technology_reply(GObject *source_object, GAsyncResult *res, gpointer user_data)
97 {
98         GVariant *reply;
99         GDBusConnection *conn = NULL;
100         GError *error = NULL;
101
102         conn = G_DBUS_CONNECTION(source_object);
103         reply = g_dbus_connection_call_finish(conn, res, &error);
104
105         if (reply == NULL) {
106                 if (error != NULL) {
107                         if (g_strstr_len(error->message, strlen(error->message),
108                                         CONNMAN_ERROR_INTERFACE ".AlreadyEnabled") != NULL) {
109                                 wifi_state_update_power_state(TRUE);
110                         } else if (g_strstr_len(error->message, strlen(error->message),
111                                         CONNMAN_ERROR_INTERFACE ".AlreadyDisabled") != NULL) {
112                                 wifi_state_update_power_state(FALSE);
113                         } else {
114                                 ERR("Fail to request status [%d: %s]", error->code, error->message);
115                                 wifi_state_update_power_state(FALSE);
116                         }
117                         g_error_free(error);
118                 } else {
119                         ERR("Fail to request status");
120                         wifi_state_update_power_state(FALSE);
121                 }
122         } else {
123                 DBG("Successfully requested");
124         }
125
126         g_variant_unref(reply);
127         netconfig_gdbus_pending_call_unref();
128 }
129
130 static int __execute_supplicant(gboolean enable)
131 {
132         int rv = 0;
133         const char *path = WLAN_SUPPLICANT_SCRIPT;
134         char *const args_enable[] = { "/usr/sbin/wpa_supp.sh", "start", NULL };
135         char *const args_disable[] = { "/usr/sbin/wpa_supp.sh", "stop", NULL };
136         char *const envs[] = { NULL };
137         static gboolean enabled = FALSE;
138
139         if (enabled == enable)
140                 return -EALREADY;
141
142         if (enable == TRUE)
143                 rv = netconfig_execute_file(path, args_enable, envs);
144         else
145                 rv = netconfig_execute_file(path, args_disable, envs);
146         if (rv < 0)
147                 return -EIO;
148
149         DBG("wpa_supplicant %s", enable == TRUE ? "started" : "stopped");
150
151         enabled = enable;
152
153         return 0;
154 }
155
156 #if defined TIZEN_P2P_ENABLE && defined WLAN_CONCURRENT_MODE
157 static int __netconfig_p2p_supplicant(gboolean enable)
158 {
159         int rv = 0;
160         const char *path = P2P_SUPPLICANT_SCRIPT;
161         char *const args_enable[] = { P2P_SUPPLICANT_SCRIPT, "start", NULL };
162         char *const args_disable[] = { P2P_SUPPLICANT_SCRIPT, "stop", NULL };
163         char *const envs[] = { NULL };
164
165         if (enable == TRUE)
166                 rv = netconfig_execute_file(path, args_enable, envs);
167         else
168                 rv = netconfig_execute_file(path, args_disable, envs);
169         if (rv < 0)
170                 return -EIO;
171
172         DBG("p2p_supplicant %s", enable == TRUE ? "started" : "stopped");
173
174         return 0;
175 }
176 #endif
177
178 void netconfig_wifi_recover_firmware(void)
179 {
180         wifi_firmware_recovery_mode = TRUE;
181
182         netconfig_wifi_bgscan_stop();
183
184         wifi_power_off();
185 }
186
187 #if defined TIZEN_P2P_ENABLE && !defined WLAN_CONCURRENT_MODE
188 static void __netconfig_wifi_direct_state_cb(int error_code, wifi_direct_device_state_e device_state, void *user_data)
189 {
190         int err;
191
192         wifi_direct_unset_device_state_changed_cb();
193         wifi_direct_deinitialize();
194
195         if (device_state == WIFI_DIRECT_DEVICE_STATE_DEACTIVATED) {
196                 err = wifi_power_on();
197                 if (err < 0) {
198                         if (err == -EALREADY)
199                                 wifi_state_update_power_state(TRUE);
200                         else
201                                 wifi_state_emit_power_failed();
202                 }
203         }
204 }
205
206 static gboolean __netconfig_wifi_direct_power_off(void)
207 {
208         DBG("Wi-Fi direct is turning off");
209
210         if (wifi_direct_initialize() < 0)
211                 return FALSE;
212
213         if (wifi_direct_set_device_state_changed_cb(__netconfig_wifi_direct_state_cb, NULL) < 0)
214                 return FALSE;
215
216         if (wifi_direct_deactivate() < 0)
217                 return FALSE;
218
219         return TRUE;
220 }
221 #endif
222
223 static int _load_driver_and_supplicant(void)
224 {
225         int err = 0;
226         wifi_tech_state_e tech_state;
227
228         tech_state = wifi_state_get_technology_state();
229         if (tech_state > NETCONFIG_WIFI_TECH_OFF)
230                 return -EALREADY;
231
232         err = __execute_supplicant(TRUE);
233         if (err < 0 && err != -EALREADY)
234                 return err;
235
236         err = netconfig_wifi_firmware(NETCONFIG_WIFI_STA, TRUE);
237         if (err < 0 && err != -EALREADY) {
238                 __execute_supplicant(FALSE);
239                 return err;
240         }
241
242         wifi_state_set_tech_state(NETCONFIG_WIFI_TECH_WPS_ONLY);
243
244         return 0;
245 }
246
247 static int _remove_driver_and_supplicant(void)
248 {
249         int err = 0;
250
251         if (wifi_firmware_recovery_mode != TRUE &&
252                                         netconfig_wifi_is_wps_enabled() == TRUE) {
253                 DBG("Wi-Fi WPS mode");
254                 return 0;
255         }
256
257         err = netconfig_wifi_firmware(NETCONFIG_WIFI_STA, FALSE);
258         if (err < 0 && err != -EALREADY)
259                 return err;
260
261         err = __execute_supplicant(FALSE);
262         if (err < 0 && err != -EALREADY)
263                 return err;
264
265         wifi_state_set_tech_state(NETCONFIG_WIFI_TECH_OFF);
266
267         if (wifi_firmware_recovery_mode == TRUE) {
268                 if (wifi_power_on() < 0)
269                         ERR("Failed to recover Wi-Fi firmware");
270
271                 wifi_firmware_recovery_mode = FALSE;
272         }
273
274         return 0;
275 }
276
277 static int _set_connman_technology_power(gboolean enable)
278 {
279         gboolean reply = FALSE;
280         GVariant *param0 = NULL;
281         GVariant *params = NULL;
282         char key[] = "Powered";
283         gboolean value_enable = TRUE;
284         gboolean value_disable = FALSE;
285
286         if (connman_wifi_technology_state == enable)
287                 return -EALREADY;
288
289         if (enable == TRUE)
290                 param0 = g_variant_new_boolean(value_enable);
291         else
292                 param0 = g_variant_new_boolean(value_disable);
293
294         params = g_variant_new("(sv)", key, param0);
295
296         reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
297                                         CONNMAN_WIFI_TECHNOLOGY_PREFIX, CONNMAN_TECHNOLOGY_INTERFACE,
298                                         "SetProperty", params, __technology_reply);
299
300         if (reply != TRUE) {
301                 ERR("Fail to set technology %s", enable == TRUE ? "enable" : "disable");
302                 return -ESRCH;
303         }
304
305         /* If Wi-Fi powered off,
306          * Do not remove Wi-Fi driver until ConnMan technology state updated
307          */
308         if (enable == TRUE)
309                 connman_wifi_technology_state = enable;
310
311         /* To be keep safe, early disable Wi-Fi tech state */
312         if (enable != TRUE)
313                 wifi_state_set_tech_state(NETCONFIG_WIFI_TECH_WPS_ONLY);
314
315         return 0;
316 }
317
318 static void __netconfig_set_wifi_bssid(void)
319 {
320         int rv = 0;
321         char bssid[WLAN_MAC_ADDR_MAX];
322
323         FILE *fp = fopen(WLAN_MAC_INFO, "r");
324
325         if (fp == NULL) {
326                 ERR("Fail to open %s", WLAN_MAC_INFO);
327                 fp = fopen(WLAN_MAC_ADDRESS_FILEPATH, "r");
328                 if (fp == NULL) {
329                         ERR("Fail to open %s", WLAN_MAC_ADDRESS_FILEPATH);
330                         return;
331                 }
332         }
333
334         fseek(fp, 0L, SEEK_SET);
335         rv = fscanf(fp, "%17s", bssid);
336
337         if (rv < 0)
338                 ERR("Fail to read bssid");
339
340         netconfig_set_vconf_str(VCONF_WIFI_BSSID_ADDRESS, bssid);
341
342         fclose(fp);
343 }
344
345 int netconfig_wifi_driver_and_supplicant(gboolean enable)
346 {
347         /* There are 3 thumb rules for Wi-Fi power management
348          *   1. Do not make exposed API to control wpa_supplicant and driver directly.
349          *      It probably breaks ConnMan technology operation.
350          *
351          *   2. Do not remove driver and wpa_supplicant if ConnMan already enabled.
352          *      It breaks ConnMan technology operation.
353          *
354          *   3. Final the best rule: make it as simple as possible.
355          *      Simple code enables easy maintenance and reduces logical errors.
356          */
357         if (enable == TRUE)
358                 return _load_driver_and_supplicant();
359         else {
360                 if (connman_wifi_technology_state == TRUE)
361                         return -ENOSYS;
362
363                 return _load_driver_and_supplicant();
364         }
365 }
366
367 void netconfig_wifi_disable_technology_state_by_only_connman_signal(void)
368 {
369         /* Important: it's only done by ConnMan technology signal update */
370         connman_wifi_technology_state = FALSE;
371 }
372
373 #if defined TIZEN_WEARABLE
374 int netconfig_wifi_on_wearable(gboolean device_picker_test)
375 {
376         int err = 0;
377         int wifi_use;
378         int ps_mode;
379
380         if (netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use) < 0) {
381                 ERR("Fail to get VCONF_WIFI_WEARABLE_WIFI_USE");
382                 return -EIO;
383         }
384
385         if (wifi_use > 0) {
386                 if (netconfig_vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &ps_mode) < 0) {
387                         ERR("Fail to get VCONFKEY_SETAPPL_PSMODE");
388                         return -EIO;
389                 }
390
391                 if (ps_mode > SETTING_PSMODE_NORMAL) {
392                         WARN("ps mode is on(%d), Not turn on Wi-Fi", ps_mode);
393                         return -EPERM;
394                 }
395         } else {
396                 WARN("Not permitted Wi-Fi on");
397                 return -EPERM;
398         }
399
400         err = wifi_power_driver_and_supplicant(TRUE);
401         if (err < 0 && err != -EALREADY)
402                 return err;
403
404         err = _set_connman_technology_power(TRUE);
405
406         if (device_picker_test == TRUE)
407                 netconfig_wifi_enable_device_picker_test();
408
409         return err;
410 }
411
412 static void __wearable_wifi_use_changed_cb(keynode_t* node, void* user_data)
413 {
414         int wifi_state;
415         int wifi_use = 1;
416
417         if (netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state) < 0) {
418                 ERR("Fail to get VCONFKEY_WIFI_STATE");
419                 return;
420         }
421
422         if (node != NULL)
423                 wifi_use = vconf_keynode_get_int(node);
424         else
425                 netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use);
426
427         if (wifi_use > 0) {
428                 DBG("wifi use on");
429                 if (wifi_state > VCONFKEY_WIFI_OFF) {
430                         WARN("Wi-Fi is already turned on");
431                         return;
432                 }
433                 wifi_power_on_wearable(TRUE);
434         } else {
435                 ERR("## wifi use [OFF]");
436                 if (wifi_state == VCONFKEY_WIFI_OFF) {
437                         WARN("Wi-Fi is already turned off");
438                         return;
439                 }
440
441                 wifi_power_off();
442         }
443 }
444 #else
445 static void __netconfig_wifi_restrict_mode(keynode_t *node, void *user_data)
446 {
447         int wifi_state = 0, restricted = 0;
448         int wifi_off_by_restricted = 0;
449
450         netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, &wifi_off_by_restricted);
451
452         netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
453
454         if (node != NULL)
455                 restricted = vconf_keynode_get_bool(node);
456         else
457                 netconfig_vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE, &restricted);
458
459         DBG("network restricted mode %s", restricted > 0 ? "ON" : "OFF");
460         DBG("Wi-Fi state %d, Wi-Fi was off by restricted mode %s", wifi_state,
461                         wifi_off_by_restricted ? "Yes" : "No");
462
463         if (restricted > 0) {
464                 /* network restricted on */
465                 if (wifi_state == VCONFKEY_WIFI_OFF)
466                         return;
467
468                 wifi_power_off();
469
470                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, 1);
471         } else {
472                 /* network restricted off */
473                 if (!wifi_off_by_restricted)
474                         return;
475
476                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, 0);
477
478                 if (wifi_state > VCONFKEY_WIFI_OFF)
479                         return;
480
481                 wifi_power_on();
482         }
483 }
484 #endif
485
486 static void __netconfig_wifi_airplane_mode(keynode_t *node, void *user_data)
487 {
488         int wifi_state = 0, airplane_state = 0;
489         int wifi_off_by_airplane = 0;
490
491         netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, &wifi_off_by_airplane);
492
493 #if defined TIZEN_WEARABLE
494         netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_state)
495 #else
496         netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
497 #endif
498
499         if (node != NULL)
500                 airplane_state = vconf_keynode_get_bool(node);
501         else
502                 netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &airplane_state);
503
504         DBG("airplane mode %s (prev:%d)", airplane_state > 0 ? "ON" : "OFF", airplane_mode);
505         DBG("Wi-Fi state(or use) %d, Wi-Fi was off by flight mode %s", wifi_state,
506                         wifi_off_by_airplane ? "Yes" : "No");
507
508         if (airplane_mode == airplane_state)
509                 return ;
510
511         airplane_mode = airplane_state;
512
513         if (airplane_state > 0) {
514                 /* airplane mode on */
515                 if (wifi_state == VCONFKEY_WIFI_OFF)
516                         return;
517
518                 wifi_power_off();
519
520                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 1);
521 #if defined TIZEN_WEARABLE
522                 netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, 0);
523 #endif
524         } else {
525                 /* airplane mode off */
526                 if (!wifi_off_by_airplane)
527                         return;
528
529                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
530 #if defined TIZEN_WEARABLE
531                 netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, 1);
532 #else
533                 if (wifi_state > VCONFKEY_WIFI_OFF)
534                         return;
535
536                 wifi_power_on();
537 #endif
538         }
539 }
540
541 static void __emergency_mode_changed_cb(keynode_t *node, void *user_data)
542 {
543         int wifi_state = 0, emergency = 0;
544         int wifi_off_by_emergency = 0;
545 #if !defined TIZEN_WEARABLE
546         int emergency_by_fmm = 0;
547 #endif
548 #if defined TIZEN_WEARABLE
549         int wifi_use = 1;
550 #endif
551
552         netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, &wifi_off_by_emergency);
553         netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
554
555 #if !defined TIZEN_WEARABLE
556         netconfig_vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_PERMIT_WITH_LCD_OFF_LIMIT, &emergency_by_fmm);
557         DBG("emergency mode by Find My Mobile (%d)", emergency_by_fmm);
558         if (emergency_by_fmm == 1)
559                 return;
560 #endif
561
562         if (node != NULL)
563                 emergency = vconf_keynode_get_int(node);
564         else
565                 netconfig_vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &emergency);
566
567         DBG("emergency mode %s", emergency > SETTING_PSMODE_POWERFUL ? "ON" : "OFF");
568         DBG("Wi-Fi state %d, Wi-Fi was off by emergency mode %s", wifi_state, wifi_off_by_emergency ? "Yes" : "No");
569
570 #if defined TIZEN_WEARABLE
571         if (emergency == SETTING_PSMODE_WEARABLE) {
572                 /* basic power saving mode on */
573         } else if (emergency == SETTING_PSMODE_WEARABLE_ENHANCED) {
574                 /* enhanced power saving mode on */
575                 netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use);
576                 psmode_wifi_use = wifi_use;
577                 if (wifi_use != 0)
578                         netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, 0);
579
580                 if (wifi_state == VCONFKEY_WIFI_OFF)
581                         return;
582
583                 wifi_power_off();
584                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 1);
585         } else {
586                 /* power saving mode off */
587                 netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, psmode_wifi_use);
588                 if (!wifi_off_by_emergency)
589                         return;
590
591                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 0);
592                 if (wifi_state > VCONFKEY_WIFI_OFF)
593                         return;
594
595                 wifi_power_on_wearable(TRUE);
596         }
597 #else
598         if (emergency > SETTING_PSMODE_POWERFUL) {
599                 /* emergency mode on */
600                 if (wifi_state == VCONFKEY_WIFI_OFF)
601                         return;
602
603                 wifi_power_off();
604
605                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 1);
606         } else {
607                 /* emergency mode off */
608                 if (!wifi_off_by_emergency)
609                         return;
610
611                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 0);
612
613                 if (wifi_state > VCONFKEY_WIFI_OFF)
614                         return;
615
616                 wifi_power_on();
617         }
618 #endif
619
620 }
621
622 static void __pm_state_changed_cb(keynode_t* node, void* user_data)
623 {
624         int new_state = -1;
625         int wifi_state = 0;
626         static int prev_state = VCONFKEY_PM_STATE_NORMAL;
627
628         if (netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state) < 0) {
629                 ERR("Fail to get VCONFKEY_WIFI_STATE");
630                 return;
631         }
632
633         /* PM state
634          *      VCONFKEY_PM_STATE_NORMAL = 1,
635          *      VCONFKEY_PM_STATE_LCDDIM,
636          *      VCONFKEY_PM_STATE_LCDOFF,
637          *      VCONFKEY_PM_STATE_SLEEP
638          */
639         if (node != NULL)
640                 new_state = vconf_keynode_get_int(node);
641         else
642                 netconfig_vconf_get_int(VCONFKEY_PM_STATE, &new_state);
643
644         DBG("wifi state: %d (0 off / 1 on / 2 connected)", wifi_state);
645         DBG("Old PM state: %d, current: %d", prev_state, new_state);
646
647         if ((new_state == VCONFKEY_PM_STATE_NORMAL) && (prev_state >= VCONFKEY_PM_STATE_LCDOFF)) {
648                 netconfig_wifi_bgscan_stop();
649                 netconfig_wifi_bgscan_start(TRUE);
650         }
651
652         prev_state = new_state;
653 }
654
655 #if defined TIZEN_TELEPHONY_ENABLE
656 static void _tapi_noti_sim_status_cb(TapiHandle *handle, const char *noti_id,
657                                                                                 void *data, void *user_data)
658 {
659         TelSimCardStatus_t *status = data;
660
661         if (*status == TAPI_SIM_STATUS_SIM_INIT_COMPLETED) {
662                 DBG("Turn Wi-Fi on automatically");
663 #if defined TIZEN_WEARABLE
664                 wifi_power_on_wearable(TRUE);
665 #else
666                 wifi_power_on();
667 #endif
668                 netconfig_tel_deinit();
669         }
670 }
671
672 static gboolean netconfig_tapi_check_sim_state(void)
673 {
674         int ret, card_changed;
675         TelSimCardStatus_t status = TAPI_SIM_STATUS_UNKNOWN;
676         TapiHandle *tapi_handle = NULL;
677
678         tapi_handle = (TapiHandle *)netconfig_tel_init();
679         if (tapi_handle == NULL) {
680                 ERR("Failed to tapi init");
681                 return FALSE;
682         }
683
684         ret = tel_get_sim_init_info(tapi_handle, &status, &card_changed);
685         if (ret != TAPI_API_SUCCESS) {
686                 ERR("tel_get_sim_init_info() Failed : [%d]", ret);
687                 netconfig_tel_deinit();
688                 return FALSE;
689         }
690
691         switch (status) {
692         case TAPI_SIM_STATUS_UNKNOWN:
693         case TAPI_SIM_STATUS_CARD_ERROR:
694         case TAPI_SIM_STATUS_CARD_NOT_PRESENT:
695         case TAPI_SIM_STATUS_CARD_BLOCKED:
696         case TAPI_SIM_STATUS_SIM_INIT_COMPLETED:
697                 break;
698         case TAPI_SIM_STATUS_SIM_PIN_REQUIRED:
699         case TAPI_SIM_STATUS_SIM_INITIALIZING:
700         case TAPI_SIM_STATUS_SIM_PUK_REQUIRED:
701         case TAPI_SIM_STATUS_SIM_LOCK_REQUIRED:
702         case TAPI_SIM_STATUS_SIM_NCK_REQUIRED:
703         case TAPI_SIM_STATUS_SIM_NSCK_REQUIRED:
704         case TAPI_SIM_STATUS_SIM_SPCK_REQUIRED:
705         case TAPI_SIM_STATUS_SIM_CCK_REQUIRED:
706                 tel_register_noti_event(tapi_handle, TAPI_NOTI_SIM_STATUS,
707                                 _tapi_noti_sim_status_cb, NULL);
708                 return FALSE;
709         default:
710                 ERR("not defined status(%d)", status);
711                 break;
712         }
713
714         netconfig_tel_deinit();
715
716         return TRUE;
717 }
718
719 static void __netconfig_telephony_ready_changed_cb(keynode_t * node, void *data)
720 {
721         int telephony_ready = 0;
722
723         if (node != NULL)
724                 telephony_ready = vconf_keynode_get_bool(node);
725         else
726                 netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_READY, &telephony_ready);
727
728         if (telephony_ready != 0) {
729                 if (netconfig_tapi_check_sim_state() == FALSE) {
730                         DBG("Sim is not initialized yet.");
731
732                         goto done;
733                 }
734         } else
735                 return;
736
737         DBG("Turn Wi-Fi on automatically");
738
739 #if defined TIZEN_WEARABLE
740         wifi_power_on_wearable(TRUE);
741 #else
742         wifi_power_on();
743 #endif
744
745 done:
746         vconf_ignore_key_changed(VCONFKEY_TELEPHONY_READY, __netconfig_telephony_ready_changed_cb);
747 }
748 #endif
749
750 int wifi_power_driver_and_supplicant(gboolean enable)
751 {
752         /* There are 3 thumb rules for Wi-Fi power management
753          *   1. Do not make exposed API to control wpa_supplicant and driver directly.
754          *      It probably breaks ConnMan technology operation.
755          *
756          *   2. Do not remove driver and wpa_supplicant if ConnMan already enabled.
757          *      It breaks ConnMan technology operation.
758          *
759          *   3. Final the best rule: make it as simple as possible.
760          *      Simple code enables easy maintenance and reduces logical errors.
761          */
762         if (enable == TRUE) {
763                 return _load_driver_and_supplicant();
764         } else {
765                 if (connman_wifi_technology_state == TRUE)
766                         return -ENOSYS;
767
768                 return _remove_driver_and_supplicant();
769         }
770 }
771
772 void wifi_power_disable_technology_state_by_only_connman_signal(void)
773 {
774         /* Important: it's only done by ConnMan technology signal update */
775         connman_wifi_technology_state = FALSE;
776 }
777
778 void wifi_power_recover_firmware(void)
779 {
780         wifi_firmware_recovery_mode = TRUE;
781
782         netconfig_wifi_bgscan_stop();
783
784         wifi_power_off();
785 }
786
787 int wifi_power_on(void)
788 {
789         int err = 0;
790         wifi_tech_state_e tech_state;
791
792         tech_state = wifi_state_get_technology_state();
793         if (tech_state >= NETCONFIG_WIFI_TECH_POWERED)
794                 return -EALREADY;
795
796         if (__is_wifi_restricted() == TRUE)
797                 return -EPERM;
798
799         if (netconfig_is_wifi_tethering_on() == TRUE) {
800                 /* TODO: Wi-Fi tethering turns off here */
801                 /* return TRUE; */
802                 ERR("Failed to turn tethering off");
803                 return -EBUSY;
804         }
805
806 #if defined TIZEN_P2P_ENABLE && !defined WLAN_CONCURRENT_MODE
807         if (netconfig_is_wifi_direct_on() == TRUE) {
808                 if (__netconfig_wifi_direct_power_off() == TRUE)
809                         return -EINPROGRESS;
810                 else {
811                         ERR("Failed to turn Wi-Fi direct off");
812                         return -EBUSY;
813                 }
814         }
815 #endif
816
817         err = wifi_power_driver_and_supplicant(TRUE);
818         if (err < 0 && err != -EALREADY)
819                 return err;
820
821         err = _set_connman_technology_power(TRUE);
822
823         return err;
824 }
825
826 int wifi_power_off(void)
827 {
828         int err;
829
830         err = _set_connman_technology_power(FALSE);
831         if (err == -EALREADY)
832                 wifi_state_update_power_state(FALSE);
833
834         return 0;
835 }
836
837 #if defined TIZEN_WEARABLE
838 int wifi_power_on_wearable(gboolean device_picker_test)
839 {
840         int err = 0;
841         int wifi_use = 1;
842         wifi_tech_state_e tech_state;
843
844         tech_state = wifi_state_get_technology_state();
845         if (tech_state >= NETCONFIG_WIFI_TECH_POWERED)
846                 return -EALREADY;
847
848         if (netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use) < 0) {
849                 ERR("Fail to get VCONF_WIFI_WEARABLE_WIFI_USE");
850                 return -EIO;
851         }
852
853         if (wifi_use == 0) {
854                 WARN("VCONF_WIFI_WEARABLE_WIFI_USE is OFF");
855                 return -EPERM;
856         }
857
858         err = wifi_power_driver_and_supplicant(TRUE);
859         if (err < 0 && err != -EALREADY)
860                 return err;
861
862         err = _set_connman_technology_power(TRUE);
863
864         if (device_picker_test == TRUE)
865                 netconfig_wifi_enable_device_picker_test();
866
867         return err;
868 }
869 #endif
870
871 void wifi_power_initialize(void)
872 {
873         int wifi_last_power_state = 0;
874
875         /* Initialize Airplane mode */
876         netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &airplane_mode);
877         DBG("Airplane[%s]", airplane_mode > 0 ? "ON" : "OFF");
878
879         /* Update the last Wi-Fi power state */
880         netconfig_vconf_get_int(VCONF_WIFI_LAST_POWER_STATE, &wifi_last_power_state);
881         if (wifi_last_power_state > VCONFKEY_WIFI_OFF) {
882 #if defined TIZEN_TELEPHONY_ENABLE
883                 int telephony_ready = 0;
884                 netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_READY, &telephony_ready);
885                 if (telephony_ready == 0) {
886                         DBG("Telephony API is not initialized yet");
887                         vconf_notify_key_changed(VCONFKEY_TELEPHONY_READY,
888                                         __netconfig_telephony_ready_changed_cb, NULL);
889                 } else {
890                         if (netconfig_tapi_check_sim_state() == FALSE)
891                                 DBG("SIM is not initialized yet");
892                 }
893 #endif
894                 DBG("Turn Wi-Fi on automatically");
895 #if defined TIZEN_WEARABLE
896                 wifi_power_on_wearable(TRUE);
897 #else
898                 wifi_power_on();
899 #endif
900         }
901
902 #if defined TIZEN_WEARABLE
903         vconf_notify_key_changed(VCONF_WIFI_WEARABLE_WIFI_USE, __wearable_wifi_use_changed_cb, NULL);
904
905         vconf_notify_key_changed(VCONFKEY_TELEPHONY_FLIGHT_MODE,
906                         __netconfig_wifi_airplane_mode, NULL);
907 #else
908         vconf_notify_key_changed(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE,
909                         __netconfig_wifi_restrict_mode, NULL);
910         vconf_notify_key_changed(VCONFKEY_TELEPHONY_FLIGHT_MODE,
911                         __netconfig_wifi_airplane_mode, NULL);
912 #endif
913
914         vconf_notify_key_changed(VCONFKEY_SETAPPL_PSMODE, __emergency_mode_changed_cb, NULL);
915         vconf_notify_key_changed(VCONFKEY_PM_STATE, __pm_state_changed_cb, NULL);
916 }
917
918 void wifi_power_deinitialize(void)
919 {
920 }
921
922 gboolean handle_load_driver(Wifi *wifi,
923                 GDBusMethodInvocation *context, gboolean device_picker_test)
924 {
925         int err;
926
927         DBG("Wi-Fi power on requested");
928
929         g_return_val_if_fail(wifi != NULL, FALSE);
930
931         if (!netconfig_dpm_update_from_wifi()) {
932                 DBG("DPM policy restricts Wi-Fi");
933                 netconfig_error_permission_denied(context);
934                 return TRUE;
935         }
936
937 #if defined TIZEN_WLAN_BOARD_SPRD
938         wifi_firmware_download();
939 #endif
940
941 #if defined TIZEN_WEARABLE
942         err = wifi_power_on_wearable(device_picker_test);
943 #else
944         err = wifi_power_on();
945
946         if (device_picker_test == TRUE)
947                 netconfig_wifi_enable_device_picker_test();
948 #endif
949         if (err < 0) {
950                 if (err == -EINPROGRESS)
951                         netconfig_error_inprogress(context);
952                 else if (err == -EALREADY)
953                         netconfig_error_already_exists(context);
954                 else if (err == -EPERM)
955                         netconfig_error_permission_denied(context);
956                 else
957                         netconfig_error_wifi_driver_failed(context);
958
959                 return TRUE;
960         }
961
962
963         netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
964         __netconfig_set_wifi_bssid();
965
966         wifi_complete_load_driver(wifi, context);
967         return TRUE;
968 }
969
970 gboolean handle_remove_driver(Wifi *wifi, GDBusMethodInvocation *context)
971 {
972         int err;
973
974         DBG("Wi-Fi power off requested");
975
976         g_return_val_if_fail(wifi != NULL, FALSE);
977
978         err = wifi_power_off();
979         if (err < 0) {
980                 if (err == -EINPROGRESS)
981                         netconfig_error_inprogress(context);
982                 else if (err == -EALREADY)
983                         netconfig_error_already_exists(context);
984                 else if (err == -EPERM)
985                         netconfig_error_permission_denied(context);
986                 else
987                         netconfig_error_wifi_driver_failed(context);
988                 return TRUE;
989         }
990
991         netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
992
993         wifi_complete_remove_driver(wifi, context);
994         return TRUE;
995 }
996
997 gboolean handle_load_p2p_driver(Wifi *wifi, GDBusMethodInvocation *context)
998 {
999         ERR("Deprecated");
1000
1001         wifi_complete_load_p2p_driver(wifi, context);
1002         return TRUE;
1003 }
1004
1005 gboolean handle_remove_p2p_driver(Wifi *wifi, GDBusMethodInvocation *context)
1006 {
1007         ERR("Deprecated");
1008
1009         wifi_complete_remove_p2p_driver(wifi, context);
1010         return TRUE;
1011 }
1012
1013 #if defined TIZEN_TV
1014 static int __netconfig_get_random_mac(unsigned char *mac_buf, int mac_len)
1015 {
1016         DBG("Generate Random Mac address of ethernet");
1017         FILE *fp;
1018         int rc;
1019
1020         fp = fopen(OS_RANDOM_FILE, "rb");
1021
1022         if (fp == NULL) {
1023                 ERR("Could not open /dev/urandom");
1024                 return -1;
1025         }
1026         rc = fread(mac_buf, 1, mac_len, fp);
1027         if (fp)
1028                 fclose(fp);
1029
1030         return rc != mac_len ? -1 : 0;
1031 }
1032
1033 void __netconfig_set_ether_macaddr()
1034 {
1035         DBG("Set wired Mac address ");
1036         char *mac_addr = NULL;
1037         char rand_addr[WLAN_MAC_ADDR_MAX];
1038         int rv = -1;
1039
1040         mac_addr = vconf_get_str(VCONF_ETH_MAC_ADDRESS);
1041         if (mac_addr == NULL) {
1042                 DBG("vconf_get_str Failed\n");
1043                 return;
1044         }
1045         /* Checking Invalid MAC Address */
1046         if ((strlen(mac_addr) == 0)) {
1047                 ERR("Failed to get valid MAC Address from vconf");
1048                 /*Generate the Random Mac address*/
1049                 unsigned char rand_mac_add[ETH_MAC_ADDR_SIZE+1];
1050
1051                 if (__netconfig_get_random_mac(rand_mac_add, ETH_MAC_ADDR_SIZE) == -1) {
1052
1053                         ERR("Could not generate the Random Mac address");
1054                         g_free(mac_addr);
1055                         return;
1056                 }
1057
1058                 rand_mac_add[0] &= 0xFE; /*Clear multicase bit*/
1059                 rand_mac_add[0] |= 0x02; /*set local assignment bit*/
1060
1061                 /*Set the Mac address in Vconf*/
1062                 snprintf(rand_addr, WLAN_MAC_ADDR_MAX, "%x:%x:%x:%x:%x:%x",
1063                                 rand_mac_add[0], rand_mac_add[1],
1064                                 rand_mac_add[2], rand_mac_add[3],
1065                                 rand_mac_add[4], rand_mac_add[5]);
1066
1067                 netconfig_set_vconf_str(VCONF_ETH_MAC_ADDRESS, rand_addr);
1068         } else { /* Valid MAC address */
1069                 strncpy(rand_addr, mac_addr, strlen(mac_addr));
1070                 rand_addr[strlen(mac_addr)] = '\0';
1071         }
1072
1073         DBG("MAC Address of eth0 [%s]", rand_addr);
1074         const char *path = NET_EXEC_PATH;
1075         char *const args[] = { "/sbin/ifconfig", "eth0", "hw",
1076                 "ether", rand_addr, "up", NULL};
1077         char *const envs[] = { NULL };
1078         rv = netconfig_execute_file(path, args, envs);
1079
1080         if (rv < 0)
1081                 ERR("Unable to execute system command");
1082         g_free(mac_addr);
1083
1084 }
1085 #endif