Create new rpm for wearable profile
[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 *param0 = NULL;
225         GVariant *params = NULL;
226         char key[] = "Powered";
227
228         if (wifi_state_is_technology_available() == FALSE) {
229                 retry_count--;
230                 if (retry_count > 0)
231                         return TRUE;
232         }
233
234         param0 = g_variant_new_boolean(value_enable);
235         params = g_variant_new("(sv)", key, param0);
236
237         reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
238                                         CONNMAN_WIFI_TECHNOLOGY_PREFIX,
239                                         CONNMAN_TECHNOLOGY_INTERFACE,
240                                         "SetProperty", params, __technology_reply);
241
242         if (reply != TRUE) {
243                 ERR("Fail to set technology enable");
244                 wifi_state_update_power_state(FALSE);
245
246                 retry_count = NETCONFIG_TECH_WAITING_COUNT;
247                 return FALSE;
248         }
249
250         retry_count = NETCONFIG_TECH_WAITING_COUNT;
251         return FALSE;
252 }
253
254 static int _set_connman_technology_power(gboolean enable)
255 {
256         gboolean reply = FALSE;
257         GVariant *param0 = NULL;
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         if (enable == TRUE)
274                 param0 = g_variant_new_boolean(value_enable);
275         else
276                 param0 = g_variant_new_boolean(value_disable);
277
278         params = g_variant_new("(sv)", key, param0);
279
280         reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
281                                         CONNMAN_WIFI_TECHNOLOGY_PREFIX, CONNMAN_TECHNOLOGY_INTERFACE,
282                                         "SetProperty", params, __technology_reply);
283
284         if (reply != TRUE) {
285                 ERR("Fail to set technology %s", enable == TRUE ? "enable" : "disable");
286                 return -ESRCH;
287         }
288
289         /* If Wi-Fi powered off,
290          * Do not remove Wi-Fi driver until ConnMan technology state updated
291          */
292         if (enable == TRUE)
293                 connman_wifi_technology_state = enable;
294
295         /* To be keep safe, early disable Wi-Fi tech state */
296         if (enable != TRUE)
297                 wifi_state_set_tech_state(NETCONFIG_WIFI_TECH_WPS_ONLY);
298
299         return 0;
300 }
301
302 static void __netconfig_set_wifi_bssid(void)
303 {
304         int rv = 0;
305         char bssid[WLAN_MAC_ADDR_MAX];
306
307         FILE *fp = fopen(WLAN_MAC_ADDRESS_FILEPATH, "r");
308
309         if (fp == NULL) {
310                 ERR("Fail to open %s", WLAN_MAC_ADDRESS_FILEPATH);
311                 return;
312         }
313
314         fseek(fp, 0L, SEEK_SET);
315         rv = fscanf(fp, "%17s", bssid);
316
317         if (rv < 0)
318                 ERR("Fail to read bssid");
319
320         netconfig_set_vconf_str(VCONF_WIFI_BSSID_ADDRESS, bssid);
321
322         fclose(fp);
323 }
324
325 void netconfig_wifi_disable_technology_state_by_only_connman_signal(void)
326 {
327         /* Important: it's only done by ConnMan technology signal update */
328         connman_wifi_technology_state = FALSE;
329 }
330
331 #if defined TIZEN_WEARABLE
332 int netconfig_wifi_on_wearable(gboolean device_picker_test)
333 {
334         int err = 0;
335         int wifi_use;
336         int ps_mode;
337
338         if (netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use) < 0) {
339                 ERR("Fail to get VCONF_WIFI_WEARABLE_WIFI_USE");
340                 return -EIO;
341         }
342
343         if (wifi_use > 0) {
344                 if (netconfig_vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &ps_mode) < 0) {
345                         ERR("Fail to get VCONFKEY_SETAPPL_PSMODE");
346                         return -EIO;
347                 }
348
349                 if (ps_mode > SETTING_PSMODE_NORMAL) {
350                         WARN("ps mode is on(%d), Not turn on Wi-Fi", ps_mode);
351                         return -EPERM;
352                 }
353         } else {
354                 WARN("Not permitted Wi-Fi on");
355                 return -EPERM;
356         }
357
358         err = wifi_power_driver_and_supplicant(TRUE);
359         if (err < 0 && err != -EALREADY)
360                 return err;
361
362         err = _set_connman_technology_power(TRUE);
363
364         if (device_picker_test == TRUE)
365                 netconfig_wifi_enable_device_picker_test();
366
367         return err;
368 }
369
370 static void __wearable_wifi_use_changed_cb(keynode_t* node, void* user_data)
371 {
372         int wifi_state;
373         int wifi_use = 1;
374
375         if (netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state) < 0) {
376                 ERR("Fail to get VCONFKEY_WIFI_STATE");
377                 return;
378         }
379
380         if (node != NULL)
381                 wifi_use = vconf_keynode_get_int(node);
382         else
383                 netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use);
384
385         if (wifi_use > 0) {
386                 DBG("wifi use on");
387                 if (wifi_state > VCONFKEY_WIFI_OFF) {
388                         WARN("Wi-Fi is already turned on");
389                         return;
390                 }
391                 wifi_power_on_wearable(TRUE);
392         } else {
393                 ERR("## wifi use [OFF]");
394                 if (wifi_state == VCONFKEY_WIFI_OFF) {
395                         WARN("Wi-Fi is already turned off");
396                         return;
397                 }
398
399                 wifi_power_off();
400         }
401 }
402 #else
403 static void __netconfig_wifi_restrict_mode(keynode_t *node, void *user_data)
404 {
405         int wifi_state = 0, restricted = 0;
406         int wifi_off_by_restricted = 0;
407
408         netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, &wifi_off_by_restricted);
409
410         netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
411
412         if (node != NULL)
413                 restricted = vconf_keynode_get_bool(node);
414         else
415                 netconfig_vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE, &restricted);
416
417         DBG("network restricted mode %s", restricted > 0 ? "ON" : "OFF");
418         DBG("Wi-Fi state %d, Wi-Fi was off by restricted mode %s", wifi_state,
419                         wifi_off_by_restricted ? "Yes" : "No");
420
421         if (restricted > 0) {
422                 /* network restricted on */
423                 if (wifi_state == VCONFKEY_WIFI_OFF)
424                         return;
425
426                 wifi_power_off();
427
428                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, 1);
429         } else {
430                 /* network restricted off */
431                 if (!wifi_off_by_restricted)
432                         return;
433
434                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, 0);
435
436                 if (wifi_state > VCONFKEY_WIFI_OFF)
437                         return;
438
439                 wifi_power_on();
440         }
441 }
442 #endif
443
444 static void __netconfig_wifi_airplane_mode(keynode_t *node, void *user_data)
445 {
446         int wifi_state = 0, airplane_state = 0;
447         int wifi_off_by_airplane = 0;
448
449         netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, &wifi_off_by_airplane);
450
451 #if defined TIZEN_WEARABLE
452         netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_state);
453 #else
454         netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
455 #endif
456
457         if (node != NULL)
458                 airplane_state = vconf_keynode_get_bool(node);
459         else
460                 netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &airplane_state);
461
462         DBG("airplane mode %s (prev:%d)", airplane_state > 0 ? "ON" : "OFF", airplane_mode);
463         DBG("Wi-Fi state(or use) %d, Wi-Fi was off by flight mode %s", wifi_state,
464                         wifi_off_by_airplane ? "Yes" : "No");
465
466         if (airplane_mode == airplane_state)
467                 return ;
468
469         airplane_mode = airplane_state;
470
471         if (airplane_state > 0) {
472                 /* airplane mode on */
473                 if (wifi_state == VCONFKEY_WIFI_OFF)
474                         return;
475
476                 wifi_power_off();
477
478                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 1);
479 #if defined TIZEN_WEARABLE
480                 netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, 0);
481 #endif
482         } else {
483                 /* airplane mode off */
484                 if (!wifi_off_by_airplane)
485                         return;
486
487                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
488 #if defined TIZEN_WEARABLE
489                 netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, 1);
490 #else
491                 if (wifi_state > VCONFKEY_WIFI_OFF)
492                         return;
493
494                 wifi_power_on();
495 #endif
496         }
497 }
498
499 static void __emergency_mode_changed_cb(keynode_t *node, void *user_data)
500 {
501         int wifi_state = 0, emergency = 0;
502         int wifi_off_by_emergency = 0;
503 #if !defined TIZEN_WEARABLE
504         int emergency_by_fmm = 0;
505 #endif
506 #if defined TIZEN_WEARABLE
507         int wifi_use = 1;
508 #endif
509
510         netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, &wifi_off_by_emergency);
511         netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
512
513 #if !defined TIZEN_WEARABLE
514         netconfig_vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_PERMIT_WITH_LCD_OFF_LIMIT, &emergency_by_fmm);
515         DBG("emergency mode by Find My Mobile (%d)", emergency_by_fmm);
516         if (emergency_by_fmm == 1)
517                 return;
518 #endif
519
520         if (node != NULL)
521                 emergency = vconf_keynode_get_int(node);
522         else
523                 netconfig_vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &emergency);
524
525         DBG("emergency mode %s", emergency > SETTING_PSMODE_POWERFUL ? "ON" : "OFF");
526         DBG("Wi-Fi state %d, Wi-Fi was off by emergency mode %s", wifi_state, wifi_off_by_emergency ? "Yes" : "No");
527
528 #if defined TIZEN_WEARABLE
529         if (emergency == SETTING_PSMODE_WEARABLE) {
530                 /* basic power saving mode on */
531         } else if (emergency == SETTING_PSMODE_WEARABLE_ENHANCED) {
532                 /* enhanced power saving mode on */
533                 netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use);
534                 psmode_wifi_use = wifi_use;
535                 if (wifi_use != 0)
536                         netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, 0);
537
538                 if (wifi_state == VCONFKEY_WIFI_OFF)
539                         return;
540
541                 wifi_power_off();
542                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 1);
543         } else {
544                 /* power saving mode off */
545                 netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, psmode_wifi_use);
546                 if (!wifi_off_by_emergency)
547                         return;
548
549                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 0);
550                 if (wifi_state > VCONFKEY_WIFI_OFF)
551                         return;
552
553                 wifi_power_on_wearable(TRUE);
554         }
555 #else
556         if (emergency > SETTING_PSMODE_POWERFUL) {
557                 /* emergency mode on */
558                 if (wifi_state == VCONFKEY_WIFI_OFF)
559                         return;
560
561                 wifi_power_off();
562
563                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 1);
564         } else {
565                 /* emergency mode off */
566                 if (!wifi_off_by_emergency)
567                         return;
568
569                 netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 0);
570
571                 if (wifi_state > VCONFKEY_WIFI_OFF)
572                         return;
573
574                 wifi_power_on();
575         }
576 #endif
577
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                 netconfig_wifi_bgscan_stop();
607                 netconfig_wifi_bgscan_set_interval(SCAN_EXPONENTIAL_MIN);
608                 netconfig_wifi_bgscan_start(TRUE);
609         }
610
611         prev_state = new_state;
612 }
613
614 static void __netconfig_telephony_ready_changed_cb(keynode_t * node, void *data)
615 {
616         int telephony_ready = 0;
617
618         if (node != NULL)
619                 telephony_ready = vconf_keynode_get_bool(node);
620         else
621                 netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_READY, &telephony_ready);
622
623         if (telephony_ready != 0) {
624                 if (netconfig_tapi_check_sim_state() == FALSE) {
625                         DBG("Sim is not initialized yet.");
626
627                         goto done;
628                 }
629         } else
630                 return;
631
632         DBG("Turn Wi-Fi on automatically");
633
634 #if defined TIZEN_WEARABLE
635         wifi_power_on_wearable(TRUE);
636 #else
637         wifi_power_on();
638 #endif
639
640 done:
641         vconf_ignore_key_changed(VCONFKEY_TELEPHONY_READY, __netconfig_telephony_ready_changed_cb);
642 }
643
644 int wifi_power_driver_and_supplicant(gboolean enable)
645 {
646         /* There are 3 thumb rules for Wi-Fi power management
647          *   1. Do not make exposed API to control wpa_supplicant and driver directly.
648          *      It probably breaks ConnMan technology operation.
649          *
650          *   2. Do not remove driver and wpa_supplicant if ConnMan already enabled.
651          *      It breaks ConnMan technology operation.
652          *
653          *   3. Final the best rule: make it as simple as possible.
654          *      Simple code enables easy maintenance and reduces logical errors.
655          */
656         if (enable == TRUE) {
657                 return _load_driver_and_supplicant();
658         } else {
659                 if (connman_wifi_technology_state == TRUE)
660                         return -ENOSYS;
661
662                 return _remove_driver_and_supplicant();
663         }
664 }
665
666 void wifi_power_disable_technology_state_by_only_connman_signal(void)
667 {
668         /* Important: it's only done by ConnMan technology signal update */
669         connman_wifi_technology_state = FALSE;
670 }
671
672 void wifi_power_recover_firmware(void)
673 {
674         wifi_firmware_recovery_mode = TRUE;
675
676         netconfig_wifi_bgscan_stop();
677
678         wifi_power_off();
679 }
680
681 int wifi_power_on(void)
682 {
683         int err = 0;
684         wifi_tech_state_e tech_state;
685
686         tech_state = wifi_state_get_technology_state();
687         if (tech_state >= NETCONFIG_WIFI_TECH_POWERED) {
688                 /* There can be a scenario where wifi is automatically *
689                  * activated by connman if wifi was powered in last boot. *
690                  * So we should update connman_wifi_technology_state variable *
691                  * if it is found that wifi_tech_state variable is *
692                  * NETCONFIG_WIFI_TECH_POWERED and connman_wifi_technology_state *
693                  * variable is FALSE. Earlier connman_wifi_technology_state *
694                  * variable was only updated when wifi was Powered on from *
695                  * net-config resulting in variable not getting updated. *
696                  * This caused wifi to not get deactivated after reboot if *
697                  * last power state was activated */
698                 ERR("Net-Config WiFi connman technology state %d",
699                                 connman_wifi_technology_state);
700                 if (connman_wifi_technology_state == FALSE)
701                         connman_wifi_technology_state = TRUE;
702                 return -EALREADY;
703         }
704
705         if (__is_wifi_restricted() == TRUE)
706                 return -EPERM;
707
708         if (netconfig_is_wifi_tethering_on() == TRUE) {
709                 /* TODO: Wi-Fi tethering turns off here */
710                 /* return TRUE; */
711                 ERR("Failed to turn tethering off");
712                 return -EBUSY;
713         }
714
715         err = wifi_power_driver_and_supplicant(TRUE);
716         if (err < 0 && err != -EALREADY)
717                 return err;
718
719         err = _set_connman_technology_power(TRUE);
720
721         return err;
722 }
723
724 int wifi_power_off(void)
725 {
726         int err;
727
728         err = _set_connman_technology_power(FALSE);
729         if (err == -EALREADY)
730                 wifi_state_update_power_state(FALSE);
731
732         return 0;
733 }
734
735 #if defined TIZEN_WEARABLE
736 int wifi_power_on_wearable(gboolean device_picker_test)
737 {
738         int err = 0;
739         int wifi_use = 1;
740         wifi_tech_state_e tech_state;
741
742         tech_state = wifi_state_get_technology_state();
743         if (tech_state >= NETCONFIG_WIFI_TECH_POWERED)
744                 return -EALREADY;
745
746         if (netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use) < 0) {
747                 ERR("Fail to get VCONF_WIFI_WEARABLE_WIFI_USE");
748                 return -EIO;
749         }
750
751         if (wifi_use == 0) {
752                 WARN("VCONF_WIFI_WEARABLE_WIFI_USE is OFF");
753                 return -EPERM;
754         }
755
756         err = wifi_power_driver_and_supplicant(TRUE);
757         if (err < 0 && err != -EALREADY)
758                 return err;
759
760         err = _set_connman_technology_power(TRUE);
761
762         if (device_picker_test == TRUE)
763                 netconfig_wifi_enable_device_picker_test();
764
765         return err;
766 }
767 #endif
768
769 void wifi_power_initialize(void)
770 {
771         int wifi_last_power_state = 0;
772
773         /* Initialize Airplane mode */
774         netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &airplane_mode);
775         DBG("Airplane[%s]", airplane_mode > 0 ? "ON" : "OFF");
776
777         /* Update the last Wi-Fi power state */
778         netconfig_vconf_get_int(VCONF_WIFI_LAST_POWER_STATE, &wifi_last_power_state);
779         if (wifi_last_power_state > VCONFKEY_WIFI_OFF) {
780                 if (TIZEN_TELEPHONY_ENABLE) {
781                         int telephony_ready = 0;
782                         netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_READY, &telephony_ready);
783                         if (telephony_ready == 0) {
784                                 DBG("Telephony API is not initialized yet");
785                                 vconf_notify_key_changed(VCONFKEY_TELEPHONY_READY,
786                                                 __netconfig_telephony_ready_changed_cb, NULL);
787                         } else {
788                                 if (netconfig_tapi_check_sim_state() == FALSE)
789                                         DBG("SIM is not initialized yet");
790                         }
791                 }
792                 DBG("Turn Wi-Fi on automatically");
793 #if defined TIZEN_WEARABLE
794                 wifi_power_on_wearable(TRUE);
795 #else
796                 wifi_power_on();
797 #endif
798         }
799
800 #if defined TIZEN_WEARABLE
801         vconf_notify_key_changed(VCONF_WIFI_WEARABLE_WIFI_USE, __wearable_wifi_use_changed_cb, NULL);
802
803         vconf_notify_key_changed(VCONFKEY_TELEPHONY_FLIGHT_MODE,
804                         __netconfig_wifi_airplane_mode, NULL);
805 #else
806         vconf_notify_key_changed(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE,
807                         __netconfig_wifi_restrict_mode, NULL);
808         vconf_notify_key_changed(VCONFKEY_TELEPHONY_FLIGHT_MODE,
809                         __netconfig_wifi_airplane_mode, NULL);
810 #endif
811
812         vconf_notify_key_changed(VCONFKEY_SETAPPL_PSMODE, __emergency_mode_changed_cb, NULL);
813         vconf_notify_key_changed(VCONFKEY_PM_STATE, __pm_state_changed_cb, NULL);
814 }
815
816 void wifi_power_deinitialize(void)
817 {
818 }
819
820 gboolean handle_load_driver(Wifi *wifi,
821                 GDBusMethodInvocation *context, gboolean device_picker_test)
822 {
823         int err;
824
825         DBG("Wi-Fi power on requested");
826
827         g_return_val_if_fail(wifi != NULL, FALSE);
828
829         if (!netconfig_dpm_update_from_wifi()) {
830                 DBG("DPM policy restricts Wi-Fi");
831                 netconfig_error_permission_denied(context);
832                 return TRUE;
833         }
834
835         if (TIZEN_WLAN_BOARD_SPRD)
836                 wifi_firmware_download();
837
838 #if defined TIZEN_WEARABLE
839         err = wifi_power_on_wearable(device_picker_test);
840 #else
841         err = wifi_power_on();
842
843         if (device_picker_test == TRUE)
844                 netconfig_wifi_enable_device_picker_test();
845 #endif
846         if (err < 0) {
847                 if (err == -EINPROGRESS)
848                         netconfig_error_inprogress(context);
849                 else if (err == -EALREADY)
850                         netconfig_error_already_exists(context);
851                 else if (err == -EPERM)
852                         netconfig_error_permission_denied(context);
853                 else
854                         netconfig_error_wifi_driver_failed(context);
855
856                 return TRUE;
857         }
858
859
860         netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
861         __netconfig_set_wifi_bssid();
862
863         wifi_complete_load_driver(wifi, context);
864         return TRUE;
865 }
866
867 gboolean handle_remove_driver(Wifi *wifi, GDBusMethodInvocation *context)
868 {
869         int err;
870
871         DBG("Wi-Fi power off requested");
872
873         g_return_val_if_fail(wifi != NULL, FALSE);
874
875         err = wifi_power_off();
876         if (err < 0) {
877                 if (err == -EINPROGRESS)
878                         netconfig_error_inprogress(context);
879                 else if (err == -EALREADY)
880                         netconfig_error_already_exists(context);
881                 else if (err == -EPERM)
882                         netconfig_error_permission_denied(context);
883                 else
884                         netconfig_error_wifi_driver_failed(context);
885                 return TRUE;
886         }
887
888         netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
889
890         wifi_complete_remove_driver(wifi, context);
891         return TRUE;
892 }
893
894 gboolean handle_load_p2p_driver(Wifi *wifi, GDBusMethodInvocation *context)
895 {
896         ERR("Deprecated");
897
898         wifi_complete_load_p2p_driver(wifi, context);
899         return TRUE;
900 }
901
902 gboolean handle_remove_p2p_driver(Wifi *wifi, GDBusMethodInvocation *context)
903 {
904         ERR("Deprecated");
905
906         wifi_complete_remove_p2p_driver(wifi, context);
907         return TRUE;
908 }
909
910 static int __netconfig_get_random_mac(unsigned char *mac_buf, int mac_len)
911 {
912         DBG("Generate Random Mac address of ethernet");
913         FILE *fp;
914         int rc;
915
916         fp = fopen(OS_RANDOM_FILE, "rb");
917
918         if (fp == NULL) {
919                 ERR("Could not open /dev/urandom");
920                 return -1;
921         }
922         rc = fread(mac_buf, 1, mac_len, fp);
923         if (fp)
924                 fclose(fp);
925
926         return rc != mac_len ? -1 : 0;
927 }
928
929 void __netconfig_set_ether_macaddr()
930 {
931         DBG("Set wired Mac address ");
932         char *mac_addr = NULL;
933         char rand_addr[WLAN_MAC_ADDR_MAX];
934         int rv = -1;
935
936         mac_addr = vconf_get_str(VCONF_ETH_MAC_ADDRESS);
937         if (mac_addr == NULL) {
938                 DBG("vconf_get_str Failed\n");
939                 return;
940         }
941         /* Checking Invalid MAC Address */
942         if ((strlen(mac_addr) == 0)) {
943                 ERR("Failed to get valid MAC Address from vconf");
944                 /*Generate the Random Mac address*/
945                 unsigned char rand_mac_add[ETH_MAC_ADDR_SIZE+1];
946
947                 if (__netconfig_get_random_mac(rand_mac_add, ETH_MAC_ADDR_SIZE) == -1) {
948
949                         ERR("Could not generate the Random Mac address");
950                         free(mac_addr);
951                         return;
952                 }
953
954                 rand_mac_add[0] &= 0xFE; /*Clear multicase bit*/
955                 rand_mac_add[0] |= 0x02; /*set local assignment bit*/
956
957                 /*Set the Mac address in Vconf*/
958                 snprintf(rand_addr, WLAN_MAC_ADDR_MAX, "%x:%x:%x:%x:%x:%x",
959                                 rand_mac_add[0], rand_mac_add[1],
960                                 rand_mac_add[2], rand_mac_add[3],
961                                 rand_mac_add[4], rand_mac_add[5]);
962
963                 netconfig_set_vconf_str(VCONF_ETH_MAC_ADDRESS, rand_addr);
964         } else { /* Valid MAC address */
965                 g_strlcpy(rand_addr, mac_addr, WLAN_MAC_ADDR_MAX);
966         }
967
968         DBG("MAC Address of eth0 [%s]", rand_addr);
969         const char *path = NET_EXEC_PATH;
970         char *const args[] = { "/sbin/ifconfig", "eth0", "hw",
971                 "ether", rand_addr, "up", NULL};
972         char *const envs[] = { NULL };
973         rv = netconfig_execute_file(path, args, envs);
974
975         if (rv < 0)
976                 ERR("Unable to execute system command");
977         free(mac_addr);
978
979 }