fa33939cd9b353700896d17e58e9bc06654c0811
[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 "wifi-firmware.h"
43 #include "wifi-background-scan.h"
44
45
46 #define WLAN_SUPPLICANT_SCRIPT          "/usr/sbin/wpa_supp.sh"
47 #define P2P_SUPPLICANT_SCRIPT           "/usr/sbin/p2p_supp.sh"
48
49 #if defined TIZEN_WEARABLE
50 #include <weconn.h>
51 static weconn_h weconn_handle = NULL;
52 #endif
53
54 #define VCONF_WIFI_OFF_STATE_BY_AIRPLANE        "file/private/wifi/wifi_off_by_airplane"
55 #define VCONF_WIFI_OFF_STATE_BY_RESTRICTED      "file/private/wifi/wifi_off_by_restricted"
56 #define VCONF_WIFI_OFF_STATE_BY_EMERGENCY       "file/private/wifi/wifi_off_by_emergency"
57 #if defined TIZEN_WEARABLE
58 #define VCONF_WIFI_WEARABLE_WIFI_USE                    "db/private/wifi/wearable_wifi_use"
59 #endif
60 #if !defined TIZEN_WEARABLE
61 #define VCONFKEY_SETAPPL_NETWORK_PERMIT_WITH_LCD_OFF_LIMIT      "db/setting/network_with_lcd_off_limit"
62 #endif
63
64 #define WLAN_MAC_INFO               tzplatform_mkpath(TZ_SYS_SHARE, "/.mac.info")
65 #define WLAN_MAC_ADDR_MAX           20
66 #define VCONF_WIFI_BSSID_ADDRESS        "db/wifi/bssid_address"
67
68 #if defined TIZEN_TV
69 #define ETH_MAC_ADDR_SIZE 6
70 #define VCONF_ETH_MAC_ADDRESS  "db/dnet/mac_address"
71 #define NET_EXEC_PATH "/sbin/ifconfig"
72 #define OS_RANDOM_FILE "/dev/urandom"
73 #endif
74
75 static gboolean connman_wifi_technology_state = FALSE;
76 static gboolean wifi_firmware_recovery_mode = FALSE;
77 static int airplane_mode = 0;
78
79 #if defined TIZEN_WEARABLE
80 static int psmode_wifi_use = 1;
81 #endif
82
83 static gboolean __is_wifi_restricted(void)
84 {
85 #if defined TIZEN_WEARABLE
86         return FALSE;
87 #endif
88         int restricted_mode = 0;
89
90         vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE, &restricted_mode);
91         if (restricted_mode != 0) {
92                 DBG("network restricted mode[%d]", restricted_mode);
93                 return TRUE;
94         }
95
96         return FALSE;
97 }
98
99 static void __technology_reply(GObject *source_object, GAsyncResult *res, gpointer user_data)
100 {
101         GVariant *reply;
102         GDBusConnection *conn = NULL;
103         GError *error = NULL;
104
105         conn = G_DBUS_CONNECTION (source_object);
106         reply = g_dbus_connection_call_finish(conn, res, &error);
107
108         if (reply == NULL) {
109                 if (error != NULL) {
110                         if (g_strcmp0(error->message, CONNMAN_ERROR_INTERFACE ".AlreadyEnabled") == 0) {
111                                 wifi_state_update_power_state(TRUE);
112                         } else if (g_strcmp0(error->message, CONNMAN_ERROR_INTERFACE ".AlreadyDisabled") == 0) {
113                                 wifi_state_update_power_state(FALSE);
114                         } else {
115                                 ERR("Fail to request status [%d: %s]", error->code, error->message);
116                         }
117                         g_error_free(error);
118                 } else {
119                         ERR("Fail torequest status");
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         enum netconfig_wifi_tech_state wifi_tech_state;
431         weconn_service_state_e weconn_state;
432
433         wifi_tech_state = wifi_state_get_technology_state();
434         if (wifi_tech_state >= NETCONFIG_WIFI_TECH_POWERED)
435                 return -EALREADY;
436
437         err = weconn_get_service_state(weconn_handle, W_SERVICE_TYPE_BT,
438                         &weconn_state);
439         if (err == 0 && weconn_state == W_SERVICE_STATE_CONNECTED) {
440                 WARN("Not permitted Wi-Fi on");
441                 return -EPERM;
442         }
443
444         if (vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use) < 0) {
445                 ERR("Fail to get VCONF_WIFI_WEARABLE_WIFI_USE");
446                 return -EIO;
447         }
448
449         if (wifi_use > 0) {
450                 if (vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &ps_mode) < 0) {
451                         ERR("Fail to get VCONFKEY_SETAPPL_PSMODE");
452                         return -EIO;
453                 }
454
455                 if (ps_mode > SETTING_PSMODE_NORMAL) {
456                         WARN("ps mode is on(%d), Not turn on Wi-Fi", ps_mode);
457                         return -EPERM;
458                 }
459         } else {
460                 WARN("Not permitted Wi-Fi on");
461                 return -EPERM;
462         }
463
464         err = wifi_power_driver_and_supplicant(TRUE);
465         if (err < 0 && err != -EALREADY)
466                 return err;
467
468         err = _set_connman_technology_power(TRUE);
469
470         if (device_picker_test == TRUE)
471                 netconfig_wifi_enable_device_picker_test();
472
473         return err;
474 }
475
476 static void __weconn_service_state_changed_cb(weconn_service_state_e state, void *user_data)
477 {
478         if (state == W_SERVICE_STATE_CONNECTED) {
479                 DBG("SAP is connected");
480                 if (wifi_state > VCONFKEY_WIFI_OFF)
481                         wifi_power_off();
482         } else if (state == W_SERVICE_STATE_DISCONNECTED) {
483                 DBG("SAP is disconnected");
484                 wifi_power_on_wearable(FALSE);
485         }
486 }
487
488 static int _weconn_set_state_changed_cb(int service_type, void *user_data)
489 {
490         int ret;
491
492         if (weconn_handle) {
493                 weconn_destroy(weconn_handle);
494                 weconn_handle = NULL;
495         }
496
497         ret = weconn_create(&weconn_handle);
498         if (ret < 0) {
499                 ERR("Failed weconn_create(%d)", ret);
500                 return -1;
501         }
502
503         ret = weconn_set_service_state_change_cb(weconn_handle, __weconn_service_state_changed_cb, service_type, user_data);
504         if (ret < 0) {
505                 ERR("Failed weconn_set_service_state_change_cb(%d)", ret);
506                 return -1;
507         }
508
509         return 0;
510 }
511
512 static void __wearable_wifi_use_changed_cb(keynode_t* node, void* user_data)
513 {
514         int wifi_state;
515         int wifi_use = 1;
516         gboolean wifi_restrict = FALSE;
517
518         if (vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state) < 0) {
519                 ERR("Fail to get VCONFKEY_WIFI_STATE");
520                 return;
521         }
522
523         if (node != NULL)
524                 wifi_use = vconf_keynode_get_int(node);
525         else
526                 vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use);
527
528         if (wifi_use > 0) {
529                 DBG("wifi use on");
530                 if (wifi_state > VCONFKEY_WIFI_OFF) {
531                         WARN("Wi-Fi is already turned on");
532                         return;
533                 }
534
535                 wifi_restrict = netconfig_is_wifi_allowed();
536                 if (wifi_restrict == FALSE) {
537                         DBG("launch wifi restrict popup");
538                         netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, 0);
539                         wc_launch_syspopup(WC_POPUP_TYPE_WIFI_RESTRICT);
540                 } else {
541                         wifi_power_on_wearable(TRUE);
542                 }
543         } else {
544                 ERR("## wifi use [OFF]");
545                 if (wifi_state == VCONFKEY_WIFI_OFF) {
546                         WARN("Wi-Fi is already turned off");
547                         return;
548                 }
549
550                 wifi_power_off();
551         }
552 }
553
554 #if defined TIZEN_TELEPHONY_ENABLE
555 static void __netconfig_wifi_wearable_airplane_mode(keynode_t *node,
556                 void *user_data)
557 {
558         int wifi_use = 0, airplane_state = 0;
559         int wifi_use_off_by_airplane = 0;
560
561         vconf_get_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE,
562                         &wifi_use_off_by_airplane);
563
564         vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use);
565
566         if (node != NULL)
567                 airplane_state = vconf_keynode_get_bool(node);
568         else
569                 vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &airplane_state);
570
571         DBG("airplane mode %s (prev:%d)", airplane_state > 0 ? "ON" : "OFF", airplane_mode);
572         DBG("Wi-Fi use %d, Wi-Fi was off by flight mode %s", wifi_use,
573                         wifi_use_off_by_airplane ? "Yes" : "No");
574
575         if (airplane_mode == airplane_state)
576                 return ;
577
578         airplane_mode = airplane_state;
579
580         if (airplane_state > 0) {
581                 /* airplane mode on */
582                 if (wifi_use == 0)
583                         return;
584
585                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 1);
586                 netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, 0);
587
588         } else {
589                 /* airplane mode off */
590                 if (!wifi_use_off_by_airplane)
591                         return;
592
593                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
594                 netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, 1);
595         }
596 }
597 #endif
598 #else
599 #if defined TIZEN_TELEPHONY_ENABLE
600 static void __netconfig_wifi_airplane_mode(keynode_t *node, void *user_data)
601 {
602         int wifi_state = 0, airplane_state = 0;
603         int wifi_off_by_airplane = 0;
604
605         vconf_get_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, &wifi_off_by_airplane);
606
607         vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
608
609         if (node != NULL)
610                 airplane_state = vconf_keynode_get_bool(node);
611         else
612                 vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &airplane_state);
613
614         DBG("airplane mode %s (prev:%d)", airplane_state > 0 ? "ON" : "OFF", airplane_mode);
615         DBG("Wi-Fi state %d, Wi-Fi was off by flight mode %s", wifi_state,
616                         wifi_off_by_airplane ? "Yes" : "No");
617
618         if (airplane_mode == airplane_state)
619                 return ;
620
621         airplane_mode = airplane_state;
622
623         if (airplane_state > 0) {
624                 /* airplane mode on */
625                 if (wifi_state == VCONFKEY_WIFI_OFF)
626                         return;
627
628                 wifi_power_off();
629
630                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 1);
631         } else {
632                 /* airplane mode off */
633                 if (!wifi_off_by_airplane)
634                         return;
635
636                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
637
638                 if (wifi_state > VCONFKEY_WIFI_OFF)
639                         return;
640
641                 wifi_power_on();
642         }
643 }
644 #endif
645
646 static void __netconfig_wifi_restrict_mode(keynode_t *node, void *user_data)
647 {
648         int wifi_state = 0, restricted = 0;
649         int wifi_off_by_restricted = 0;
650
651         vconf_get_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, &wifi_off_by_restricted);
652
653         vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
654
655         if (node != NULL)
656                 restricted = vconf_keynode_get_bool(node);
657         else
658                 vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE, &restricted);
659
660         DBG("network restricted mode %s", restricted > 0 ? "ON" : "OFF");
661         DBG("Wi-Fi state %d, Wi-Fi was off by restricted mode %s", wifi_state,
662                         wifi_off_by_restricted ? "Yes" : "No");
663
664         if (restricted > 0) {
665                 /* network restricted on */
666                 if (wifi_state == VCONFKEY_WIFI_OFF)
667                         return;
668
669                 wifi_power_off();
670
671                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, 1);
672         } else {
673                 /* network restricted off */
674                 if (!wifi_off_by_restricted)
675                         return;
676
677                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, 0);
678
679                 if (wifi_state > VCONFKEY_WIFI_OFF)
680                         return;
681
682                 wifi_power_on();
683         }
684 }
685 #endif
686
687 static void __emergency_mode_changed_cb(keynode_t *node, void *user_data)
688 {
689         int wifi_state = 0, emergency = 0;
690         int wifi_off_by_emergency = 0;
691 #if !defined TIZEN_WEARABLE
692         int emergency_by_fmm = 0;
693 #endif
694 #if defined TIZEN_WEARABLE
695         int wifi_use = 1;
696 #endif
697
698         vconf_get_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, &wifi_off_by_emergency);
699         vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
700
701 #if !defined TIZEN_WEARABLE
702         vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_PERMIT_WITH_LCD_OFF_LIMIT, &emergency_by_fmm);
703         DBG("emergency mode by Find My Mobile (%d)", emergency_by_fmm);
704         if (emergency_by_fmm == 1)
705                 return;
706 #endif
707
708         if (node != NULL)
709                 emergency = vconf_keynode_get_int(node);
710         else
711                 vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &emergency);
712
713         DBG("emergency mode %s", emergency > SETTING_PSMODE_POWERFUL ? "ON" : "OFF");
714         DBG("Wi-Fi state %d, Wi-Fi was off by emergency mode %s", wifi_state, wifi_off_by_emergency ? "Yes" : "No");
715
716 #if defined TIZEN_WEARABLE
717         if (emergency == SETTING_PSMODE_WEARABLE) {
718                 /* basic power saving mode on */
719         } else if (emergency == SETTING_PSMODE_WEARABLE_ENHANCED) {
720                 /* enhanced power saving mode on */
721                 vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use);
722                 psmode_wifi_use = wifi_use;
723                 if (wifi_use != 0) {
724                         netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, 0);
725                 }
726
727                 if (wifi_state == VCONFKEY_WIFI_OFF)
728                         return;
729
730                 wifi_power_off();
731                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 1);
732         } else {
733                 /* power saving mode off */
734                 netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, psmode_wifi_use);
735                 if (!wifi_off_by_emergency)
736                         return;
737
738                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 0);
739                 if (wifi_state > VCONFKEY_WIFI_OFF)
740                         return;
741
742                 wifi_power_on_wearable(TRUE);
743         }
744 #else
745         if (emergency > SETTING_PSMODE_POWERFUL) {
746                 /* emergency mode on */
747                 if (wifi_state == VCONFKEY_WIFI_OFF)
748                         return;
749
750                 wifi_power_off();
751
752                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 1);
753         } else {
754                 /* emergency mode off */
755                 if (!wifi_off_by_emergency)
756                         return;
757
758                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 0);
759
760                 if (wifi_state > VCONFKEY_WIFI_OFF)
761                         return;
762
763                 wifi_power_on();
764         }
765 #endif
766
767 }
768
769 static void __pm_state_changed_cb(keynode_t* node, void* user_data)
770 {
771         int new_state = -1;
772         int wifi_state = 0;
773         static int prev_state = VCONFKEY_PM_STATE_NORMAL;
774
775         if (vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state) < 0) {
776                 ERR("Fail to get VCONFKEY_WIFI_STATE");
777                 return;
778         }
779
780         /* PM state
781          *      VCONFKEY_PM_STATE_NORMAL = 1,
782          *      VCONFKEY_PM_STATE_LCDDIM,
783          *      VCONFKEY_PM_STATE_LCDOFF,
784          *      VCONFKEY_PM_STATE_SLEEP
785          */
786         if (node != NULL)
787                 new_state = vconf_keynode_get_int(node);
788         else
789                 vconf_get_int(VCONFKEY_PM_STATE, &new_state);
790
791         DBG("wifi state: %d (0 off / 1 on / 2 connected)", wifi_state);
792         DBG("Old PM state: %d, current: %d", prev_state, new_state);
793
794         if ((new_state == VCONFKEY_PM_STATE_NORMAL) && (prev_state >= VCONFKEY_PM_STATE_LCDOFF)) {
795                 netconfig_wifi_bgscan_stop();
796                 netconfig_wifi_bgscan_start(TRUE);
797         }
798
799         prev_state = new_state;
800 }
801
802 #if defined TIZEN_TELEPHONY_ENABLE
803 static void _tapi_noti_sim_status_cb(TapiHandle *handle, const char *noti_id,
804                                                                                 void *data, void *user_data)
805 {
806         TelSimCardStatus_t *status = data;
807
808         if (*status == TAPI_SIM_STATUS_SIM_INIT_COMPLETED) {
809                 DBG("Turn Wi-Fi on automatically");
810 #if defined TIZEN_WEARABLE
811                 wifi_power_on_wearable(TRUE);
812 #else
813                 wifi_power_on();
814 #endif
815                 netconfig_tel_deinit();
816         }
817 }
818
819 static gboolean netconfig_tapi_check_sim_state(void)
820 {
821         int ret, card_changed;
822         TelSimCardStatus_t status = TAPI_SIM_STATUS_UNKNOWN;
823         TapiHandle *tapi_handle = NULL;
824
825         tapi_handle = (TapiHandle *)netconfig_tel_init();
826         if (tapi_handle == NULL) {
827                 ERR("Failed to tapi init");
828                 return FALSE;
829         }
830
831         ret = tel_get_sim_init_info(tapi_handle, &status, &card_changed);
832         if (ret != TAPI_API_SUCCESS) {
833                 ERR("tel_get_sim_init_info() Failed : [%d]", ret);
834                 netconfig_tel_deinit();
835                 return FALSE;
836         }
837
838         switch (status) {
839         case TAPI_SIM_STATUS_UNKNOWN:
840         case TAPI_SIM_STATUS_CARD_ERROR:
841         case TAPI_SIM_STATUS_CARD_NOT_PRESENT:
842         case TAPI_SIM_STATUS_CARD_BLOCKED:
843         case TAPI_SIM_STATUS_SIM_INIT_COMPLETED:
844                 break;
845         case TAPI_SIM_STATUS_SIM_PIN_REQUIRED:
846         case TAPI_SIM_STATUS_SIM_INITIALIZING:
847         case TAPI_SIM_STATUS_SIM_PUK_REQUIRED:
848         case TAPI_SIM_STATUS_SIM_LOCK_REQUIRED:
849         case TAPI_SIM_STATUS_SIM_NCK_REQUIRED:
850         case TAPI_SIM_STATUS_SIM_NSCK_REQUIRED:
851         case TAPI_SIM_STATUS_SIM_SPCK_REQUIRED:
852         case TAPI_SIM_STATUS_SIM_CCK_REQUIRED:
853                 tel_register_noti_event(tapi_handle, TAPI_NOTI_SIM_STATUS,
854                                 _tapi_noti_sim_status_cb, NULL);
855                 return FALSE;
856         default:
857                 ERR("not defined status(%d)", status);
858                 break;
859         }
860
861         netconfig_tel_deinit();
862
863         return TRUE;
864 }
865
866 static void __netconfig_telephony_ready_changed_cb(keynode_t * node, void *data)
867 {
868         int telephony_ready = 0;
869
870         if (node != NULL)
871                 telephony_ready = vconf_keynode_get_bool(node);
872         else
873                 vconf_get_bool(VCONFKEY_TELEPHONY_READY, &telephony_ready);
874
875         if (telephony_ready != 0) {
876                 if (netconfig_tapi_check_sim_state() == FALSE) {
877                         DBG("Sim is not initialized yet.");
878
879                         goto done;
880                 }
881         } else
882                 return;
883
884         DBG("Turn Wi-Fi on automatically");
885
886 #if defined TIZEN_WEARABLE
887         wifi_power_on_wearable(TRUE);
888 #else
889         wifi_power_on();
890 #endif
891
892 done:
893         vconf_ignore_key_changed(VCONFKEY_TELEPHONY_READY, __netconfig_telephony_ready_changed_cb);
894 }
895 #endif
896
897 int wifi_power_driver_and_supplicant(gboolean enable)
898 {
899         /* There are 3 thumb rules for Wi-Fi power management
900          *   1. Do not make exposed API to control wpa_supplicant and driver directly.
901          *      It probably breaks ConnMan technology operation.
902          *
903          *   2. Do not remove driver and wpa_supplicant if ConnMan already enabled.
904          *      It breaks ConnMan technology operation.
905          *
906          *   3. Final the best rule: make it as simple as possible.
907          *      Simple code enables easy maintenance and reduces logical errors.
908          */
909         if (enable == TRUE) {
910                 return _load_driver_and_supplicant();
911         } else {
912                 if (connman_wifi_technology_state == TRUE)
913                         return -ENOSYS;
914
915                 return _remove_driver_and_supplicant();
916         }
917 }
918
919 void wifi_power_disable_technology_state_by_only_connman_signal(void)
920 {
921         /* Important: it's only done by ConnMan technology signal update */
922         connman_wifi_technology_state = FALSE;
923 }
924
925 void wifi_power_recover_firmware(void)
926 {
927         wifi_firmware_recovery_mode = TRUE;
928
929         netconfig_wifi_bgscan_stop();
930
931         wifi_power_off();
932 }
933
934 int wifi_power_on(void)
935 {
936         int err = 0;
937         wifi_tech_state_e tech_state;
938
939         tech_state = wifi_state_get_technology_state();
940         if (tech_state >= NETCONFIG_WIFI_TECH_POWERED)
941                 return -EALREADY;
942
943         if (__is_wifi_restricted() == TRUE)
944                 return -EPERM;
945
946         if (netconfig_is_wifi_tethering_on() == TRUE) {
947                 /* TODO: Wi-Fi tethering turns off here */
948                 /* return TRUE; */
949                 ERR("Failed to turn tethering off");
950                 return -EBUSY;
951         }
952
953 #if defined TIZEN_P2P_ENABLE && !defined WLAN_CONCURRENT_MODE
954         if (netconfig_is_wifi_direct_on() == TRUE) {
955                 if (__netconfig_wifi_direct_power_off() == TRUE)
956                         return -EINPROGRESS;
957                 else {
958                         ERR("Failed to turn Wi-Fi direct off");
959                         return -EBUSY;
960                 }
961         }
962 #endif
963
964         err = wifi_power_driver_and_supplicant(TRUE);
965         if (err < 0 && err != -EALREADY)
966                 return err;
967
968         err = _set_connman_technology_power(TRUE);
969
970         return err;
971 }
972
973 int wifi_power_off(void)
974 {
975         int err;
976
977         err = _set_connman_technology_power(FALSE);
978         if (err == -EALREADY)
979                 wifi_state_update_power_state(FALSE);
980
981         return 0;
982 }
983
984 #if defined TIZEN_WEARABLE
985 int wifi_power_on_wearable(gboolean device_picker_test)
986 {
987         int err = 0;
988         int wifi_use = 1;
989         wifi_tech_state_e tech_state;
990         weconn_service_state_e weconn_state;
991
992         tech_state = wifi_state_get_technology_state();
993         if (tech_state >= NETCONFIG_WIFI_TECH_POWERED)
994                 return -EALREADY;
995
996         err = weconn_get_service_state(weconn_handle, W_SERVICE_TYPE_BT, &weconn_state);
997         if (err == 0 && weconn_state == W_SERVICE_STATE_CONNECTED) {
998                 WARN("Not permitted Wi-Fi on");
999                 return -EPERM;
1000         }
1001
1002         if (vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use) < 0) {
1003                 ERR("Fail to get VCONF_WIFI_WEARABLE_WIFI_USE");
1004                 return -EIO;
1005         }
1006
1007         if (wifi_use == 0) {
1008                 WARN("VCONF_WIFI_WEARABLE_WIFI_USE is OFF");
1009                 return -EPERM;
1010         }
1011
1012         err = wifi_power_driver_and_supplicant(TRUE);
1013         if (err < 0 && err != -EALREADY)
1014                 return err;
1015
1016         err = _set_connman_technology_power(TRUE);
1017
1018         if (device_picker_test == TRUE)
1019                 netconfig_wifi_enable_device_picker_test();
1020
1021         return err;
1022 }
1023 #endif
1024
1025 void wifi_power_initialize(void)
1026 {
1027         int wifi_last_power_state = 0;
1028
1029         /* Initialize Airplane mode */
1030 #if defined TIZEN_TELEPHONY_ENABLE
1031         vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &airplane_mode);
1032 #endif
1033         DBG("Airplane[%s]", airplane_mode > 0 ? "ON" : "OFF");
1034
1035         /* Update the last Wi-Fi power state */
1036         vconf_get_int(VCONF_WIFI_LAST_POWER_STATE, &wifi_last_power_state);
1037         if (wifi_last_power_state > VCONFKEY_WIFI_OFF) {
1038 #if defined TIZEN_TELEPHONY_ENABLE
1039                 int telephony_ready = 0;
1040                 vconf_get_bool(VCONFKEY_TELEPHONY_READY, &telephony_ready);
1041                 if (telephony_ready == 0) {
1042                         DBG("Telephony API is not initialized yet");
1043                         vconf_notify_key_changed(VCONFKEY_TELEPHONY_READY,
1044                                         __netconfig_telephony_ready_changed_cb, NULL);
1045                 } else {
1046                         if (netconfig_tapi_check_sim_state() == FALSE)
1047                                 DBG("SIM is not initialized yet");
1048                 }
1049 #endif
1050                 DBG("Turn Wi-Fi on automatically");
1051 #if defined TIZEN_WEARABLE
1052                 wifi_power_on_wearable(TRUE);
1053 #else
1054                 wifi_power_on();
1055 #endif
1056         }
1057
1058 #if defined TIZEN_WEARABLE
1059         _weconn_set_state_changed_cb(W_SERVICE_TYPE_BT, NULL);
1060         vconf_notify_key_changed(VCONF_WIFI_WEARABLE_WIFI_USE, __wearable_wifi_use_changed_cb, NULL);
1061
1062 #if defined TIZEN_TELEPHONY_ENABLE
1063         vconf_notify_key_changed(VCONFKEY_TELEPHONY_FLIGHT_MODE,
1064                         __netconfig_wifi_wearable_airplane_mode, NULL);
1065 #endif
1066 #else
1067         vconf_notify_key_changed(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE,
1068                         __netconfig_wifi_restrict_mode, NULL);
1069 #if defined TIZEN_TELEPHONY_ENABLE
1070         vconf_notify_key_changed(VCONFKEY_TELEPHONY_FLIGHT_MODE,
1071                         __netconfig_wifi_airplane_mode, NULL);
1072 #endif
1073 #endif
1074
1075         vconf_notify_key_changed(VCONFKEY_SETAPPL_PSMODE, __emergency_mode_changed_cb, NULL);
1076         vconf_notify_key_changed(VCONFKEY_PM_STATE, __pm_state_changed_cb, NULL);
1077 }
1078
1079 void wifi_power_deinitialize(void)
1080 {
1081 }
1082
1083 gboolean handle_load_driver(Wifi *wifi,
1084                 GDBusMethodInvocation *context, gboolean device_picker_test)
1085 {
1086         int err;
1087
1088         DBG("Wi-Fi power on requested");
1089
1090         g_return_val_if_fail(wifi != NULL, FALSE);
1091
1092 #if defined TIZEN_WEARABLE
1093         err = wifi_power_on_wearable(device_picker_test);
1094 #else
1095         err = wifi_power_on();
1096
1097         if (device_picker_test == TRUE)
1098                 netconfig_wifi_enable_device_picker_test();
1099 #endif
1100         if (err < 0) {
1101                 if (err == -EINPROGRESS)
1102                         netconfig_error_inprogress(context);
1103                 else if (err == -EALREADY)
1104                         netconfig_error_already_exists(context);
1105                 else if (err == -EPERM)
1106                         netconfig_error_permission_denied(context);
1107                 else
1108                         netconfig_error_wifi_driver_failed(context);
1109
1110                 return TRUE;
1111         }
1112
1113
1114         netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
1115         __netconfig_set_wifi_bssid();
1116
1117         wifi_complete_load_driver(wifi, context);
1118         return TRUE;
1119 }
1120
1121 gboolean handle_remove_driver(Wifi *wifi, GDBusMethodInvocation *context)
1122 {
1123         int err;
1124
1125         DBG("Wi-Fi power off requested");
1126
1127         g_return_val_if_fail(wifi != NULL, FALSE);
1128
1129         err = wifi_power_off();
1130         if (err < 0) {
1131                 if (err == -EINPROGRESS)
1132                         netconfig_error_inprogress(context);
1133                 else if (err == -EALREADY)
1134                         netconfig_error_already_exists(context);
1135                 else if (err == -EPERM)
1136                         netconfig_error_permission_denied(context);
1137                 else
1138                         netconfig_error_wifi_driver_failed(context);
1139                 return TRUE;
1140         }
1141
1142         netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
1143
1144         wifi_complete_remove_driver(wifi, context);
1145         return TRUE;
1146 }
1147
1148 gboolean handle_load_p2p_driver(Wifi *wifi, GDBusMethodInvocation *context)
1149 {
1150         ERR("Deprecated");
1151
1152         wifi_complete_load_p2p_driver(wifi, context);
1153         return TRUE;
1154 }
1155
1156 gboolean handle_remove_p2p_driver(Wifi *wifi, GDBusMethodInvocation *context)
1157 {
1158         ERR("Deprecated");
1159
1160         wifi_complete_remove_p2p_driver(wifi, context);
1161         return TRUE;
1162 }
1163
1164 #if defined TIZEN_TV
1165 static int __netconfig_get_random_mac(unsigned char *mac_buf, int mac_len)
1166 {
1167         DBG("Generate Random Mac address of ethernet");
1168         FILE *fp;
1169         int rc;
1170
1171         fp = fopen(OS_RANDOM_FILE, "rb");
1172
1173         if (fp == NULL) {
1174                 ERR("Could not open /dev/urandom");
1175                 return -1;
1176         }
1177         rc = fread(mac_buf, 1, mac_len, fp);
1178         if (fp)
1179                 fclose(fp);
1180
1181         return rc != mac_len ? -1 : 0;
1182 }
1183
1184 void __netconfig_set_ether_macaddr()
1185 {
1186
1187         DBG("Set wired Mac address ");
1188         char *mac_addr = NULL;
1189         int rv = -1;
1190
1191         mac_addr = vconf_get_str(VCONF_ETH_MAC_ADDRESS);
1192         if (mac_addr == NULL) {
1193                 DBG("vconf_get_str Failed\n");
1194                 return;
1195         }
1196         /* Checking Invalid MAC Address */
1197         if ((strlen(mac_addr) == 0)) {
1198                 ERR("Failed to get valid MAC Address from vconf");
1199                 /*Generate the Random Mac address*/
1200                 unsigned char rand_mac_add[ETH_MAC_ADDR_SIZE+1];
1201
1202                 if (__netconfig_get_random_mac(rand_mac_add, ETH_MAC_ADDR_SIZE == -1)) {
1203
1204                         ERR("Could not generate the Random Mac address");
1205                         g_free(mac_addr);
1206                         return;
1207                 }
1208
1209                 rand_mac_add[0] &= 0xFE; /*Clear multicase bit*/
1210                 rand_mac_add[0] |= 0x02; /*set local assignment bit*/
1211
1212                 /*Set the Mac address in Vconf*/
1213                 snprintf(mac_addr, WLAN_MAC_ADDR_MAX, "%x:%x:%x:%x:%x:%x",
1214                                 rand_mac_add[0], rand_mac_add[1],
1215                                 rand_mac_add[2], rand_mac_add[3],
1216                                 rand_mac_add[4], rand_mac_add[5]);
1217
1218                 netconfig_set_vconf_str(VCONF_ETH_MAC_ADDRESS, mac_addr);
1219         }
1220
1221         DBG("MAC Address of eth0 [%s]",mac_addr);
1222         const char *path = NET_EXEC_PATH;
1223         char *const args[] = { "/sbin/ifconfig", "eth0", "hw",
1224                 "ether",mac_addr, "up", NULL};
1225         char *const envs[] = { NULL };
1226         rv = netconfig_execute_file(path, args, envs);
1227
1228         if (rv < 0) {
1229                 ERR("Unable to execute system command");
1230         }
1231         g_free(mac_addr);
1232
1233 }
1234 #endif