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