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