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