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