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