Modify send_arp
[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 <stdio.h>
24 #include <stdlib.h>
25 #include <glib.h>
26 #include <tzplatform_config.h>
27 #include <net/if.h>
28 #include <sys/ioctl.h>
29
30 #include "log.h"
31 #include "util.h"
32 #include "netdbus.h"
33 #include "neterror.h"
34 #include "wifi-wps.h"
35 #include "wifi-bssid-scan.h"
36 #include "wifi-power.h"
37 #include "wifi-state.h"
38 #include "netsupplicant.h"
39 #include "network-state.h"
40 #include "network-dpm.h"
41 #include "wifi-firmware.h"
42 #include "wifi-background-scan.h"
43
44
45 #define WLAN_SUPPLICANT_SCRIPT          "/usr/bin/wpa_supp.sh"
46 #define P2P_SUPPLICANT_SCRIPT           "/usr/bin/p2p_supp.sh"
47
48 #define VCONF_WIFI_OFF_STATE_BY_AIRPLANE        "file/private/wifi/wifi_off_by_airplane"
49 #define VCONF_WIFI_OFF_STATE_BY_RESTRICTED      "file/private/wifi/wifi_off_by_restricted"
50 #define VCONF_WIFI_OFF_STATE_BY_EMERGENCY       "file/private/wifi/wifi_off_by_emergency"
51 #if !defined TIZEN_WEARABLE
52 #define VCONFKEY_SETAPPL_NETWORK_PERMIT_WITH_LCD_OFF_LIMIT      "db/setting/network_with_lcd_off_limit"
53 #endif
54
55 #define WLAN_MAC_ADDRESS_FILEPATH   "/sys/class/net/wlan0/address"
56 #define WLAN_MAC_ADDR_MAX           20
57 #define VCONF_WIFI_BSSID_ADDRESS        "db/wifi/bssid_address"
58
59 #define ETH_MAC_ADDR_SIZE 6
60 #define VCONF_ETH_MAC_ADDRESS  "db/dnet/mac_address"
61 #define NET_EXEC_PATH "/sbin/ifconfig"
62 #define OS_RANDOM_FILE "/dev/urandom"
63
64 #define NETCONFIG_TECH_WAITING_INTERVAL 500
65 #define NETCONFIG_TECH_WAITING_COUNT 6
66 #define MAX_DRV_CMD_SIZE 248
67 #define WLAN_IOCTL_SUSPEND (SIOCDEVPRIVATE + 1)
68
69 static gboolean connman_wifi_technology_state = FALSE;
70 static gboolean wifi_firmware_recovery_mode = FALSE;
71 static int airplane_mode = 0;
72
73 typedef struct {
74         char *buf;
75         int used_len;
76         int total_len;
77 } netconfig_wifi_priv_cmd;
78
79 static gboolean __is_wifi_restricted(void)
80 {
81 #if defined TIZEN_WEARABLE
82         return FALSE;
83 #endif
84         int restricted_mode = 0;
85
86         netconfig_vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE, &restricted_mode);
87         if (restricted_mode != 0) {
88                 DBG("network restricted mode[%d]", restricted_mode);
89                 return TRUE;
90         }
91
92         return FALSE;
93 }
94
95 static void __technology_reply(GObject *source_object, GAsyncResult *res, gpointer user_data)
96 {
97         GVariant *reply;
98         GDBusConnection *conn = NULL;
99         GError *error = NULL;
100
101         conn = G_DBUS_CONNECTION(source_object);
102         reply = g_dbus_connection_call_finish(conn, res, &error);
103
104         if (reply == NULL) {
105                 if (error != NULL) {
106                         if (g_strstr_len(error->message, strlen(error->message),
107                                         CONNMAN_ERROR_INTERFACE ".AlreadyEnabled") != NULL) {
108                                 wifi_state_update_power_state(TRUE);
109                         } else if (g_strstr_len(error->message, strlen(error->message),
110                                         CONNMAN_ERROR_INTERFACE ".AlreadyDisabled") != NULL) {
111                                 wifi_state_update_power_state(FALSE);
112                         } else {
113                                 ERR("Fail to request status [%d: %s]", error->code, error->message);
114                                 wifi_state_update_power_state(FALSE);
115                         }
116                         g_error_free(error);
117                 } else {
118                         ERR("Fail to request status");
119                         wifi_state_update_power_state(FALSE);
120                 }
121         } else {
122                 DBG("Successfully requested");
123                 g_variant_unref(reply);
124         }
125
126         netconfig_gdbus_pending_call_unref();
127 }
128
129 static int __execute_supplicant(gboolean enable)
130 {
131         int rv = 0;
132         const char *path = WLAN_SUPPLICANT_SCRIPT;
133         char *const args_enable[] = { "/usr/bin/wpa_supp.sh", "start", NULL };
134         char *const args_disable[] = { "/usr/bin/wpa_supp.sh", "stop", NULL };
135         char *const envs[] = { NULL };
136         static gboolean enabled = FALSE;
137
138         if (enabled == enable)
139                 return -EALREADY;
140
141         if (enable == TRUE)
142                 rv = netconfig_execute_file(path, args_enable, envs);
143         else
144                 rv = netconfig_execute_file(path, args_disable, envs);
145         if (rv < 0)
146                 return -EIO;
147
148         DBG("wpa_supplicant %s", enable == TRUE ? "started" : "stopped");
149
150         enabled = enable;
151
152         return 0;
153 }
154
155 void netconfig_wifi_recover_firmware(void)
156 {
157         wifi_firmware_recovery_mode = TRUE;
158
159         netconfig_wifi_bgscan_stop();
160
161         wifi_power_off();
162 }
163
164 static int _load_driver_and_supplicant(void)
165 {
166         int err = 0;
167         wifi_tech_state_e tech_state;
168
169         tech_state = wifi_state_get_technology_state();
170         if (tech_state > NETCONFIG_WIFI_TECH_OFF)
171                 return -EALREADY;
172
173         err = __execute_supplicant(TRUE);
174         if (err < 0 && err != -EALREADY)
175                 return err;
176
177         err = netconfig_wifi_firmware(NETCONFIG_WIFI_STA, TRUE);
178         if (err < 0 && err != -EALREADY) {
179                 __execute_supplicant(FALSE);
180                 return err;
181         }
182
183         wifi_state_set_tech_state(NETCONFIG_WIFI_TECH_WPS_ONLY);
184
185         return 0;
186 }
187
188 static int _remove_driver_and_supplicant(void)
189 {
190         int err = 0;
191
192         DBG("remove driver and supplicant");
193         if (wifi_firmware_recovery_mode != TRUE &&
194                                         netconfig_wifi_is_bssid_scan_started() == TRUE) {
195                 DBG("Wi-Fi WPS mode");
196                 return 0;
197         }
198
199         err = netconfig_wifi_firmware(NETCONFIG_WIFI_STA, FALSE);
200         if (err < 0 && err != -EALREADY)
201                 return err;
202
203         err = __execute_supplicant(FALSE);
204         if (err < 0 && err != -EALREADY)
205                 return err;
206
207         wifi_state_set_tech_state(NETCONFIG_WIFI_TECH_OFF);
208
209         // reset service state
210         wifi_state_set_service_state(NETCONFIG_WIFI_IDLE);
211
212         if (wifi_firmware_recovery_mode == TRUE) {
213                 if (wifi_power_on() < 0)
214                         ERR("Failed to recover Wi-Fi firmware");
215
216                 wifi_firmware_recovery_mode = FALSE;
217         }
218
219         return 0;
220 }
221
222 static gboolean __check_and_set_technology_enable(gpointer data)
223 {
224         static int retry_count = NETCONFIG_TECH_WAITING_COUNT;
225         gboolean value_enable = TRUE;
226         gboolean reply = FALSE;
227         GVariant *params = NULL;
228         char key[] = "Powered";
229
230         if (wifi_state_is_technology_available() == FALSE) {
231                 retry_count--;
232                 if (retry_count > 0)
233                         return TRUE;
234         }
235
236         params = g_variant_new("(sv)", key, g_variant_new_boolean(value_enable));
237
238         reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
239                                         CONNMAN_WIFI_TECHNOLOGY_PREFIX,
240                                         CONNMAN_TECHNOLOGY_INTERFACE,
241                                         "SetProperty", params, __technology_reply);
242
243         if (reply != TRUE) {
244                 ERR("Fail to set technology enable");
245                 wifi_state_update_power_state(FALSE);
246
247                 retry_count = NETCONFIG_TECH_WAITING_COUNT;
248                 return FALSE;
249         }
250
251         retry_count = NETCONFIG_TECH_WAITING_COUNT;
252         return FALSE;
253 }
254
255 static int _set_connman_technology_power(gboolean enable)
256 {
257         gboolean reply = FALSE;
258         GVariant *params = NULL;
259         char key[] = "Powered";
260         gboolean value_enable = TRUE;
261         gboolean value_disable = FALSE;
262
263         if (connman_wifi_technology_state == enable)
264                 return -EALREADY;
265
266         if (enable && wifi_state_is_technology_available() == FALSE) {
267                 netconfig_start_timer(NETCONFIG_TECH_WAITING_INTERVAL,
268                                 __check_and_set_technology_enable, NULL, NULL);
269                 connman_wifi_technology_state = enable;
270                 return 0;
271         }
272
273         params = g_variant_new("(sv)", key, (enable == TRUE) ?
274                 g_variant_new_boolean(value_enable) : g_variant_new_boolean(value_disable));
275
276         reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
277                                         CONNMAN_WIFI_TECHNOLOGY_PREFIX, CONNMAN_TECHNOLOGY_INTERFACE,
278                                         "SetProperty", params, __technology_reply);
279
280         if (reply != TRUE) {
281                 ERR("Fail to set technology %s", enable == TRUE ? "enable" : "disable");
282                 return -ESRCH;
283         }
284
285         /* If Wi-Fi powered off,
286          * Do not remove Wi-Fi driver until ConnMan technology state updated
287          */
288         if (enable == TRUE)
289                 connman_wifi_technology_state = enable;
290
291         /* To be keep safe, early disable Wi-Fi tech state */
292         if (enable != TRUE)
293                 wifi_state_set_tech_state(NETCONFIG_WIFI_TECH_WPS_ONLY);
294
295         return 0;
296 }
297
298 static void __netconfig_set_wifi_bssid(void)
299 {
300         int rv = 0;
301         char bssid[WLAN_MAC_ADDR_MAX];
302
303         FILE *fp = fopen(WLAN_MAC_ADDRESS_FILEPATH, "r");
304
305         if (fp == NULL) {
306                 ERR("Fail to open %s", WLAN_MAC_ADDRESS_FILEPATH);
307                 return;
308         }
309
310         rv = fseek(fp, 0L, SEEK_SET);
311         if (rv != 0) {
312                 ERR("Fail to seek file");
313                 fclose(fp);
314                 return;
315         }
316
317         rv = fscanf(fp, "%17s", bssid);
318         if (rv < 0) {
319                 ERR("Fail to read bssid");
320                 fclose(fp);
321                 return;
322         }
323
324         netconfig_set_vconf_str(VCONF_WIFI_BSSID_ADDRESS, bssid);
325
326         fclose(fp);
327 }
328
329 void netconfig_wifi_disable_technology_state_by_only_connman_signal(void)
330 {
331         /* Important: it's only done by ConnMan technology signal update */
332         connman_wifi_technology_state = FALSE;
333 }
334
335 #if defined TIZEN_WEARABLE
336 int netconfig_wifi_on_wearable(gboolean device_picker_test)
337 {
338         int err = 0;
339         int ps_mode;
340
341         if (netconfig_vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &ps_mode) < 0) {
342                 ERR("Fail to get VCONFKEY_SETAPPL_PSMODE");
343                 return -EIO;
344         }
345
346         if (ps_mode > SETTING_PSMODE_NORMAL) {
347                 WARN("ps mode is on(%d), Not turn on Wi-Fi", ps_mode);
348                 return -EPERM;
349         }
350
351         err = wifi_power_driver_and_supplicant(TRUE);
352         if (err < 0 && err != -EALREADY)
353                 return err;
354
355         err = _set_connman_technology_power(TRUE);
356
357         if (device_picker_test == TRUE)
358                 netconfig_wifi_enable_device_picker_test();
359
360         return err;
361 }
362 #else
363 static void __netconfig_wifi_restrict_mode(keynode_t *node, void *user_data)
364 {
365         int wifi_state = 0, restricted = 0;
366         int wifi_off_by_restricted = 0;
367
368         netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, &wifi_off_by_restricted);
369
370         netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
371
372         if (node != NULL)
373                 restricted = vconf_keynode_get_bool(node);
374         else
375                 netconfig_vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE, &restricted);
376
377         DBG("network restricted mode %s", restricted > 0 ? "ON" : "OFF");
378         DBG("Wi-Fi state %d, Wi-Fi was off by restricted mode %s", wifi_state,
379                         wifi_off_by_restricted ? "Yes" : "No");
380
381         if (restricted > 0) {
382                 /* network restricted on */
383                 if (wifi_state == VCONFKEY_WIFI_OFF)
384                         return;
385
386                 wifi_power_off();
387
388                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, 1);
389         } else {
390                 /* network restricted off */
391                 if (!wifi_off_by_restricted)
392                         return;
393
394                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, 0);
395
396                 if (wifi_state > VCONFKEY_WIFI_OFF)
397                         return;
398
399                 wifi_power_on();
400         }
401 }
402 #endif
403
404 static void __netconfig_wifi_airplane_mode(keynode_t *node, void *user_data)
405 {
406         int wifi_state = 0, airplane_state = 0;
407         int wifi_off_by_airplane = 0;
408
409         netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, &wifi_off_by_airplane);
410         netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
411
412         if (node != NULL)
413                 airplane_state = vconf_keynode_get_bool(node);
414         else
415                 netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &airplane_state);
416
417         DBG("airplane mode %s (prev:%d)", airplane_state > 0 ? "ON" : "OFF", airplane_mode);
418         DBG("Wi-Fi state(or use) %d, Wi-Fi was off by flight mode %s", wifi_state,
419                         wifi_off_by_airplane ? "Yes" : "No");
420
421         if (airplane_mode == airplane_state)
422                 return ;
423
424         airplane_mode = airplane_state;
425
426         if (airplane_state > 0) {
427                 /* airplane mode on */
428                 if (wifi_state == VCONFKEY_WIFI_OFF)
429                         return;
430
431                 wifi_power_off();
432
433                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 1);
434         } else {
435                 /* airplane mode off */
436                 if (!wifi_off_by_airplane)
437                         return;
438
439                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
440                 if (wifi_state > VCONFKEY_WIFI_OFF)
441                         return;
442
443                 wifi_power_on();
444         }
445 }
446
447 static void __emergency_mode_changed_cb(keynode_t *node, void *user_data)
448 {
449         int wifi_state = 0, emergency = 0;
450         int wifi_off_by_emergency = 0;
451 #if !defined TIZEN_WEARABLE
452         int emergency_by_fmm = 0;
453 #endif
454         netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, &wifi_off_by_emergency);
455         netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
456
457 #if !defined TIZEN_WEARABLE
458         netconfig_vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_PERMIT_WITH_LCD_OFF_LIMIT, &emergency_by_fmm);
459         DBG("emergency mode by Find My Mobile (%d)", emergency_by_fmm);
460         if (emergency_by_fmm == 1)
461                 return;
462 #endif
463
464         if (node != NULL)
465                 emergency = vconf_keynode_get_int(node);
466         else
467                 netconfig_vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &emergency);
468
469         DBG("emergency mode %s", emergency > SETTING_PSMODE_POWERFUL ? "ON" : "OFF");
470         DBG("Wi-Fi state %d, Wi-Fi was off by emergency mode %s", wifi_state, wifi_off_by_emergency ? "Yes" : "No");
471
472 #if defined TIZEN_WEARABLE
473         if (emergency == SETTING_PSMODE_WEARABLE) {
474                 /* basic power saving mode on */
475         } else if (emergency == SETTING_PSMODE_WEARABLE_ENHANCED) {
476                 /* enhanced power saving mode on */
477                 if (wifi_state == VCONFKEY_WIFI_OFF)
478                         return;
479
480                 wifi_power_off();
481                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 1);
482         } else {
483                 /* power saving mode off */
484                 if (!wifi_off_by_emergency)
485                         return;
486
487                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 0);
488                 if (wifi_state > VCONFKEY_WIFI_OFF)
489                         return;
490
491                 wifi_power_on_wearable(TRUE);
492         }
493 #else
494         if (emergency > SETTING_PSMODE_POWERFUL) {
495                 /* emergency mode on */
496                 if (wifi_state == VCONFKEY_WIFI_OFF)
497                         return;
498
499                 wifi_power_off();
500
501                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 1);
502         } else {
503                 /* emergency mode off */
504                 if (!wifi_off_by_emergency)
505                         return;
506
507                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 0);
508
509                 if (wifi_state > VCONFKEY_WIFI_OFF)
510                         return;
511
512                 wifi_power_on();
513         }
514 #endif
515
516 }
517
518 void wifi_set_early_suspend(gboolean value)
519 {
520         static gboolean old_state = FALSE;
521         struct ifreq ifr;
522         char buf[MAX_DRV_CMD_SIZE];
523         netconfig_wifi_priv_cmd priv_cmd;
524         int ret = 0;
525         int ioctl_sock = 0;
526         int pm_state = 0;
527         wifi_service_state_e wifi_state;
528         char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, };
529
530         if (old_state == value) {
531                 DBG("Old and new states are same");
532                 return;
533         }
534
535         if (netconfig_vconf_get_int(VCONFKEY_PM_STATE, &pm_state) < 0)
536                 ERR("Fail to get VCONFKEY_PM_STATE");
537
538         wifi_state = wifi_state_get_service_state();
539
540         if (value == TRUE &&
541                         (pm_state < VCONFKEY_PM_STATE_LCDOFF ||
542                          wifi_state == NETCONFIG_WIFI_ASSOCIATION ||
543                          wifi_state == NETCONFIG_WIFI_CONFIGURATION)){
544                 DBG("");
545                 return;
546         }
547
548         memset(buf, 0, sizeof(buf));
549         snprintf(buf, sizeof(buf), "SETSUSPENDMODE %d", value);
550
551         memset(&ifr, 0, sizeof(struct ifreq));
552         g_strlcpy((char *)ifr.ifr_name, WIFI_IFNAME, IFNAMSIZ);
553
554         DBG("Early suspend command: [%s]", buf);
555
556         memset(&priv_cmd, 0, sizeof(priv_cmd));
557         priv_cmd.buf = buf;
558         priv_cmd.used_len = sizeof(buf);
559         priv_cmd.total_len = sizeof(buf);
560         ifr.ifr_data = (char *)&priv_cmd;
561
562         ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
563         if (ioctl_sock < 0) {
564                 DBG("socket(PF_INET,SOCK_DGRAM) failed: %s",
565                                 strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER));
566                 return;
567         }
568
569         ret = ioctl(ioctl_sock, WLAN_IOCTL_SUSPEND, &ifr);
570         if (ret < 0) {
571                 ERR("Fail to issue private commands: %d. %s", ret,
572                                 strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER));
573         } else {
574                 old_state = value;
575         }
576
577         close(ioctl_sock);
578 }
579
580 static void __pm_state_changed_cb(keynode_t* node, void* user_data)
581 {
582         int new_state = -1;
583         int wifi_state = 0;
584         static int prev_state = VCONFKEY_PM_STATE_NORMAL;
585
586         if (netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state) < 0) {
587                 ERR("Fail to get VCONFKEY_WIFI_STATE");
588                 return;
589         }
590
591         /* PM state
592          *      VCONFKEY_PM_STATE_NORMAL = 1,
593          *      VCONFKEY_PM_STATE_LCDDIM,
594          *      VCONFKEY_PM_STATE_LCDOFF,
595          *      VCONFKEY_PM_STATE_SLEEP
596          */
597         if (node != NULL)
598                 new_state = vconf_keynode_get_int(node);
599         else
600                 netconfig_vconf_get_int(VCONFKEY_PM_STATE, &new_state);
601
602         DBG("wifi state: %d (0 off / 1 on / 2 connected)", wifi_state);
603         DBG("Old PM state: %d, current: %d (1 normal / 2 lcddim / 3 lcdoff / 4 sleep)", prev_state, new_state);
604
605         if ((new_state == VCONFKEY_PM_STATE_NORMAL) && (prev_state >= VCONFKEY_PM_STATE_LCDOFF)) {
606                 /* Send early suspend mode based on LCD state and disallow early suspend count */
607                 if (wifi_state != VCONFKEY_WIFI_OFF) {
608                         wifi_set_early_suspend(FALSE);
609                         DBG("Unset early suspend");
610                 }
611
612                 netconfig_wifi_bgscan_stop();
613                 netconfig_wifi_bgscan_set_interval(SCAN_EXPONENTIAL_MIN);
614                 netconfig_wifi_bgscan_start(TRUE);
615         } else if ((new_state == VCONFKEY_PM_STATE_LCDOFF) && (prev_state < VCONFKEY_PM_STATE_LCDOFF) && (wifi_state != VCONFKEY_WIFI_OFF)) {
616                 wifi_set_early_suspend(TRUE);
617                 DBG("Set early suspend");
618         }
619
620         prev_state = new_state;
621 }
622
623 static void __netconfig_telephony_ready_changed_cb(keynode_t * node, void *data)
624 {
625         int telephony_ready = 0;
626
627         if (node != NULL)
628                 telephony_ready = vconf_keynode_get_bool(node);
629         else
630                 netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_READY, &telephony_ready);
631
632         if (telephony_ready != 0) {
633                 if (netconfig_tapi_check_sim_state() == FALSE) {
634                         DBG("Sim is not initialized yet.");
635
636                         goto done;
637                 }
638         } else
639                 return;
640
641         DBG("Turn Wi-Fi on automatically");
642
643 #if defined TIZEN_WEARABLE
644         wifi_power_on_wearable(TRUE);
645 #else
646         wifi_power_on();
647 #endif
648
649 done:
650         vconf_ignore_key_changed(VCONFKEY_TELEPHONY_READY, __netconfig_telephony_ready_changed_cb);
651 }
652
653 int wifi_power_driver_and_supplicant(gboolean enable)
654 {
655         /* There are 3 thumb rules for Wi-Fi power management
656          *   1. Do not make exposed API to control wpa_supplicant and driver directly.
657          *      It probably breaks ConnMan technology operation.
658          *
659          *   2. Do not remove driver and wpa_supplicant if ConnMan already enabled.
660          *      It breaks ConnMan technology operation.
661          *
662          *   3. Final the best rule: make it as simple as possible.
663          *      Simple code enables easy maintenance and reduces logical errors.
664          */
665         if (enable == TRUE) {
666                 return _load_driver_and_supplicant();
667         } else {
668                 if (connman_wifi_technology_state == TRUE)
669                         return -ENOSYS;
670
671                 return _remove_driver_and_supplicant();
672         }
673 }
674
675 void wifi_power_disable_technology_state_by_only_connman_signal(void)
676 {
677         /* Important: it's only done by ConnMan technology signal update */
678         connman_wifi_technology_state = FALSE;
679 }
680
681 void wifi_power_recover_firmware(void)
682 {
683         wifi_firmware_recovery_mode = TRUE;
684
685         netconfig_wifi_bgscan_stop();
686
687         wifi_power_off();
688 }
689
690 int wifi_power_on(void)
691 {
692         int err = 0;
693         wifi_tech_state_e tech_state;
694
695         tech_state = wifi_state_get_technology_state();
696         if (tech_state >= NETCONFIG_WIFI_TECH_POWERED) {
697                 /* There can be a scenario where wifi is automatically *
698                  * activated by connman if wifi was powered in last boot. *
699                  * So we should update connman_wifi_technology_state variable *
700                  * if it is found that wifi_tech_state variable is *
701                  * NETCONFIG_WIFI_TECH_POWERED and connman_wifi_technology_state *
702                  * variable is FALSE. Earlier connman_wifi_technology_state *
703                  * variable was only updated when wifi was Powered on from *
704                  * net-config resulting in variable not getting updated. *
705                  * This caused wifi to not get deactivated after reboot if *
706                  * last power state was activated */
707                 ERR("Net-Config WiFi connman technology state %d",
708                                 connman_wifi_technology_state);
709                 if (connman_wifi_technology_state == FALSE)
710                         connman_wifi_technology_state = TRUE;
711                 return -EALREADY;
712         }
713
714         if (__is_wifi_restricted() == TRUE)
715                 return -EPERM;
716
717         if (netconfig_is_wifi_tethering_on() == TRUE) {
718                 /* TODO: Wi-Fi tethering turns off here */
719                 /* return TRUE; */
720                 ERR("Failed to turn tethering off");
721                 return -EBUSY;
722         }
723
724         err = wifi_power_driver_and_supplicant(TRUE);
725         if (err < 0 && err != -EALREADY)
726                 return err;
727
728         err = _set_connman_technology_power(TRUE);
729
730         return err;
731 }
732
733 int wifi_power_off(void)
734 {
735         int err;
736
737         err = _set_connman_technology_power(FALSE);
738         if (err == -EALREADY)
739                 wifi_state_update_power_state(FALSE);
740
741         return 0;
742 }
743
744 #if defined TIZEN_WEARABLE
745 int wifi_power_on_wearable(gboolean device_picker_test)
746 {
747         int err = 0;
748         wifi_tech_state_e tech_state;
749
750         tech_state = wifi_state_get_technology_state();
751         if (tech_state >= NETCONFIG_WIFI_TECH_POWERED)
752                 return -EALREADY;
753
754         err = wifi_power_driver_and_supplicant(TRUE);
755         if (err < 0 && err != -EALREADY)
756                 return err;
757
758         err = _set_connman_technology_power(TRUE);
759
760         if (device_picker_test == TRUE)
761                 netconfig_wifi_enable_device_picker_test();
762
763         return err;
764 }
765 #endif
766
767 void wifi_power_initialize(void)
768 {
769         int wifi_last_power_state = 0;
770
771         /* Initialize Airplane mode */
772         netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &airplane_mode);
773         DBG("Airplane[%s]", airplane_mode > 0 ? "ON" : "OFF");
774
775         /* Update the last Wi-Fi power state */
776         netconfig_vconf_get_int(VCONF_WIFI_LAST_POWER_STATE, &wifi_last_power_state);
777         if (wifi_last_power_state > VCONFKEY_WIFI_OFF) {
778                 if (TIZEN_TELEPHONY_ENABLE) {
779                         int telephony_ready = 0;
780                         netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_READY, &telephony_ready);
781                         if (telephony_ready == 0) {
782                                 DBG("Telephony API is not initialized yet");
783                                 vconf_notify_key_changed(VCONFKEY_TELEPHONY_READY,
784                                                 __netconfig_telephony_ready_changed_cb, NULL);
785                         } else {
786                                 if (netconfig_tapi_check_sim_state() == FALSE)
787                                         DBG("SIM is not initialized yet");
788                         }
789                 }
790                 DBG("Turn Wi-Fi on automatically");
791 #if defined TIZEN_WEARABLE
792                 wifi_power_on_wearable(TRUE);
793 #else
794                 wifi_power_on();
795 #endif
796         }
797
798 #if defined TIZEN_WEARABLE
799         vconf_notify_key_changed(VCONFKEY_TELEPHONY_FLIGHT_MODE,
800                         __netconfig_wifi_airplane_mode, NULL);
801 #else
802         vconf_notify_key_changed(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE,
803                         __netconfig_wifi_restrict_mode, NULL);
804         vconf_notify_key_changed(VCONFKEY_TELEPHONY_FLIGHT_MODE,
805                         __netconfig_wifi_airplane_mode, NULL);
806 #endif
807
808         vconf_notify_key_changed(VCONFKEY_SETAPPL_PSMODE, __emergency_mode_changed_cb, NULL);
809         vconf_notify_key_changed(VCONFKEY_PM_STATE, __pm_state_changed_cb, NULL);
810 }
811
812 void wifi_power_deinitialize(void)
813 {
814 }
815
816 gboolean handle_load_driver(Wifi *wifi,
817                 GDBusMethodInvocation *context, gboolean device_picker_test)
818 {
819         int err;
820
821         DBG("Wi-Fi power on requested");
822
823         g_return_val_if_fail(wifi != NULL, TRUE);
824
825         if (!netconfig_dpm_update_from_wifi()) {
826                 DBG("DPM policy restricts Wi-Fi");
827                 netconfig_error_permission_denied(context);
828                 return TRUE;
829         }
830
831         if (TIZEN_WLAN_BOARD_SPRD)
832                 wifi_firmware_download();
833
834 #if defined TIZEN_WEARABLE
835         err = wifi_power_on_wearable(device_picker_test);
836 #else
837         err = wifi_power_on();
838
839         if (device_picker_test == TRUE)
840                 netconfig_wifi_enable_device_picker_test();
841 #endif
842         if (err < 0) {
843                 if (err == -EALREADY)
844                         netconfig_error_already_exists(context);
845                 else if (err == -EPERM)
846                         netconfig_error_permission_denied(context);
847                 else
848                         netconfig_error_wifi_driver_failed(context);
849
850                 return TRUE;
851         }
852
853
854         netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
855         __netconfig_set_wifi_bssid();
856
857         wifi_complete_load_driver(wifi, context);
858         return TRUE;
859 }
860
861 gboolean handle_remove_driver(Wifi *wifi, GDBusMethodInvocation *context)
862 {
863         int err;
864
865         DBG("Wi-Fi power off requested");
866
867         g_return_val_if_fail(wifi != NULL, TRUE);
868
869         err = wifi_power_off();
870         if (err < 0) {
871                 if (err == -EINPROGRESS)
872                         netconfig_error_inprogress(context);
873                 else if (err == -EALREADY)
874                         netconfig_error_already_exists(context);
875                 else if (err == -EPERM)
876                         netconfig_error_permission_denied(context);
877                 else
878                         netconfig_error_wifi_driver_failed(context);
879                 return TRUE;
880         }
881
882         netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
883
884         wifi_complete_remove_driver(wifi, context);
885         return TRUE;
886 }
887
888 gboolean handle_load_p2p_driver(Wifi *wifi, GDBusMethodInvocation *context)
889 {
890         ERR("Deprecated");
891
892         wifi_complete_load_p2p_driver(wifi, context);
893         return TRUE;
894 }
895
896 gboolean handle_remove_p2p_driver(Wifi *wifi, GDBusMethodInvocation *context)
897 {
898         ERR("Deprecated");
899
900         wifi_complete_remove_p2p_driver(wifi, context);
901         return TRUE;
902 }
903
904 static int __netconfig_get_random_mac(unsigned char *mac_buf, int mac_len)
905 {
906         DBG("Generate Random Mac address of ethernet");
907         FILE *fp;
908         int rc;
909
910         fp = fopen(OS_RANDOM_FILE, "rb");
911
912         if (fp == NULL) {
913                 ERR("Could not open /dev/urandom");
914                 return -1;
915         }
916         rc = fread(mac_buf, 1, mac_len, fp);
917         if (fp)
918                 fclose(fp);
919
920         return rc != mac_len ? -1 : 0;
921 }
922
923 void __netconfig_set_ether_macaddr()
924 {
925         DBG("Set wired Mac address ");
926         char *mac_addr = NULL;
927         char rand_addr[WLAN_MAC_ADDR_MAX];
928         int rv = -1;
929
930         mac_addr = vconf_get_str(VCONF_ETH_MAC_ADDRESS);
931         if (mac_addr == NULL) {
932                 DBG("vconf_get_str Failed\n");
933                 return;
934         }
935         /* Checking Invalid MAC Address */
936         if ((strlen(mac_addr) == 0)) {
937                 ERR("Failed to get valid MAC Address from vconf");
938                 /*Generate the Random Mac address*/
939                 unsigned char rand_mac_add[ETH_MAC_ADDR_SIZE+1];
940
941                 if (__netconfig_get_random_mac(rand_mac_add, ETH_MAC_ADDR_SIZE) == -1) {
942
943                         ERR("Could not generate the Random Mac address");
944                         free(mac_addr);
945                         return;
946                 }
947
948                 rand_mac_add[0] &= 0xFE; /*Clear multicase bit*/
949                 rand_mac_add[0] |= 0x02; /*set local assignment bit*/
950
951                 /*Set the Mac address in Vconf*/
952                 snprintf(rand_addr, WLAN_MAC_ADDR_MAX, "%x:%x:%x:%x:%x:%x",
953                                 rand_mac_add[0], rand_mac_add[1],
954                                 rand_mac_add[2], rand_mac_add[3],
955                                 rand_mac_add[4], rand_mac_add[5]);
956
957                 netconfig_set_vconf_str(VCONF_ETH_MAC_ADDRESS, rand_addr);
958         } else { /* Valid MAC address */
959                 g_strlcpy(rand_addr, mac_addr, WLAN_MAC_ADDR_MAX);
960         }
961
962         DBG("MAC Address of eth0 [%s]", rand_addr);
963         const char *path = NET_EXEC_PATH;
964         char *const args[] = { "/sbin/ifconfig", "eth0", "hw",
965                 "ether", rand_addr, "up", NULL};
966         char *const envs[] = { NULL };
967         rv = netconfig_execute_file(path, args, envs);
968
969         if (rv < 0)
970                 ERR("Unable to execute system command");
971         free(mac_addr);
972
973 }