Removed unused netconfig_wifi_on/off function
[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 #if defined TIZEN_WEARABLE
369 int netconfig_wifi_on_wearable(gboolean device_picker_test)
370 {
371         int err = 0;
372         int wifi_use;
373         int ps_mode;
374
375         if (netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use) < 0) {
376                 ERR("Fail to get VCONF_WIFI_WEARABLE_WIFI_USE");
377                 return -EIO;
378         }
379
380         if (wifi_use > 0) {
381                 if (netconfig_vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &ps_mode) < 0) {
382                         ERR("Fail to get VCONFKEY_SETAPPL_PSMODE");
383                         return -EIO;
384                 }
385
386                 if (ps_mode > SETTING_PSMODE_NORMAL) {
387                         WARN("ps mode is on(%d), Not turn on Wi-Fi", ps_mode);
388                         return -EPERM;
389                 }
390         } else {
391                 WARN("Not permitted Wi-Fi on");
392                 return -EPERM;
393         }
394
395         err = wifi_power_driver_and_supplicant(TRUE);
396         if (err < 0 && err != -EALREADY)
397                 return err;
398
399         err = _set_connman_technology_power(TRUE);
400
401         if (device_picker_test == TRUE)
402                 netconfig_wifi_enable_device_picker_test();
403
404         return err;
405 }
406
407 static void __wearable_wifi_use_changed_cb(keynode_t* node, void* user_data)
408 {
409         int wifi_state;
410         int wifi_use = 1;
411
412         if (netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state) < 0) {
413                 ERR("Fail to get VCONFKEY_WIFI_STATE");
414                 return;
415         }
416
417         if (node != NULL)
418                 wifi_use = vconf_keynode_get_int(node);
419         else
420                 netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use);
421
422         if (wifi_use > 0) {
423                 DBG("wifi use on");
424                 if (wifi_state > VCONFKEY_WIFI_OFF) {
425                         WARN("Wi-Fi is already turned on");
426                         return;
427                 }
428                 wifi_power_on_wearable(TRUE);
429         } else {
430                 ERR("## wifi use [OFF]");
431                 if (wifi_state == VCONFKEY_WIFI_OFF) {
432                         WARN("Wi-Fi is already turned off");
433                         return;
434                 }
435
436                 wifi_power_off();
437         }
438 }
439 #else
440 static void __netconfig_wifi_restrict_mode(keynode_t *node, void *user_data)
441 {
442         int wifi_state = 0, restricted = 0;
443         int wifi_off_by_restricted = 0;
444
445         netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, &wifi_off_by_restricted);
446
447         netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
448
449         if (node != NULL)
450                 restricted = vconf_keynode_get_bool(node);
451         else
452                 netconfig_vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE, &restricted);
453
454         DBG("network restricted mode %s", restricted > 0 ? "ON" : "OFF");
455         DBG("Wi-Fi state %d, Wi-Fi was off by restricted mode %s", wifi_state,
456                         wifi_off_by_restricted ? "Yes" : "No");
457
458         if (restricted > 0) {
459                 /* network restricted on */
460                 if (wifi_state == VCONFKEY_WIFI_OFF)
461                         return;
462
463                 wifi_power_off();
464
465                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, 1);
466         } else {
467                 /* network restricted off */
468                 if (!wifi_off_by_restricted)
469                         return;
470
471                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, 0);
472
473                 if (wifi_state > VCONFKEY_WIFI_OFF)
474                         return;
475
476                 wifi_power_on();
477         }
478 }
479 #endif
480
481 static void __netconfig_wifi_airplane_mode(keynode_t *node, void *user_data)
482 {
483         int wifi_state = 0, airplane_state = 0;
484         int wifi_off_by_airplane = 0;
485
486         netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, &wifi_off_by_airplane);
487
488 #if defined TIZEN_WEARABLE
489         netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_state)
490 #else
491         netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
492 #endif
493
494         if (node != NULL)
495                 airplane_state = vconf_keynode_get_bool(node);
496         else
497                 netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &airplane_state);
498
499         DBG("airplane mode %s (prev:%d)", airplane_state > 0 ? "ON" : "OFF", airplane_mode);
500         DBG("Wi-Fi state(or use) %d, Wi-Fi was off by flight mode %s", wifi_state,
501                         wifi_off_by_airplane ? "Yes" : "No");
502
503         if (airplane_mode == airplane_state)
504                 return ;
505
506         airplane_mode = airplane_state;
507
508         if (airplane_state > 0) {
509                 /* airplane mode on */
510                 if (wifi_state == VCONFKEY_WIFI_OFF)
511                         return;
512
513                 wifi_power_off();
514
515                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 1);
516 #if defined TIZEN_WEARABLE
517                 netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, 0);
518 #endif
519         } else {
520                 /* airplane mode off */
521                 if (!wifi_off_by_airplane)
522                         return;
523
524                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
525 #if defined TIZEN_WEARABLE
526                 netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, 1);
527 #else
528                 if (wifi_state > VCONFKEY_WIFI_OFF)
529                         return;
530
531                 wifi_power_on();
532 #endif
533         }
534 }
535
536 static void __emergency_mode_changed_cb(keynode_t *node, void *user_data)
537 {
538         int wifi_state = 0, emergency = 0;
539         int wifi_off_by_emergency = 0;
540 #if !defined TIZEN_WEARABLE
541         int emergency_by_fmm = 0;
542 #endif
543 #if defined TIZEN_WEARABLE
544         int wifi_use = 1;
545 #endif
546
547         netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, &wifi_off_by_emergency);
548         netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
549
550 #if !defined TIZEN_WEARABLE
551         netconfig_vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_PERMIT_WITH_LCD_OFF_LIMIT, &emergency_by_fmm);
552         DBG("emergency mode by Find My Mobile (%d)", emergency_by_fmm);
553         if (emergency_by_fmm == 1)
554                 return;
555 #endif
556
557         if (node != NULL)
558                 emergency = vconf_keynode_get_int(node);
559         else
560                 netconfig_vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &emergency);
561
562         DBG("emergency mode %s", emergency > SETTING_PSMODE_POWERFUL ? "ON" : "OFF");
563         DBG("Wi-Fi state %d, Wi-Fi was off by emergency mode %s", wifi_state, wifi_off_by_emergency ? "Yes" : "No");
564
565 #if defined TIZEN_WEARABLE
566         if (emergency == SETTING_PSMODE_WEARABLE) {
567                 /* basic power saving mode on */
568         } else if (emergency == SETTING_PSMODE_WEARABLE_ENHANCED) {
569                 /* enhanced power saving mode on */
570                 netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use);
571                 psmode_wifi_use = wifi_use;
572                 if (wifi_use != 0)
573                         netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, 0);
574
575                 if (wifi_state == VCONFKEY_WIFI_OFF)
576                         return;
577
578                 wifi_power_off();
579                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 1);
580         } else {
581                 /* power saving mode off */
582                 netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, psmode_wifi_use);
583                 if (!wifi_off_by_emergency)
584                         return;
585
586                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 0);
587                 if (wifi_state > VCONFKEY_WIFI_OFF)
588                         return;
589
590                 wifi_power_on_wearable(TRUE);
591         }
592 #else
593         if (emergency > SETTING_PSMODE_POWERFUL) {
594                 /* emergency mode on */
595                 if (wifi_state == VCONFKEY_WIFI_OFF)
596                         return;
597
598                 wifi_power_off();
599
600                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 1);
601         } else {
602                 /* emergency mode off */
603                 if (!wifi_off_by_emergency)
604                         return;
605
606                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 0);
607
608                 if (wifi_state > VCONFKEY_WIFI_OFF)
609                         return;
610
611                 wifi_power_on();
612         }
613 #endif
614
615 }
616
617 static void __pm_state_changed_cb(keynode_t* node, void* user_data)
618 {
619         int new_state = -1;
620         int wifi_state = 0;
621         static int prev_state = VCONFKEY_PM_STATE_NORMAL;
622
623         if (netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state) < 0) {
624                 ERR("Fail to get VCONFKEY_WIFI_STATE");
625                 return;
626         }
627
628         /* PM state
629          *      VCONFKEY_PM_STATE_NORMAL = 1,
630          *      VCONFKEY_PM_STATE_LCDDIM,
631          *      VCONFKEY_PM_STATE_LCDOFF,
632          *      VCONFKEY_PM_STATE_SLEEP
633          */
634         if (node != NULL)
635                 new_state = vconf_keynode_get_int(node);
636         else
637                 netconfig_vconf_get_int(VCONFKEY_PM_STATE, &new_state);
638
639         DBG("wifi state: %d (0 off / 1 on / 2 connected)", wifi_state);
640         DBG("Old PM state: %d, current: %d", prev_state, new_state);
641
642         if ((new_state == VCONFKEY_PM_STATE_NORMAL) && (prev_state >= VCONFKEY_PM_STATE_LCDOFF)) {
643                 netconfig_wifi_bgscan_stop();
644                 netconfig_wifi_bgscan_start(TRUE);
645         }
646
647         prev_state = new_state;
648 }
649
650 #if defined TIZEN_TELEPHONY_ENABLE
651 static void _tapi_noti_sim_status_cb(TapiHandle *handle, const char *noti_id,
652                                                                                 void *data, void *user_data)
653 {
654         TelSimCardStatus_t *status = data;
655
656         if (*status == TAPI_SIM_STATUS_SIM_INIT_COMPLETED) {
657                 DBG("Turn Wi-Fi on automatically");
658 #if defined TIZEN_WEARABLE
659                 wifi_power_on_wearable(TRUE);
660 #else
661                 wifi_power_on();
662 #endif
663                 netconfig_tel_deinit();
664         }
665 }
666
667 static gboolean netconfig_tapi_check_sim_state(void)
668 {
669         int ret, card_changed;
670         TelSimCardStatus_t status = TAPI_SIM_STATUS_UNKNOWN;
671         TapiHandle *tapi_handle = NULL;
672
673         tapi_handle = (TapiHandle *)netconfig_tel_init();
674         if (tapi_handle == NULL) {
675                 ERR("Failed to tapi init");
676                 return FALSE;
677         }
678
679         ret = tel_get_sim_init_info(tapi_handle, &status, &card_changed);
680         if (ret != TAPI_API_SUCCESS) {
681                 ERR("tel_get_sim_init_info() Failed : [%d]", ret);
682                 netconfig_tel_deinit();
683                 return FALSE;
684         }
685
686         switch (status) {
687         case TAPI_SIM_STATUS_UNKNOWN:
688         case TAPI_SIM_STATUS_CARD_ERROR:
689         case TAPI_SIM_STATUS_CARD_NOT_PRESENT:
690         case TAPI_SIM_STATUS_CARD_BLOCKED:
691         case TAPI_SIM_STATUS_SIM_INIT_COMPLETED:
692                 break;
693         case TAPI_SIM_STATUS_SIM_PIN_REQUIRED:
694         case TAPI_SIM_STATUS_SIM_INITIALIZING:
695         case TAPI_SIM_STATUS_SIM_PUK_REQUIRED:
696         case TAPI_SIM_STATUS_SIM_LOCK_REQUIRED:
697         case TAPI_SIM_STATUS_SIM_NCK_REQUIRED:
698         case TAPI_SIM_STATUS_SIM_NSCK_REQUIRED:
699         case TAPI_SIM_STATUS_SIM_SPCK_REQUIRED:
700         case TAPI_SIM_STATUS_SIM_CCK_REQUIRED:
701                 tel_register_noti_event(tapi_handle, TAPI_NOTI_SIM_STATUS,
702                                 _tapi_noti_sim_status_cb, NULL);
703                 return FALSE;
704         default:
705                 ERR("not defined status(%d)", status);
706                 break;
707         }
708
709         netconfig_tel_deinit();
710
711         return TRUE;
712 }
713
714 static void __netconfig_telephony_ready_changed_cb(keynode_t * node, void *data)
715 {
716         int telephony_ready = 0;
717
718         if (node != NULL)
719                 telephony_ready = vconf_keynode_get_bool(node);
720         else
721                 netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_READY, &telephony_ready);
722
723         if (telephony_ready != 0) {
724                 if (netconfig_tapi_check_sim_state() == FALSE) {
725                         DBG("Sim is not initialized yet.");
726
727                         goto done;
728                 }
729         } else
730                 return;
731
732         DBG("Turn Wi-Fi on automatically");
733
734 #if defined TIZEN_WEARABLE
735         wifi_power_on_wearable(TRUE);
736 #else
737         wifi_power_on();
738 #endif
739
740 done:
741         vconf_ignore_key_changed(VCONFKEY_TELEPHONY_READY, __netconfig_telephony_ready_changed_cb);
742 }
743 #endif
744
745 int wifi_power_driver_and_supplicant(gboolean enable)
746 {
747         /* There are 3 thumb rules for Wi-Fi power management
748          *   1. Do not make exposed API to control wpa_supplicant and driver directly.
749          *      It probably breaks ConnMan technology operation.
750          *
751          *   2. Do not remove driver and wpa_supplicant if ConnMan already enabled.
752          *      It breaks ConnMan technology operation.
753          *
754          *   3. Final the best rule: make it as simple as possible.
755          *      Simple code enables easy maintenance and reduces logical errors.
756          */
757         if (enable == TRUE) {
758                 return _load_driver_and_supplicant();
759         } else {
760                 if (connman_wifi_technology_state == TRUE)
761                         return -ENOSYS;
762
763                 return _remove_driver_and_supplicant();
764         }
765 }
766
767 void wifi_power_disable_technology_state_by_only_connman_signal(void)
768 {
769         /* Important: it's only done by ConnMan technology signal update */
770         connman_wifi_technology_state = FALSE;
771 }
772
773 void wifi_power_recover_firmware(void)
774 {
775         wifi_firmware_recovery_mode = TRUE;
776
777         netconfig_wifi_bgscan_stop();
778
779         wifi_power_off();
780 }
781
782 int wifi_power_on(void)
783 {
784         int err = 0;
785         wifi_tech_state_e tech_state;
786
787         tech_state = wifi_state_get_technology_state();
788         if (tech_state >= NETCONFIG_WIFI_TECH_POWERED)
789                 return -EALREADY;
790
791         if (__is_wifi_restricted() == TRUE)
792                 return -EPERM;
793
794         if (netconfig_is_wifi_tethering_on() == TRUE) {
795                 /* TODO: Wi-Fi tethering turns off here */
796                 /* return TRUE; */
797                 ERR("Failed to turn tethering off");
798                 return -EBUSY;
799         }
800
801 #if defined TIZEN_P2P_ENABLE && !defined WLAN_CONCURRENT_MODE
802         if (netconfig_is_wifi_direct_on() == TRUE) {
803                 if (__netconfig_wifi_direct_power_off() == TRUE)
804                         return -EINPROGRESS;
805                 else {
806                         ERR("Failed to turn Wi-Fi direct off");
807                         return -EBUSY;
808                 }
809         }
810 #endif
811
812         err = wifi_power_driver_and_supplicant(TRUE);
813         if (err < 0 && err != -EALREADY)
814                 return err;
815
816         err = _set_connman_technology_power(TRUE);
817
818         return err;
819 }
820
821 int wifi_power_off(void)
822 {
823         int err;
824
825         err = _set_connman_technology_power(FALSE);
826         if (err == -EALREADY)
827                 wifi_state_update_power_state(FALSE);
828
829         return 0;
830 }
831
832 #if defined TIZEN_WEARABLE
833 int wifi_power_on_wearable(gboolean device_picker_test)
834 {
835         int err = 0;
836         int wifi_use = 1;
837         wifi_tech_state_e tech_state;
838
839         tech_state = wifi_state_get_technology_state();
840         if (tech_state >= NETCONFIG_WIFI_TECH_POWERED)
841                 return -EALREADY;
842
843         if (netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use) < 0) {
844                 ERR("Fail to get VCONF_WIFI_WEARABLE_WIFI_USE");
845                 return -EIO;
846         }
847
848         if (wifi_use == 0) {
849                 WARN("VCONF_WIFI_WEARABLE_WIFI_USE is OFF");
850                 return -EPERM;
851         }
852
853         err = wifi_power_driver_and_supplicant(TRUE);
854         if (err < 0 && err != -EALREADY)
855                 return err;
856
857         err = _set_connman_technology_power(TRUE);
858
859         if (device_picker_test == TRUE)
860                 netconfig_wifi_enable_device_picker_test();
861
862         return err;
863 }
864 #endif
865
866 void wifi_power_initialize(void)
867 {
868         int wifi_last_power_state = 0;
869
870         /* Initialize Airplane mode */
871         netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &airplane_mode);
872         DBG("Airplane[%s]", airplane_mode > 0 ? "ON" : "OFF");
873
874         /* Update the last Wi-Fi power state */
875         netconfig_vconf_get_int(VCONF_WIFI_LAST_POWER_STATE, &wifi_last_power_state);
876         if (wifi_last_power_state > VCONFKEY_WIFI_OFF) {
877 #if defined TIZEN_TELEPHONY_ENABLE
878                 int telephony_ready = 0;
879                 netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_READY, &telephony_ready);
880                 if (telephony_ready == 0) {
881                         DBG("Telephony API is not initialized yet");
882                         vconf_notify_key_changed(VCONFKEY_TELEPHONY_READY,
883                                         __netconfig_telephony_ready_changed_cb, NULL);
884                 } else {
885                         if (netconfig_tapi_check_sim_state() == FALSE)
886                                 DBG("SIM is not initialized yet");
887                 }
888 #endif
889                 DBG("Turn Wi-Fi on automatically");
890 #if defined TIZEN_WEARABLE
891                 wifi_power_on_wearable(TRUE);
892 #else
893                 wifi_power_on();
894 #endif
895         }
896
897 #if defined TIZEN_WEARABLE
898         vconf_notify_key_changed(VCONF_WIFI_WEARABLE_WIFI_USE, __wearable_wifi_use_changed_cb, NULL);
899
900         vconf_notify_key_changed(VCONFKEY_TELEPHONY_FLIGHT_MODE,
901                         __netconfig_wifi_airplane_mode, NULL);
902 #else
903         vconf_notify_key_changed(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE,
904                         __netconfig_wifi_restrict_mode, NULL);
905         vconf_notify_key_changed(VCONFKEY_TELEPHONY_FLIGHT_MODE,
906                         __netconfig_wifi_airplane_mode, NULL);
907 #endif
908
909         vconf_notify_key_changed(VCONFKEY_SETAPPL_PSMODE, __emergency_mode_changed_cb, NULL);
910         vconf_notify_key_changed(VCONFKEY_PM_STATE, __pm_state_changed_cb, NULL);
911 }
912
913 void wifi_power_deinitialize(void)
914 {
915 }
916
917 gboolean handle_load_driver(Wifi *wifi,
918                 GDBusMethodInvocation *context, gboolean device_picker_test)
919 {
920         int err;
921
922         DBG("Wi-Fi power on requested");
923
924         g_return_val_if_fail(wifi != NULL, FALSE);
925
926         if (!netconfig_dpm_update_from_wifi()) {
927                 DBG("DPM policy restricts Wi-Fi");
928                 netconfig_error_permission_denied(context);
929                 return TRUE;
930         }
931
932 #if defined TIZEN_WLAN_BOARD_SPRD
933         wifi_firmware_download();
934 #endif
935
936 #if defined TIZEN_WEARABLE
937         err = wifi_power_on_wearable(device_picker_test);
938 #else
939         err = wifi_power_on();
940
941         if (device_picker_test == TRUE)
942                 netconfig_wifi_enable_device_picker_test();
943 #endif
944         if (err < 0) {
945                 if (err == -EINPROGRESS)
946                         netconfig_error_inprogress(context);
947                 else if (err == -EALREADY)
948                         netconfig_error_already_exists(context);
949                 else if (err == -EPERM)
950                         netconfig_error_permission_denied(context);
951                 else
952                         netconfig_error_wifi_driver_failed(context);
953
954                 return TRUE;
955         }
956
957
958         netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
959         __netconfig_set_wifi_bssid();
960
961         wifi_complete_load_driver(wifi, context);
962         return TRUE;
963 }
964
965 gboolean handle_remove_driver(Wifi *wifi, GDBusMethodInvocation *context)
966 {
967         int err;
968
969         DBG("Wi-Fi power off requested");
970
971         g_return_val_if_fail(wifi != NULL, FALSE);
972
973         err = wifi_power_off();
974         if (err < 0) {
975                 if (err == -EINPROGRESS)
976                         netconfig_error_inprogress(context);
977                 else if (err == -EALREADY)
978                         netconfig_error_already_exists(context);
979                 else if (err == -EPERM)
980                         netconfig_error_permission_denied(context);
981                 else
982                         netconfig_error_wifi_driver_failed(context);
983                 return TRUE;
984         }
985
986         netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
987
988         wifi_complete_remove_driver(wifi, context);
989         return TRUE;
990 }
991
992 gboolean handle_load_p2p_driver(Wifi *wifi, GDBusMethodInvocation *context)
993 {
994         ERR("Deprecated");
995
996         wifi_complete_load_p2p_driver(wifi, context);
997         return TRUE;
998 }
999
1000 gboolean handle_remove_p2p_driver(Wifi *wifi, GDBusMethodInvocation *context)
1001 {
1002         ERR("Deprecated");
1003
1004         wifi_complete_remove_p2p_driver(wifi, context);
1005         return TRUE;
1006 }
1007
1008 #if defined TIZEN_TV
1009 static int __netconfig_get_random_mac(unsigned char *mac_buf, int mac_len)
1010 {
1011         DBG("Generate Random Mac address of ethernet");
1012         FILE *fp;
1013         int rc;
1014
1015         fp = fopen(OS_RANDOM_FILE, "rb");
1016
1017         if (fp == NULL) {
1018                 ERR("Could not open /dev/urandom");
1019                 return -1;
1020         }
1021         rc = fread(mac_buf, 1, mac_len, fp);
1022         if (fp)
1023                 fclose(fp);
1024
1025         return rc != mac_len ? -1 : 0;
1026 }
1027
1028 void __netconfig_set_ether_macaddr()
1029 {
1030         DBG("Set wired Mac address ");
1031         char *mac_addr = NULL;
1032         char rand_addr[WLAN_MAC_ADDR_MAX];
1033         int rv = -1;
1034
1035         mac_addr = vconf_get_str(VCONF_ETH_MAC_ADDRESS);
1036         if (mac_addr == NULL) {
1037                 DBG("vconf_get_str Failed\n");
1038                 return;
1039         }
1040         /* Checking Invalid MAC Address */
1041         if ((strlen(mac_addr) == 0)) {
1042                 ERR("Failed to get valid MAC Address from vconf");
1043                 /*Generate the Random Mac address*/
1044                 unsigned char rand_mac_add[ETH_MAC_ADDR_SIZE+1];
1045
1046                 if (__netconfig_get_random_mac(rand_mac_add, ETH_MAC_ADDR_SIZE) == -1) {
1047
1048                         ERR("Could not generate the Random Mac address");
1049                         g_free(mac_addr);
1050                         return;
1051                 }
1052
1053                 rand_mac_add[0] &= 0xFE; /*Clear multicase bit*/
1054                 rand_mac_add[0] |= 0x02; /*set local assignment bit*/
1055
1056                 /*Set the Mac address in Vconf*/
1057                 snprintf(rand_addr, WLAN_MAC_ADDR_MAX, "%x:%x:%x:%x:%x:%x",
1058                                 rand_mac_add[0], rand_mac_add[1],
1059                                 rand_mac_add[2], rand_mac_add[3],
1060                                 rand_mac_add[4], rand_mac_add[5]);
1061
1062                 netconfig_set_vconf_str(VCONF_ETH_MAC_ADDRESS, rand_addr);
1063         } else { /* Valid MAC address */
1064                 strncpy(rand_addr, mac_addr, strlen(mac_addr));
1065                 rand_addr[strlen(mac_addr)] = '\0';
1066         }
1067
1068         DBG("MAC Address of eth0 [%s]", rand_addr);
1069         const char *path = NET_EXEC_PATH;
1070         char *const args[] = { "/sbin/ifconfig", "eth0", "hw",
1071                 "ether", rand_addr, "up", NULL};
1072         char *const envs[] = { NULL };
1073         rv = netconfig_execute_file(path, args, envs);
1074
1075         if (rv < 0)
1076                 ERR("Unable to execute system command");
1077         g_free(mac_addr);
1078
1079 }
1080 #endif