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