Free vconf_get_str using free() instead of g_free()
[platform/core/connectivity/net-config.git] / src / wifi-power.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <errno.h>
21 #include <vconf.h>
22 #include <vconf-keys.h>
23 #include <ITapiSim.h>
24 #include <TapiUtility.h>
25 #include <stdio.h>
26 #include <tzplatform_config.h>
27
28 #if defined TIZEN_P2P_ENABLE && !defined WLAN_CONCURRENT_MODE
29 #include <wifi-direct.h>
30 #endif
31
32 #include "log.h"
33 #include "util.h"
34 #include "netdbus.h"
35 #include "neterror.h"
36 #include "wifi-wps.h"
37 #include "wifi-power.h"
38 #include "wifi-state.h"
39 #include "wifi-tel-intf.h"
40 #include "netsupplicant.h"
41 #include "network-state.h"
42 #include "network-dpm.h"
43 #include "wifi-firmware.h"
44 #include "wifi-background-scan.h"
45
46
47 #define WLAN_SUPPLICANT_SCRIPT          "/usr/sbin/wpa_supp.sh"
48 #define P2P_SUPPLICANT_SCRIPT           "/usr/sbin/p2p_supp.sh"
49
50 #define VCONF_WIFI_OFF_STATE_BY_AIRPLANE        "file/private/wifi/wifi_off_by_airplane"
51 #define VCONF_WIFI_OFF_STATE_BY_RESTRICTED      "file/private/wifi/wifi_off_by_restricted"
52 #define VCONF_WIFI_OFF_STATE_BY_EMERGENCY       "file/private/wifi/wifi_off_by_emergency"
53 #if defined TIZEN_WEARABLE
54 #define VCONF_WIFI_WEARABLE_WIFI_USE                    "db/private/wifi/wearable_wifi_use"
55 #endif
56 #if !defined TIZEN_WEARABLE
57 #define VCONFKEY_SETAPPL_NETWORK_PERMIT_WITH_LCD_OFF_LIMIT      "db/setting/network_with_lcd_off_limit"
58 #endif
59
60 #define WLAN_MAC_INFO               tzplatform_mkpath(TZ_SYS_ETC, "/.mac.info")
61 #define WLAN_MAC_ADDRESS_FILEPATH   "/sys/class/net/wlan0/address"
62 #define WLAN_MAC_ADDR_MAX           20
63 #define VCONF_WIFI_BSSID_ADDRESS        "db/wifi/bssid_address"
64
65 #define ETH_MAC_ADDR_SIZE 6
66 #define VCONF_ETH_MAC_ADDRESS  "db/dnet/mac_address"
67 #define NET_EXEC_PATH "/sbin/ifconfig"
68 #define OS_RANDOM_FILE "/dev/urandom"
69
70 static gboolean connman_wifi_technology_state = FALSE;
71 static gboolean wifi_firmware_recovery_mode = FALSE;
72 static int airplane_mode = 0;
73
74 #if defined TIZEN_WEARABLE
75 static int psmode_wifi_use = 1;
76 #endif
77
78 static gboolean __is_wifi_restricted(void)
79 {
80 #if defined TIZEN_WEARABLE
81         return FALSE;
82 #endif
83         int restricted_mode = 0;
84
85         netconfig_vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE, &restricted_mode);
86         if (restricted_mode != 0) {
87                 DBG("network restricted mode[%d]", restricted_mode);
88                 return TRUE;
89         }
90
91         return FALSE;
92 }
93
94 static void __technology_reply(GObject *source_object, GAsyncResult *res, gpointer user_data)
95 {
96         GVariant *reply;
97         GDBusConnection *conn = NULL;
98         GError *error = NULL;
99
100         conn = G_DBUS_CONNECTION(source_object);
101         reply = g_dbus_connection_call_finish(conn, res, &error);
102
103         if (reply == NULL) {
104                 if (error != NULL) {
105                         if (g_strstr_len(error->message, strlen(error->message),
106                                         CONNMAN_ERROR_INTERFACE ".AlreadyEnabled") != NULL) {
107                                 wifi_state_update_power_state(TRUE);
108                         } else if (g_strstr_len(error->message, strlen(error->message),
109                                         CONNMAN_ERROR_INTERFACE ".AlreadyDisabled") != NULL) {
110                                 wifi_state_update_power_state(FALSE);
111                         } else {
112                                 ERR("Fail to request status [%d: %s]", error->code, error->message);
113                                 wifi_state_update_power_state(FALSE);
114                         }
115                         g_error_free(error);
116                 } else {
117                         ERR("Fail to request status");
118                         wifi_state_update_power_state(FALSE);
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 %s", WLAN_MAC_INFO);
325                 fp = fopen(WLAN_MAC_ADDRESS_FILEPATH, "r");
326                 if (fp == NULL) {
327                         ERR("Fail to open %s", WLAN_MAC_ADDRESS_FILEPATH);
328                         return;
329                 }
330         }
331
332         fseek(fp, 0L, SEEK_SET);
333         rv = fscanf(fp, "%17s", bssid);
334
335         if (rv < 0)
336                 ERR("Fail to read bssid");
337
338         netconfig_set_vconf_str(VCONF_WIFI_BSSID_ADDRESS, bssid);
339
340         fclose(fp);
341 }
342
343 int netconfig_wifi_driver_and_supplicant(gboolean enable)
344 {
345         /* There are 3 thumb rules for Wi-Fi power management
346          *   1. Do not make exposed API to control wpa_supplicant and driver directly.
347          *      It probably breaks ConnMan technology operation.
348          *
349          *   2. Do not remove driver and wpa_supplicant if ConnMan already enabled.
350          *      It breaks ConnMan technology operation.
351          *
352          *   3. Final the best rule: make it as simple as possible.
353          *      Simple code enables easy maintenance and reduces logical errors.
354          */
355         if (enable == TRUE)
356                 return _load_driver_and_supplicant();
357         else {
358                 if (connman_wifi_technology_state == TRUE)
359                         return -ENOSYS;
360
361                 return _load_driver_and_supplicant();
362         }
363 }
364
365 void netconfig_wifi_disable_technology_state_by_only_connman_signal(void)
366 {
367         /* Important: it's only done by ConnMan technology signal update */
368         connman_wifi_technology_state = FALSE;
369 }
370
371 #if defined TIZEN_WEARABLE
372 int netconfig_wifi_on_wearable(gboolean device_picker_test)
373 {
374         int err = 0;
375         int wifi_use;
376         int ps_mode;
377
378         if (netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use) < 0) {
379                 ERR("Fail to get VCONF_WIFI_WEARABLE_WIFI_USE");
380                 return -EIO;
381         }
382
383         if (wifi_use > 0) {
384                 if (netconfig_vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &ps_mode) < 0) {
385                         ERR("Fail to get VCONFKEY_SETAPPL_PSMODE");
386                         return -EIO;
387                 }
388
389                 if (ps_mode > SETTING_PSMODE_NORMAL) {
390                         WARN("ps mode is on(%d), Not turn on Wi-Fi", ps_mode);
391                         return -EPERM;
392                 }
393         } else {
394                 WARN("Not permitted Wi-Fi on");
395                 return -EPERM;
396         }
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         if (device_picker_test == TRUE)
405                 netconfig_wifi_enable_device_picker_test();
406
407         return err;
408 }
409
410 static void __wearable_wifi_use_changed_cb(keynode_t* node, void* user_data)
411 {
412         int wifi_state;
413         int wifi_use = 1;
414
415         if (netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state) < 0) {
416                 ERR("Fail to get VCONFKEY_WIFI_STATE");
417                 return;
418         }
419
420         if (node != NULL)
421                 wifi_use = vconf_keynode_get_int(node);
422         else
423                 netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use);
424
425         if (wifi_use > 0) {
426                 DBG("wifi use on");
427                 if (wifi_state > VCONFKEY_WIFI_OFF) {
428                         WARN("Wi-Fi is already turned on");
429                         return;
430                 }
431                 wifi_power_on_wearable(TRUE);
432         } else {
433                 ERR("## wifi use [OFF]");
434                 if (wifi_state == VCONFKEY_WIFI_OFF) {
435                         WARN("Wi-Fi is already turned off");
436                         return;
437                 }
438
439                 wifi_power_off();
440         }
441 }
442 #else
443 static void __netconfig_wifi_restrict_mode(keynode_t *node, void *user_data)
444 {
445         int wifi_state = 0, restricted = 0;
446         int wifi_off_by_restricted = 0;
447
448         netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, &wifi_off_by_restricted);
449
450         netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
451
452         if (node != NULL)
453                 restricted = vconf_keynode_get_bool(node);
454         else
455                 netconfig_vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE, &restricted);
456
457         DBG("network restricted mode %s", restricted > 0 ? "ON" : "OFF");
458         DBG("Wi-Fi state %d, Wi-Fi was off by restricted mode %s", wifi_state,
459                         wifi_off_by_restricted ? "Yes" : "No");
460
461         if (restricted > 0) {
462                 /* network restricted on */
463                 if (wifi_state == VCONFKEY_WIFI_OFF)
464                         return;
465
466                 wifi_power_off();
467
468                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, 1);
469         } else {
470                 /* network restricted off */
471                 if (!wifi_off_by_restricted)
472                         return;
473
474                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, 0);
475
476                 if (wifi_state > VCONFKEY_WIFI_OFF)
477                         return;
478
479                 wifi_power_on();
480         }
481 }
482 #endif
483
484 static void __netconfig_wifi_airplane_mode(keynode_t *node, void *user_data)
485 {
486         int wifi_state = 0, airplane_state = 0;
487         int wifi_off_by_airplane = 0;
488
489         netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, &wifi_off_by_airplane);
490
491 #if defined TIZEN_WEARABLE
492         netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_state)
493 #else
494         netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
495 #endif
496
497         if (node != NULL)
498                 airplane_state = vconf_keynode_get_bool(node);
499         else
500                 netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &airplane_state);
501
502         DBG("airplane mode %s (prev:%d)", airplane_state > 0 ? "ON" : "OFF", airplane_mode);
503         DBG("Wi-Fi state(or use) %d, Wi-Fi was off by flight mode %s", wifi_state,
504                         wifi_off_by_airplane ? "Yes" : "No");
505
506         if (airplane_mode == airplane_state)
507                 return ;
508
509         airplane_mode = airplane_state;
510
511         if (airplane_state > 0) {
512                 /* airplane mode on */
513                 if (wifi_state == VCONFKEY_WIFI_OFF)
514                         return;
515
516                 wifi_power_off();
517
518                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 1);
519 #if defined TIZEN_WEARABLE
520                 netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, 0);
521 #endif
522         } else {
523                 /* airplane mode off */
524                 if (!wifi_off_by_airplane)
525                         return;
526
527                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
528 #if defined TIZEN_WEARABLE
529                 netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, 1);
530 #else
531                 if (wifi_state > VCONFKEY_WIFI_OFF)
532                         return;
533
534                 wifi_power_on();
535 #endif
536         }
537 }
538
539 static void __emergency_mode_changed_cb(keynode_t *node, void *user_data)
540 {
541         int wifi_state = 0, emergency = 0;
542         int wifi_off_by_emergency = 0;
543 #if !defined TIZEN_WEARABLE
544         int emergency_by_fmm = 0;
545 #endif
546 #if defined TIZEN_WEARABLE
547         int wifi_use = 1;
548 #endif
549
550         netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, &wifi_off_by_emergency);
551         netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
552
553 #if !defined TIZEN_WEARABLE
554         netconfig_vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_PERMIT_WITH_LCD_OFF_LIMIT, &emergency_by_fmm);
555         DBG("emergency mode by Find My Mobile (%d)", emergency_by_fmm);
556         if (emergency_by_fmm == 1)
557                 return;
558 #endif
559
560         if (node != NULL)
561                 emergency = vconf_keynode_get_int(node);
562         else
563                 netconfig_vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &emergency);
564
565         DBG("emergency mode %s", emergency > SETTING_PSMODE_POWERFUL ? "ON" : "OFF");
566         DBG("Wi-Fi state %d, Wi-Fi was off by emergency mode %s", wifi_state, wifi_off_by_emergency ? "Yes" : "No");
567
568 #if defined TIZEN_WEARABLE
569         if (emergency == SETTING_PSMODE_WEARABLE) {
570                 /* basic power saving mode on */
571         } else if (emergency == SETTING_PSMODE_WEARABLE_ENHANCED) {
572                 /* enhanced power saving mode on */
573                 netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use);
574                 psmode_wifi_use = wifi_use;
575                 if (wifi_use != 0)
576                         netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, 0);
577
578                 if (wifi_state == VCONFKEY_WIFI_OFF)
579                         return;
580
581                 wifi_power_off();
582                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 1);
583         } else {
584                 /* power saving mode off */
585                 netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, psmode_wifi_use);
586                 if (!wifi_off_by_emergency)
587                         return;
588
589                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 0);
590                 if (wifi_state > VCONFKEY_WIFI_OFF)
591                         return;
592
593                 wifi_power_on_wearable(TRUE);
594         }
595 #else
596         if (emergency > SETTING_PSMODE_POWERFUL) {
597                 /* emergency mode on */
598                 if (wifi_state == VCONFKEY_WIFI_OFF)
599                         return;
600
601                 wifi_power_off();
602
603                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 1);
604         } else {
605                 /* emergency mode off */
606                 if (!wifi_off_by_emergency)
607                         return;
608
609                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 0);
610
611                 if (wifi_state > VCONFKEY_WIFI_OFF)
612                         return;
613
614                 wifi_power_on();
615         }
616 #endif
617
618 }
619
620 static void __pm_state_changed_cb(keynode_t* node, void* user_data)
621 {
622         int new_state = -1;
623         int wifi_state = 0;
624         static int prev_state = VCONFKEY_PM_STATE_NORMAL;
625
626         if (netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state) < 0) {
627                 ERR("Fail to get VCONFKEY_WIFI_STATE");
628                 return;
629         }
630
631         /* PM state
632          *      VCONFKEY_PM_STATE_NORMAL = 1,
633          *      VCONFKEY_PM_STATE_LCDDIM,
634          *      VCONFKEY_PM_STATE_LCDOFF,
635          *      VCONFKEY_PM_STATE_SLEEP
636          */
637         if (node != NULL)
638                 new_state = vconf_keynode_get_int(node);
639         else
640                 netconfig_vconf_get_int(VCONFKEY_PM_STATE, &new_state);
641
642         DBG("wifi state: %d (0 off / 1 on / 2 connected)", wifi_state);
643         DBG("Old PM state: %d, current: %d", prev_state, new_state);
644
645         if ((new_state == VCONFKEY_PM_STATE_NORMAL) && (prev_state >= VCONFKEY_PM_STATE_LCDOFF)) {
646                 netconfig_wifi_bgscan_stop();
647                 netconfig_wifi_bgscan_start(TRUE);
648         }
649
650         prev_state = new_state;
651 }
652
653 static void _tapi_noti_sim_status_cb(TapiHandle *handle, const char *noti_id,
654                                                                                 void *data, void *user_data)
655 {
656         TelSimCardStatus_t *status = data;
657
658         if (*status == TAPI_SIM_STATUS_SIM_INIT_COMPLETED) {
659                 DBG("Turn Wi-Fi on automatically");
660 #if defined TIZEN_WEARABLE
661                 wifi_power_on_wearable(TRUE);
662 #else
663                 wifi_power_on();
664 #endif
665                 netconfig_tel_deinit();
666         }
667 }
668
669 static gboolean netconfig_tapi_check_sim_state(void)
670 {
671         int ret, card_changed;
672         TelSimCardStatus_t status = TAPI_SIM_STATUS_UNKNOWN;
673         TapiHandle *tapi_handle = NULL;
674
675         tapi_handle = (TapiHandle *)netconfig_tel_init();
676         if (tapi_handle == NULL) {
677                 ERR("Failed to tapi init");
678                 return FALSE;
679         }
680
681         ret = tel_get_sim_init_info(tapi_handle, &status, &card_changed);
682         if (ret != TAPI_API_SUCCESS) {
683                 ERR("tel_get_sim_init_info() Failed : [%d]", ret);
684                 netconfig_tel_deinit();
685                 return FALSE;
686         }
687
688         switch (status) {
689         case TAPI_SIM_STATUS_UNKNOWN:
690         case TAPI_SIM_STATUS_CARD_ERROR:
691         case TAPI_SIM_STATUS_CARD_NOT_PRESENT:
692         case TAPI_SIM_STATUS_CARD_BLOCKED:
693         case TAPI_SIM_STATUS_SIM_INIT_COMPLETED:
694                 break;
695         case TAPI_SIM_STATUS_SIM_PIN_REQUIRED:
696         case TAPI_SIM_STATUS_SIM_INITIALIZING:
697         case TAPI_SIM_STATUS_SIM_PUK_REQUIRED:
698         case TAPI_SIM_STATUS_SIM_LOCK_REQUIRED:
699         case TAPI_SIM_STATUS_SIM_NCK_REQUIRED:
700         case TAPI_SIM_STATUS_SIM_NSCK_REQUIRED:
701         case TAPI_SIM_STATUS_SIM_SPCK_REQUIRED:
702         case TAPI_SIM_STATUS_SIM_CCK_REQUIRED:
703                 tel_register_noti_event(tapi_handle, TAPI_NOTI_SIM_STATUS,
704                                 _tapi_noti_sim_status_cb, NULL);
705                 return FALSE;
706         default:
707                 ERR("not defined status(%d)", status);
708                 break;
709         }
710
711         netconfig_tel_deinit();
712
713         return TRUE;
714 }
715
716 static void __netconfig_telephony_ready_changed_cb(keynode_t * node, void *data)
717 {
718         int telephony_ready = 0;
719
720         if (node != NULL)
721                 telephony_ready = vconf_keynode_get_bool(node);
722         else
723                 netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_READY, &telephony_ready);
724
725         if (telephony_ready != 0) {
726                 if (netconfig_tapi_check_sim_state() == FALSE) {
727                         DBG("Sim is not initialized yet.");
728
729                         goto done;
730                 }
731         } else
732                 return;
733
734         DBG("Turn Wi-Fi on automatically");
735
736 #if defined TIZEN_WEARABLE
737         wifi_power_on_wearable(TRUE);
738 #else
739         wifi_power_on();
740 #endif
741
742 done:
743         vconf_ignore_key_changed(VCONFKEY_TELEPHONY_READY, __netconfig_telephony_ready_changed_cb);
744 }
745
746 int wifi_power_driver_and_supplicant(gboolean enable)
747 {
748         /* There are 3 thumb rules for Wi-Fi power management
749          *   1. Do not make exposed API to control wpa_supplicant and driver directly.
750          *      It probably breaks ConnMan technology operation.
751          *
752          *   2. Do not remove driver and wpa_supplicant if ConnMan already enabled.
753          *      It breaks ConnMan technology operation.
754          *
755          *   3. Final the best rule: make it as simple as possible.
756          *      Simple code enables easy maintenance and reduces logical errors.
757          */
758         if (enable == TRUE) {
759                 return _load_driver_and_supplicant();
760         } else {
761                 if (connman_wifi_technology_state == TRUE)
762                         return -ENOSYS;
763
764                 return _remove_driver_and_supplicant();
765         }
766 }
767
768 void wifi_power_disable_technology_state_by_only_connman_signal(void)
769 {
770         /* Important: it's only done by ConnMan technology signal update */
771         connman_wifi_technology_state = FALSE;
772 }
773
774 void wifi_power_recover_firmware(void)
775 {
776         wifi_firmware_recovery_mode = TRUE;
777
778         netconfig_wifi_bgscan_stop();
779
780         wifi_power_off();
781 }
782
783 int wifi_power_on(void)
784 {
785         int err = 0;
786         wifi_tech_state_e tech_state;
787
788         tech_state = wifi_state_get_technology_state();
789         if (tech_state >= NETCONFIG_WIFI_TECH_POWERED)
790                 return -EALREADY;
791
792         if (__is_wifi_restricted() == TRUE)
793                 return -EPERM;
794
795         if (netconfig_is_wifi_tethering_on() == TRUE) {
796                 /* TODO: Wi-Fi tethering turns off here */
797                 /* return TRUE; */
798                 ERR("Failed to turn tethering off");
799                 return -EBUSY;
800         }
801
802 #if defined TIZEN_P2P_ENABLE && !defined WLAN_CONCURRENT_MODE
803         if (netconfig_is_wifi_direct_on() == TRUE) {
804                 if (__netconfig_wifi_direct_power_off() == TRUE)
805                         return -EINPROGRESS;
806                 else {
807                         ERR("Failed to turn Wi-Fi direct off");
808                         return -EBUSY;
809                 }
810         }
811 #endif
812
813         err = wifi_power_driver_and_supplicant(TRUE);
814         if (err < 0 && err != -EALREADY)
815                 return err;
816
817         err = _set_connman_technology_power(TRUE);
818
819         return err;
820 }
821
822 int wifi_power_off(void)
823 {
824         int err;
825
826         err = _set_connman_technology_power(FALSE);
827         if (err == -EALREADY)
828                 wifi_state_update_power_state(FALSE);
829
830         return 0;
831 }
832
833 #if defined TIZEN_WEARABLE
834 int wifi_power_on_wearable(gboolean device_picker_test)
835 {
836         int err = 0;
837         int wifi_use = 1;
838         wifi_tech_state_e tech_state;
839
840         tech_state = wifi_state_get_technology_state();
841         if (tech_state >= NETCONFIG_WIFI_TECH_POWERED)
842                 return -EALREADY;
843
844         if (netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use) < 0) {
845                 ERR("Fail to get VCONF_WIFI_WEARABLE_WIFI_USE");
846                 return -EIO;
847         }
848
849         if (wifi_use == 0) {
850                 WARN("VCONF_WIFI_WEARABLE_WIFI_USE is OFF");
851                 return -EPERM;
852         }
853
854         err = wifi_power_driver_and_supplicant(TRUE);
855         if (err < 0 && err != -EALREADY)
856                 return err;
857
858         err = _set_connman_technology_power(TRUE);
859
860         if (device_picker_test == TRUE)
861                 netconfig_wifi_enable_device_picker_test();
862
863         return err;
864 }
865 #endif
866
867 void wifi_power_initialize(void)
868 {
869         int wifi_last_power_state = 0;
870
871         /* Initialize Airplane mode */
872         netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &airplane_mode);
873         DBG("Airplane[%s]", airplane_mode > 0 ? "ON" : "OFF");
874
875         /* Update the last Wi-Fi power state */
876         netconfig_vconf_get_int(VCONF_WIFI_LAST_POWER_STATE, &wifi_last_power_state);
877         if (wifi_last_power_state > VCONFKEY_WIFI_OFF) {
878                 if (TIZEN_TELEPHONY_ENABLE) {
879                         int telephony_ready = 0;
880                         netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_READY, &telephony_ready);
881                         if (telephony_ready == 0) {
882                                 DBG("Telephony API is not initialized yet");
883                                 vconf_notify_key_changed(VCONFKEY_TELEPHONY_READY,
884                                                 __netconfig_telephony_ready_changed_cb, NULL);
885                         } else {
886                                 if (netconfig_tapi_check_sim_state() == FALSE)
887                                         DBG("SIM is not initialized yet");
888                         }
889                 }
890                 DBG("Turn Wi-Fi on automatically");
891 #if defined TIZEN_WEARABLE
892                 wifi_power_on_wearable(TRUE);
893 #else
894                 wifi_power_on();
895 #endif
896         }
897
898 #if defined TIZEN_WEARABLE
899         vconf_notify_key_changed(VCONF_WIFI_WEARABLE_WIFI_USE, __wearable_wifi_use_changed_cb, NULL);
900
901         vconf_notify_key_changed(VCONFKEY_TELEPHONY_FLIGHT_MODE,
902                         __netconfig_wifi_airplane_mode, NULL);
903 #else
904         vconf_notify_key_changed(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE,
905                         __netconfig_wifi_restrict_mode, NULL);
906         vconf_notify_key_changed(VCONFKEY_TELEPHONY_FLIGHT_MODE,
907                         __netconfig_wifi_airplane_mode, NULL);
908 #endif
909
910         vconf_notify_key_changed(VCONFKEY_SETAPPL_PSMODE, __emergency_mode_changed_cb, NULL);
911         vconf_notify_key_changed(VCONFKEY_PM_STATE, __pm_state_changed_cb, NULL);
912 }
913
914 void wifi_power_deinitialize(void)
915 {
916 }
917
918 gboolean handle_load_driver(Wifi *wifi,
919                 GDBusMethodInvocation *context, gboolean device_picker_test)
920 {
921         int err;
922
923         DBG("Wi-Fi power on requested");
924
925         g_return_val_if_fail(wifi != NULL, FALSE);
926
927         if (!netconfig_dpm_update_from_wifi()) {
928                 DBG("DPM policy restricts Wi-Fi");
929                 netconfig_error_permission_denied(context);
930                 return TRUE;
931         }
932
933         if (TIZEN_WLAN_BOARD_SPRD)
934                 wifi_firmware_download();
935
936 #if defined TIZEN_WEARABLE
937         err = wifi_power_on_wearable(device_picker_test);
938 #else
939         err = wifi_power_on();
940
941         if (device_picker_test == TRUE)
942                 netconfig_wifi_enable_device_picker_test();
943 #endif
944         if (err < 0) {
945                 if (err == -EINPROGRESS)
946                         netconfig_error_inprogress(context);
947                 else if (err == -EALREADY)
948                         netconfig_error_already_exists(context);
949                 else if (err == -EPERM)
950                         netconfig_error_permission_denied(context);
951                 else
952                         netconfig_error_wifi_driver_failed(context);
953
954                 return TRUE;
955         }
956
957
958         netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
959         __netconfig_set_wifi_bssid();
960
961         wifi_complete_load_driver(wifi, context);
962         return TRUE;
963 }
964
965 gboolean handle_remove_driver(Wifi *wifi, GDBusMethodInvocation *context)
966 {
967         int err;
968
969         DBG("Wi-Fi power off requested");
970
971         g_return_val_if_fail(wifi != NULL, FALSE);
972
973         err = wifi_power_off();
974         if (err < 0) {
975                 if (err == -EINPROGRESS)
976                         netconfig_error_inprogress(context);
977                 else if (err == -EALREADY)
978                         netconfig_error_already_exists(context);
979                 else if (err == -EPERM)
980                         netconfig_error_permission_denied(context);
981                 else
982                         netconfig_error_wifi_driver_failed(context);
983                 return TRUE;
984         }
985
986         netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
987
988         wifi_complete_remove_driver(wifi, context);
989         return TRUE;
990 }
991
992 gboolean handle_load_p2p_driver(Wifi *wifi, GDBusMethodInvocation *context)
993 {
994         ERR("Deprecated");
995
996         wifi_complete_load_p2p_driver(wifi, context);
997         return TRUE;
998 }
999
1000 gboolean handle_remove_p2p_driver(Wifi *wifi, GDBusMethodInvocation *context)
1001 {
1002         ERR("Deprecated");
1003
1004         wifi_complete_remove_p2p_driver(wifi, context);
1005         return TRUE;
1006 }
1007
1008 static int __netconfig_get_random_mac(unsigned char *mac_buf, int mac_len)
1009 {
1010         DBG("Generate Random Mac address of ethernet");
1011         FILE *fp;
1012         int rc;
1013
1014         fp = fopen(OS_RANDOM_FILE, "rb");
1015
1016         if (fp == NULL) {
1017                 ERR("Could not open /dev/urandom");
1018                 return -1;
1019         }
1020         rc = fread(mac_buf, 1, mac_len, fp);
1021         if (fp)
1022                 fclose(fp);
1023
1024         return rc != mac_len ? -1 : 0;
1025 }
1026
1027 void __netconfig_set_ether_macaddr()
1028 {
1029         DBG("Set wired Mac address ");
1030         char *mac_addr = NULL;
1031         char rand_addr[WLAN_MAC_ADDR_MAX];
1032         int rv = -1;
1033
1034         mac_addr = vconf_get_str(VCONF_ETH_MAC_ADDRESS);
1035         if (mac_addr == NULL) {
1036                 DBG("vconf_get_str Failed\n");
1037                 return;
1038         }
1039         /* Checking Invalid MAC Address */
1040         if ((strlen(mac_addr) == 0)) {
1041                 ERR("Failed to get valid MAC Address from vconf");
1042                 /*Generate the Random Mac address*/
1043                 unsigned char rand_mac_add[ETH_MAC_ADDR_SIZE+1];
1044
1045                 if (__netconfig_get_random_mac(rand_mac_add, ETH_MAC_ADDR_SIZE) == -1) {
1046
1047                         ERR("Could not generate the Random Mac address");
1048                         free(mac_addr);
1049                         return;
1050                 }
1051
1052                 rand_mac_add[0] &= 0xFE; /*Clear multicase bit*/
1053                 rand_mac_add[0] |= 0x02; /*set local assignment bit*/
1054
1055                 /*Set the Mac address in Vconf*/
1056                 snprintf(rand_addr, WLAN_MAC_ADDR_MAX, "%x:%x:%x:%x:%x:%x",
1057                                 rand_mac_add[0], rand_mac_add[1],
1058                                 rand_mac_add[2], rand_mac_add[3],
1059                                 rand_mac_add[4], rand_mac_add[5]);
1060
1061                 netconfig_set_vconf_str(VCONF_ETH_MAC_ADDRESS, rand_addr);
1062         } else { /* Valid MAC address */
1063                 strncpy(rand_addr, mac_addr, strlen(mac_addr));
1064                 rand_addr[strlen(mac_addr)] = '\0';
1065         }
1066
1067         DBG("MAC Address of eth0 [%s]", rand_addr);
1068         const char *path = NET_EXEC_PATH;
1069         char *const args[] = { "/sbin/ifconfig", "eth0", "hw",
1070                 "ether", rand_addr, "up", NULL};
1071         char *const envs[] = { NULL };
1072         rv = netconfig_execute_file(path, args, envs);
1073
1074         if (rv < 0)
1075                 ERR("Unable to execute system command");
1076         free(mac_addr);
1077
1078 }