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