X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fwifi-power.c;h=71e953058c235d4ec5bfc5553ac4350104c3425e;hb=46a7bfcb29ca7642cae080ca393cf145d15fb232;hp=6eb0fea09f2fa118dfb0e08fefdecb80f5279215;hpb=f648cc946caff6519c745280a9810a0a52af6700;p=platform%2Fcore%2Fconnectivity%2Fnet-config.git diff --git a/src/wifi-power.c b/src/wifi-power.c old mode 100644 new mode 100755 index 6eb0fea..71e9530 --- a/src/wifi-power.c +++ b/src/wifi-power.c @@ -1,7 +1,7 @@ /* * Network Configuration Module * - * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. All rights reserved. + * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,401 +17,949 @@ * */ -#include -#include +#include #include #include -#include +#include +#include +#include +#include +#include +#include -#include "wifi.h" #include "log.h" -#include "wifi.h" #include "util.h" #include "netdbus.h" #include "neterror.h" -#include "netconfig.h" -#include "emulator.h" -#include "network-statistics.h" -#include "wifi-background-scan.h" +#include "wifi-wps.h" +#include "wifi-bssid-scan.h" #include "wifi-power.h" #include "wifi-state.h" -#include "mdm-private.h" -#include "wifi-agent.h" -#include "wifi-eap-config.h" +#include "netsupplicant.h" +#include "network-state.h" +#include "network-dpm.h" +#include "wifi-firmware.h" +#include "wifi-background-scan.h" -#define WLAN_DRIVER_SCRIPT "/usr/bin/wlan.sh" +#define WLAN_SUPPLICANT_SCRIPT "/usr/bin/wpa_supp.sh" +#define P2P_SUPPLICANT_SCRIPT "/usr/bin/p2p_supp.sh" -static gboolean power_in_progress = FALSE; -static gboolean fm_waiting = FALSE; +#define VCONF_WIFI_OFF_STATE_BY_AIRPLANE "file/private/wifi/wifi_off_by_airplane" +#define VCONF_WIFI_OFF_STATE_BY_RESTRICTED "file/private/wifi/wifi_off_by_restricted" +#define VCONF_WIFI_OFF_STATE_BY_EMERGENCY "file/private/wifi/wifi_off_by_emergency" +#if !defined TIZEN_WEARABLE +#define VCONFKEY_SETAPPL_NETWORK_PERMIT_WITH_LCD_OFF_LIMIT "db/setting/network_with_lcd_off_limit" +#endif -static gboolean __netconfig_wifi_enable_technology(void) -{ - DBusMessage *reply = NULL; - char param1[] = "string:Powered"; - char param2[] = "variant:boolean:true"; - char *param_array[] = {NULL, NULL, NULL}; +#define WLAN_MAC_ADDRESS_FILEPATH "/sys/class/net/wlan0/address" +#define WLAN_MAC_ADDR_MAX 20 +#define VCONF_WIFI_BSSID_ADDRESS "db/wifi/bssid_address" - param_array[0] = param1; - param_array[1] = param2; +#define ETH_MAC_ADDR_SIZE 6 +#define VCONF_ETH_MAC_ADDRESS "db/dnet/mac_address" +#define NET_EXEC_PATH "/sbin/ifconfig" +#define OS_RANDOM_FILE "/dev/urandom" - reply = netconfig_invoke_dbus_method(CONNMAN_SERVICE, CONNMAN_WIFI_TECHNOLOGY_PREFIX, - CONNMAN_TECHNOLOGY_INTERFACE, "SetProperty", param_array); +#define NETCONFIG_TECH_WAITING_INTERVAL 500 +#define NETCONFIG_TECH_WAITING_COUNT 6 +#define MAX_DRV_CMD_SIZE 248 +#define WLAN_IOCTL_SUSPEND (SIOCDEVPRIVATE + 1) - if (reply == NULL) { - ERR("Error! Request failed"); - return FALSE; - } +static gboolean connman_wifi_technology_state = FALSE; +static gboolean wifi_firmware_recovery_mode = FALSE; +static int airplane_mode = 0; - dbus_message_unref(reply); +typedef struct { + char *buf; + int used_len; + int total_len; +} netconfig_wifi_priv_cmd; - return TRUE; +static gboolean __is_wifi_restricted(void) +{ +#if defined TIZEN_WEARABLE + return FALSE; +#endif + int restricted_mode = 0; + + netconfig_vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE, &restricted_mode); + if (restricted_mode != 0) { + DBG("network restricted mode[%d]", restricted_mode); + return TRUE; + } + + return FALSE; } -static gboolean __netconfig_wifi_disable_technology(void) +static void __technology_reply(GObject *source_object, GAsyncResult *res, gpointer user_data) { - DBusMessage *reply = NULL; - char param1[] = "string:Powered"; - char param2[] = "variant:boolean:false"; - char *param_array[] = {NULL, NULL, NULL}; - - param_array[0] = param1; - param_array[1] = param2; + GVariant *reply; + GDBusConnection *conn = NULL; + GError *error = NULL; - reply = netconfig_invoke_dbus_method(CONNMAN_SERVICE, CONNMAN_WIFI_TECHNOLOGY_PREFIX, - CONNMAN_TECHNOLOGY_INTERFACE, "SetProperty", param_array); + conn = G_DBUS_CONNECTION(source_object); + reply = g_dbus_connection_call_finish(conn, res, &error); if (reply == NULL) { - ERR("Error! Request failed"); - return FALSE; + if (error != NULL) { + if (g_strstr_len(error->message, strlen(error->message), + CONNMAN_ERROR_INTERFACE ".AlreadyEnabled") != NULL) { + wifi_state_update_power_state(TRUE); + } else if (g_strstr_len(error->message, strlen(error->message), + CONNMAN_ERROR_INTERFACE ".AlreadyDisabled") != NULL) { + wifi_state_update_power_state(FALSE); + } else { + ERR("Fail to request status [%d: %s]", error->code, error->message); + wifi_state_update_power_state(FALSE); + } + g_error_free(error); + } else { + ERR("Fail to request status"); + wifi_state_update_power_state(FALSE); + } + } else { + DBG("Successfully requested"); + g_variant_unref(reply); } - dbus_message_unref(reply); - - return TRUE; + netconfig_gdbus_pending_call_unref(); } -static gboolean __netconfig_wifi_load_driver(void) +static int __execute_supplicant(gboolean enable) { - gboolean rv = FALSE; - const char *path = WLAN_DRIVER_SCRIPT; - char *const args[] = { "wlan.sh", "start", NULL }; + int rv = 0; + const char *path = WLAN_SUPPLICANT_SCRIPT; + char *const args_enable[] = { "/usr/bin/wpa_supp.sh", "start", NULL }; + char *const args_disable[] = { "/usr/bin/wpa_supp.sh", "stop", NULL }; char *const envs[] = { NULL }; + static gboolean enabled = FALSE; - if (netconfig_emulator_is_emulated() == TRUE) - return rv; + if (enabled == enable) + return -EALREADY; - rv = netconfig_execute_file(path, args, envs); - if (rv != TRUE) { - DBG("Failed to load wireless device driver"); - return FALSE; - } + if (enable == TRUE) + rv = netconfig_execute_file(path, args_enable, envs); + else + rv = netconfig_execute_file(path, args_disable, envs); + if (rv < 0) + return -EIO; - DBG("Successfully loaded wireless device driver"); - return TRUE; + DBG("wpa_supplicant %s", enable == TRUE ? "started" : "stopped"); + + enabled = enable; + + return 0; } -gboolean netconfig_wifi_remove_driver(void) +void netconfig_wifi_recover_firmware(void) { - gboolean rv = FALSE; - const char *path = WLAN_DRIVER_SCRIPT; - char *const args[] = { "wlan.sh", "stop", NULL }; - char *const env[] = { NULL }; + wifi_firmware_recovery_mode = TRUE; - if (netconfig_emulator_is_emulated() == TRUE) - return rv; + netconfig_wifi_bgscan_stop(); - rv = netconfig_execute_file(path, args, env); - if (rv != TRUE) { - DBG("Failed to remove wireless device driver"); - return FALSE; + wifi_power_off(); +} + +static int _load_driver_and_supplicant(void) +{ + int err = 0; + wifi_tech_state_e tech_state; + + tech_state = wifi_state_get_technology_state(); + if (tech_state > NETCONFIG_WIFI_TECH_OFF) + return -EALREADY; + + err = __execute_supplicant(TRUE); + if (err < 0 && err != -EALREADY) + return err; + + err = netconfig_wifi_firmware(NETCONFIG_WIFI_STA, TRUE); + if (err < 0 && err != -EALREADY) { + __execute_supplicant(FALSE); + return err; } - DBG("Successfully removed wireless device driver"); - return TRUE; -} + wifi_state_set_tech_state(NETCONFIG_WIFI_TECH_WPS_ONLY); -static int __netconfig_wifi_try_to_load_driver(void); -static gboolean __netconfig_wifi_try_to_remove_driver(void); + return 0; +} -void netconfig_wifi_notify_power_completed(gboolean power_on) +static int _remove_driver_and_supplicant(void) { - DBusMessage *signal; - DBusConnection *connection; - DBusError error; - char *sig_name; + int err = 0; - if (power_on) - sig_name = "PowerOnCompleted"; - else - sig_name = "PowerOffCompleted"; + DBG("remove driver and supplicant"); + if (wifi_firmware_recovery_mode != TRUE && + netconfig_wifi_is_bssid_scan_started() == TRUE) { + DBG("Wi-Fi WPS mode"); + return 0; + } - dbus_error_init(&error); + err = netconfig_wifi_firmware(NETCONFIG_WIFI_STA, FALSE); + if (err < 0 && err != -EALREADY) + return err; - connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error); - if (connection == NULL) { - ERR("Error!!! Failed to get system DBus, error [%s]", error.message); - dbus_error_free(&error); - return; - } + err = __execute_supplicant(FALSE); + if (err < 0 && err != -EALREADY) + return err; - signal = dbus_message_new_signal(NETCONFIG_WIFI_PATH, - NETCONFIG_WIFI_INTERFACE, sig_name); - if (signal == NULL) - return; + wifi_state_set_tech_state(NETCONFIG_WIFI_TECH_OFF); - dbus_connection_send(connection, signal, NULL); + // reset service state + wifi_state_set_service_state(NETCONFIG_WIFI_IDLE); - dbus_message_unref(signal); - dbus_connection_unref(connection); + if (wifi_firmware_recovery_mode == TRUE) { + if (wifi_power_on() < 0) + ERR("Failed to recover Wi-Fi firmware"); - INFO("(%s)", sig_name); + wifi_firmware_recovery_mode = FALSE; + } + + return 0; } -static void __netconfig_wifi_direct_state_cb(int error_code, - wifi_direct_device_state_e device_state, void *user_data) +static gboolean __check_and_set_technology_enable(gpointer data) { - wifi_direct_unset_device_state_changed_cb(); - wifi_direct_deinitialize(); + static int retry_count = NETCONFIG_TECH_WAITING_COUNT; + gboolean value_enable = TRUE; + gboolean reply = FALSE; + GVariant *params = NULL; + char key[] = "Powered"; + + if (wifi_state_is_technology_available() == FALSE) { + retry_count--; + if (retry_count > 0) + return TRUE; + } - if (device_state == WIFI_DIRECT_DEVICE_STATE_DEACTIVATED) { - if (__netconfig_wifi_try_to_load_driver() < 0) { - power_in_progress = FALSE; + params = g_variant_new("(sv)", key, g_variant_new_boolean(value_enable)); - /* TODO: error report */ + reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE, + CONNMAN_WIFI_TECHNOLOGY_PREFIX, + CONNMAN_TECHNOLOGY_INTERFACE, + "SetProperty", params, __technology_reply); - return; - } + if (reply != TRUE) { + ERR("Fail to set technology enable"); + wifi_state_update_power_state(FALSE); + + retry_count = NETCONFIG_TECH_WAITING_COUNT; + return FALSE; } + + retry_count = NETCONFIG_TECH_WAITING_COUNT; + return FALSE; } -static gboolean __netconfig_wifi_direct_power_off(void) +static int _set_connman_technology_power(gboolean enable) { - DBG("Wi-Fi direct is turning off"); + gboolean reply = FALSE; + GVariant *params = NULL; + char key[] = "Powered"; + gboolean value_enable = TRUE; + gboolean value_disable = FALSE; + + if (connman_wifi_technology_state == enable) + return -EALREADY; + + if (enable && wifi_state_is_technology_available() == FALSE) { + netconfig_start_timer(NETCONFIG_TECH_WAITING_INTERVAL, + __check_and_set_technology_enable, NULL, NULL); + connman_wifi_technology_state = enable; + return 0; + } - if (wifi_direct_initialize() < 0) - return FALSE; + params = g_variant_new("(sv)", key, (enable == TRUE) ? + g_variant_new_boolean(value_enable) : g_variant_new_boolean(value_disable)); - if (wifi_direct_set_device_state_changed_cb( - __netconfig_wifi_direct_state_cb, NULL) < 0) - return FALSE; + reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE, + CONNMAN_WIFI_TECHNOLOGY_PREFIX, CONNMAN_TECHNOLOGY_INTERFACE, + "SetProperty", params, __technology_reply); - if (wifi_direct_deactivate() < 0) - return FALSE; + if (reply != TRUE) { + ERR("Fail to set technology %s", enable == TRUE ? "enable" : "disable"); + return -ESRCH; + } - return TRUE; + /* If Wi-Fi powered off, + * Do not remove Wi-Fi driver until ConnMan technology state updated + */ + if (enable == TRUE) + connman_wifi_technology_state = enable; + + /* To be keep safe, early disable Wi-Fi tech state */ + if (enable != TRUE) + wifi_state_set_tech_state(NETCONFIG_WIFI_TECH_WPS_ONLY); + + return 0; } -static int __netconfig_wifi_try_to_load_driver(void) +static void __netconfig_set_wifi_bssid(void) { - if (netconfig_is_wifi_allowed() != TRUE) - return -EPERM; + int rv = 0; + char bssid[WLAN_MAC_ADDR_MAX]; - if (netconfig_is_wifi_tethering_on() == TRUE) { - /* TODO: Wi-Fi tethering turns off here */ - /* return TRUE; */ - return -EBUSY; - } + FILE *fp = fopen(WLAN_MAC_ADDRESS_FILEPATH, "r"); - if (netconfig_is_wifi_direct_on() == TRUE) { - if (__netconfig_wifi_direct_power_off() == TRUE) { - power_in_progress = TRUE; - return -EINPROGRESS; - } else - return -EBUSY; + if (fp == NULL) { + ERR("Fail to open %s", WLAN_MAC_ADDRESS_FILEPATH); + return; } - if (__netconfig_wifi_load_driver() != TRUE) { - netconfig_wifi_remove_driver(); + fseek(fp, 0L, SEEK_SET); + rv = fscanf(fp, "%17s", bssid); + if (rv < 0) + ERR("Fail to read bssid"); + + netconfig_set_vconf_str(VCONF_WIFI_BSSID_ADDRESS, bssid); + + fclose(fp); +} + +void netconfig_wifi_disable_technology_state_by_only_connman_signal(void) +{ + /* Important: it's only done by ConnMan technology signal update */ + connman_wifi_technology_state = FALSE; +} + +#if defined TIZEN_WEARABLE +int netconfig_wifi_on_wearable(gboolean device_picker_test) +{ + int err = 0; + int ps_mode; + + if (netconfig_vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &ps_mode) < 0) { + ERR("Fail to get VCONFKEY_SETAPPL_PSMODE"); return -EIO; } - if (__netconfig_wifi_enable_technology() != TRUE) { - netconfig_wifi_remove_driver(); - return -EIO; + if (ps_mode > SETTING_PSMODE_NORMAL) { + WARN("ps mode is on(%d), Not turn on Wi-Fi", ps_mode); + return -EPERM; } - power_in_progress = TRUE; + err = wifi_power_driver_and_supplicant(TRUE); + if (err < 0 && err != -EALREADY) + return err; - return 0; -} + err = _set_connman_technology_power(TRUE); -static gboolean __netconfig_wifi_try_to_remove_driver(void) + if (device_picker_test == TRUE) + netconfig_wifi_enable_device_picker_test(); + + return err; +} +#else +static void __netconfig_wifi_restrict_mode(keynode_t *node, void *user_data) { - netconfig_wifi_device_picker_service_stop(); + int wifi_state = 0, restricted = 0; + int wifi_off_by_restricted = 0; - netconfig_wifi_statistics_update_powered_off(); + netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, &wifi_off_by_restricted); - if (__netconfig_wifi_disable_technology() != TRUE) - return FALSE; + netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state); + + if (node != NULL) + restricted = vconf_keynode_get_bool(node); + else + netconfig_vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE, &restricted); - power_in_progress = TRUE; + DBG("network restricted mode %s", restricted > 0 ? "ON" : "OFF"); + DBG("Wi-Fi state %d, Wi-Fi was off by restricted mode %s", wifi_state, + wifi_off_by_restricted ? "Yes" : "No"); - return TRUE; + if (restricted > 0) { + /* network restricted on */ + if (wifi_state == VCONFKEY_WIFI_OFF) + return; + + wifi_power_off(); + + netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, 1); + } else { + /* network restricted off */ + if (!wifi_off_by_restricted) + return; + + netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, 0); + + if (wifi_state > VCONFKEY_WIFI_OFF) + return; + + wifi_power_on(); + } } +#endif -static void __netconfig_wifi_airplane_mode(keynode_t* node, - void* user_data) +static void __netconfig_wifi_airplane_mode(keynode_t *node, void *user_data) { - int value = 0; - int wifi_state = 0; - static gboolean powered_off_by_flightmode = FALSE; + int wifi_state = 0, airplane_state = 0; + int wifi_off_by_airplane = 0; - if (power_in_progress) { - fm_waiting = TRUE; - return; - } + netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, &wifi_off_by_airplane); + netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state); + + if (node != NULL) + airplane_state = vconf_keynode_get_bool(node); + else + netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &airplane_state); - fm_waiting = FALSE; + DBG("airplane mode %s (prev:%d)", airplane_state > 0 ? "ON" : "OFF", airplane_mode); + DBG("Wi-Fi state(or use) %d, Wi-Fi was off by flight mode %s", wifi_state, + wifi_off_by_airplane ? "Yes" : "No"); - vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &value); - vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state); + if (airplane_mode == airplane_state) + return ; - DBG("flight mode %s", value > 0 ? "ON" : "OFF"); - DBG("Wi-Fi state %d, Wi-Fi was off by flight mode %s", - wifi_state, powered_off_by_flightmode == TRUE ? "Yes" : "No"); + airplane_mode = airplane_state; - if (value > 0) { - /* flight mode enabled */ + if (airplane_state > 0) { + /* airplane mode on */ if (wifi_state == VCONFKEY_WIFI_OFF) return; - DBG("Turning Wi-Fi off"); + wifi_power_off(); - __netconfig_wifi_try_to_remove_driver(); + netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 1); + } else { + /* airplane mode off */ + if (!wifi_off_by_airplane) + return; - powered_off_by_flightmode = TRUE; - } else if (value == 0) { - /* flight mode disabled */ + netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0); if (wifi_state > VCONFKEY_WIFI_OFF) return; - if (powered_off_by_flightmode != TRUE) + wifi_power_on(); + } +} + +static void __emergency_mode_changed_cb(keynode_t *node, void *user_data) +{ + int wifi_state = 0, emergency = 0; + int wifi_off_by_emergency = 0; +#if !defined TIZEN_WEARABLE + int emergency_by_fmm = 0; +#endif + netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, &wifi_off_by_emergency); + netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state); + +#if !defined TIZEN_WEARABLE + netconfig_vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_PERMIT_WITH_LCD_OFF_LIMIT, &emergency_by_fmm); + DBG("emergency mode by Find My Mobile (%d)", emergency_by_fmm); + if (emergency_by_fmm == 1) + return; +#endif + + if (node != NULL) + emergency = vconf_keynode_get_int(node); + else + netconfig_vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &emergency); + + DBG("emergency mode %s", emergency > SETTING_PSMODE_POWERFUL ? "ON" : "OFF"); + DBG("Wi-Fi state %d, Wi-Fi was off by emergency mode %s", wifi_state, wifi_off_by_emergency ? "Yes" : "No"); + +#if defined TIZEN_WEARABLE + if (emergency == SETTING_PSMODE_WEARABLE) { + /* basic power saving mode on */ + } else if (emergency == SETTING_PSMODE_WEARABLE_ENHANCED) { + /* enhanced power saving mode on */ + if (wifi_state == VCONFKEY_WIFI_OFF) + return; + + wifi_power_off(); + netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 1); + } else { + /* power saving mode off */ + if (!wifi_off_by_emergency) return; - __netconfig_wifi_try_to_load_driver(); + netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 0); + if (wifi_state > VCONFKEY_WIFI_OFF) + return; + + wifi_power_on_wearable(TRUE); + } +#else + if (emergency > SETTING_PSMODE_POWERFUL) { + /* emergency mode on */ + if (wifi_state == VCONFKEY_WIFI_OFF) + return; + + wifi_power_off(); + + netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 1); + } else { + /* emergency mode off */ + if (!wifi_off_by_emergency) + return; + + netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 0); + + if (wifi_state > VCONFKEY_WIFI_OFF) + return; + + wifi_power_on(); + } +#endif - powered_off_by_flightmode = FALSE; - } else - DBG("Invalid value (%d)", value); } -static void __netconfig_wifi_pm_state_mode(keynode_t* node, - void* user_data) +void wifi_set_early_suspend(gboolean value) { - int value = -1; + static gboolean old_state = FALSE; + struct ifreq ifr; + char buf[MAX_DRV_CMD_SIZE]; + netconfig_wifi_priv_cmd priv_cmd; + int ret = 0; + int ioctl_sock = 0; + int pm_state = 0; + wifi_service_state_e wifi_state; + char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, }; + + if (old_state == value) { + DBG("Old and new states are same"); + return; + } + + if (netconfig_vconf_get_int(VCONFKEY_PM_STATE, &pm_state) < 0) + ERR("Fail to get VCONFKEY_PM_STATE"); + + wifi_state = wifi_state_get_service_state(); + + if (value == TRUE && + (pm_state < VCONFKEY_PM_STATE_LCDOFF || + wifi_state == NETCONFIG_WIFI_ASSOCIATION || + wifi_state == NETCONFIG_WIFI_CONFIGURATION)){ + DBG(""); + return; + } + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf), "SETSUSPENDMODE %d", value); + + memset(&ifr, 0, sizeof(struct ifreq)); + g_strlcpy((char *)ifr.ifr_name, WIFI_IFNAME, IFNAMSIZ); + + DBG("Early suspend command: [%s]", buf); + + memset(&priv_cmd, 0, sizeof(priv_cmd)); + priv_cmd.buf = buf; + priv_cmd.used_len = sizeof(buf); + priv_cmd.total_len = sizeof(buf); + ifr.ifr_data = (char *)&priv_cmd; + + ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); + if (ioctl_sock < 0) { + DBG("socket(PF_INET,SOCK_DGRAM) failed: %s", + strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER)); + return; + } + + ret = ioctl(ioctl_sock, WLAN_IOCTL_SUSPEND, &ifr); + if (ret < 0) { + ERR("Fail to issue private commands: %d. %s", ret, + strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER)); + } else { + old_state = value; + } + + close(ioctl_sock); +} + +static void __pm_state_changed_cb(keynode_t* node, void* user_data) +{ + int new_state = -1; int wifi_state = 0; static int prev_state = VCONFKEY_PM_STATE_NORMAL; - /*** vconf-keys.h *** - * VCONFKEY_PM_STATE_NORMAL = 1, - * VCONFKEY_PM_STATE_LCDDIM, - * VCONFKEY_PM_STATE_LCDOFF, - * VCONFKEY_PM_STATE_SLEEP + if (netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state) < 0) { + ERR("Fail to get VCONFKEY_WIFI_STATE"); + return; + } + + /* PM state + * VCONFKEY_PM_STATE_NORMAL = 1, + * VCONFKEY_PM_STATE_LCDDIM, + * VCONFKEY_PM_STATE_LCDOFF, + * VCONFKEY_PM_STATE_SLEEP */ + if (node != NULL) + new_state = vconf_keynode_get_int(node); + else + netconfig_vconf_get_int(VCONFKEY_PM_STATE, &new_state); - if(vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state) == 0) { - DBG("wifi state : %d (0 off / 1 on / 2 connected)", wifi_state); - if(wifi_state <= VCONFKEY_WIFI_OFF) - return; + DBG("wifi state: %d (0 off / 1 on / 2 connected)", wifi_state); + DBG("Old PM state: %d, current: %d (1 normal / 2 lcddim / 3 lcdoff / 4 sleep)", prev_state, new_state); + + if ((new_state == VCONFKEY_PM_STATE_NORMAL) && (prev_state >= VCONFKEY_PM_STATE_LCDOFF)) { + /* Send early suspend mode based on LCD state and disallow early suspend count */ + if (wifi_state != VCONFKEY_WIFI_OFF) { + wifi_set_early_suspend(FALSE); + DBG("Unset early suspend"); + } + + netconfig_wifi_bgscan_stop(); + netconfig_wifi_bgscan_set_interval(SCAN_EXPONENTIAL_MIN); + netconfig_wifi_bgscan_start(TRUE); + } else if ((new_state == VCONFKEY_PM_STATE_LCDOFF) && (prev_state < VCONFKEY_PM_STATE_LCDOFF) && (wifi_state != VCONFKEY_WIFI_OFF)) { + wifi_set_early_suspend(TRUE); + DBG("Set early suspend"); } - if(vconf_get_int(VCONFKEY_PM_STATE, &value) < 0) { - ERR("VCONFKEY_PM_STATE get failed"); + prev_state = new_state; +} + +static void __netconfig_telephony_ready_changed_cb(keynode_t * node, void *data) +{ + int telephony_ready = 0; + + if (node != NULL) + telephony_ready = vconf_keynode_get_bool(node); + else + netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_READY, &telephony_ready); + + if (telephony_ready != 0) { + if (netconfig_tapi_check_sim_state() == FALSE) { + DBG("Sim is not initialized yet."); + + goto done; + } + } else return; + + DBG("Turn Wi-Fi on automatically"); + +#if defined TIZEN_WEARABLE + wifi_power_on_wearable(TRUE); +#else + wifi_power_on(); +#endif + +done: + vconf_ignore_key_changed(VCONFKEY_TELEPHONY_READY, __netconfig_telephony_ready_changed_cb); +} + +int wifi_power_driver_and_supplicant(gboolean enable) +{ + /* There are 3 thumb rules for Wi-Fi power management + * 1. Do not make exposed API to control wpa_supplicant and driver directly. + * It probably breaks ConnMan technology operation. + * + * 2. Do not remove driver and wpa_supplicant if ConnMan already enabled. + * It breaks ConnMan technology operation. + * + * 3. Final the best rule: make it as simple as possible. + * Simple code enables easy maintenance and reduces logical errors. + */ + if (enable == TRUE) { + return _load_driver_and_supplicant(); + } else { + if (connman_wifi_technology_state == TRUE) + return -ENOSYS; + + return _remove_driver_and_supplicant(); } +} - DBG("Old state: %d, current: %d", prev_state, value); +void wifi_power_disable_technology_state_by_only_connman_signal(void) +{ + /* Important: it's only done by ConnMan technology signal update */ + connman_wifi_technology_state = FALSE; +} - if((value == VCONFKEY_PM_STATE_NORMAL) && (prev_state >= VCONFKEY_PM_STATE_LCDOFF)) { - DBG("PM state : Wake UP!"); +void wifi_power_recover_firmware(void) +{ + wifi_firmware_recovery_mode = TRUE; - netconfig_wifi_bgscan_stop(); - netconfig_wifi_bgscan_start(); + netconfig_wifi_bgscan_stop(); + + wifi_power_off(); +} + +int wifi_power_on(void) +{ + int err = 0; + wifi_tech_state_e tech_state; + + tech_state = wifi_state_get_technology_state(); + if (tech_state >= NETCONFIG_WIFI_TECH_POWERED) { + /* There can be a scenario where wifi is automatically * + * activated by connman if wifi was powered in last boot. * + * So we should update connman_wifi_technology_state variable * + * if it is found that wifi_tech_state variable is * + * NETCONFIG_WIFI_TECH_POWERED and connman_wifi_technology_state * + * variable is FALSE. Earlier connman_wifi_technology_state * + * variable was only updated when wifi was Powered on from * + * net-config resulting in variable not getting updated. * + * This caused wifi to not get deactivated after reboot if * + * last power state was activated */ + ERR("Net-Config WiFi connman technology state %d", + connman_wifi_technology_state); + if (connman_wifi_technology_state == FALSE) + connman_wifi_technology_state = TRUE; + return -EALREADY; } - prev_state = value; + if (__is_wifi_restricted() == TRUE) + return -EPERM; + + if (netconfig_is_wifi_tethering_on() == TRUE) { + /* TODO: Wi-Fi tethering turns off here */ + /* return TRUE; */ + ERR("Failed to turn tethering off"); + return -EBUSY; + } + + err = wifi_power_driver_and_supplicant(TRUE); + if (err < 0 && err != -EALREADY) + return err; + + err = _set_connman_technology_power(TRUE); + + return err; } -void netconfig_set_power_in_progress(gboolean in_progress) +int wifi_power_off(void) { - power_in_progress = in_progress; + int err; + + err = _set_connman_technology_power(FALSE); + if (err == -EALREADY) + wifi_state_update_power_state(FALSE); + + return 0; } -void netconfig_check_fm_waiting(void) +#if defined TIZEN_WEARABLE +int wifi_power_on_wearable(gboolean device_picker_test) { - if (fm_waiting) - __netconfig_wifi_airplane_mode(NULL, NULL); + int err = 0; + wifi_tech_state_e tech_state; + + tech_state = wifi_state_get_technology_state(); + if (tech_state >= NETCONFIG_WIFI_TECH_POWERED) + return -EALREADY; + + err = wifi_power_driver_and_supplicant(TRUE); + if (err < 0 && err != -EALREADY) + return err; + + err = _set_connman_technology_power(TRUE); + + if (device_picker_test == TRUE) + netconfig_wifi_enable_device_picker_test(); + + return err; } +#endif -void netconfig_wifi_power_configuration(void) +void wifi_power_initialize(void) { int wifi_last_power_state = 0; + /* Initialize Airplane mode */ + netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &airplane_mode); + DBG("Airplane[%s]", airplane_mode > 0 ? "ON" : "OFF"); + + /* Update the last Wi-Fi power state */ + netconfig_vconf_get_int(VCONF_WIFI_LAST_POWER_STATE, &wifi_last_power_state); + if (wifi_last_power_state > VCONFKEY_WIFI_OFF) { + if (TIZEN_TELEPHONY_ENABLE) { + int telephony_ready = 0; + netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_READY, &telephony_ready); + if (telephony_ready == 0) { + DBG("Telephony API is not initialized yet"); + vconf_notify_key_changed(VCONFKEY_TELEPHONY_READY, + __netconfig_telephony_ready_changed_cb, NULL); + } else { + if (netconfig_tapi_check_sim_state() == FALSE) + DBG("SIM is not initialized yet"); + } + } + DBG("Turn Wi-Fi on automatically"); +#if defined TIZEN_WEARABLE + wifi_power_on_wearable(TRUE); +#else + wifi_power_on(); +#endif + } + +#if defined TIZEN_WEARABLE vconf_notify_key_changed(VCONFKEY_TELEPHONY_FLIGHT_MODE, __netconfig_wifi_airplane_mode, NULL); +#else + vconf_notify_key_changed(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE, + __netconfig_wifi_restrict_mode, NULL); + vconf_notify_key_changed(VCONFKEY_TELEPHONY_FLIGHT_MODE, + __netconfig_wifi_airplane_mode, NULL); +#endif - vconf_notify_key_changed(VCONFKEY_PM_STATE, - __netconfig_wifi_pm_state_mode, NULL); - - vconf_get_int(VCONF_WIFI_LAST_POWER_STATE, &wifi_last_power_state); - - if (wifi_last_power_state == WIFI_POWER_ON) { - DBG("Turn Wi-Fi on automatically"); + vconf_notify_key_changed(VCONFKEY_SETAPPL_PSMODE, __emergency_mode_changed_cb, NULL); + vconf_notify_key_changed(VCONFKEY_PM_STATE, __pm_state_changed_cb, NULL); +} - __netconfig_wifi_try_to_load_driver(); - } +void wifi_power_deinitialize(void) +{ } -gboolean netconfig_iface_wifi_load_driver(NetconfigWifi *wifi, GError **error) +gboolean handle_load_driver(Wifi *wifi, + GDBusMethodInvocation *context, gboolean device_picker_test) { + int err; + DBG("Wi-Fi power on requested"); - g_return_val_if_fail(wifi != NULL, FALSE); + g_return_val_if_fail(wifi != NULL, TRUE); - int err; + if (!netconfig_dpm_update_from_wifi()) { + DBG("DPM policy restricts Wi-Fi"); + netconfig_error_permission_denied(context); + return TRUE; + } - if (netconfig_is_wifi_allowed() != TRUE) { - netconfig_error_security_restricted(error); + if (TIZEN_WLAN_BOARD_SPRD) + wifi_firmware_download(); - return FALSE; - } +#if defined TIZEN_WEARABLE + err = wifi_power_on_wearable(device_picker_test); +#else + err = wifi_power_on(); - if (power_in_progress) { - netconfig_error_wifi_driver_failed(error); - return FALSE; + if (device_picker_test == TRUE) + netconfig_wifi_enable_device_picker_test(); +#endif + if (err < 0) { + if (err == -EALREADY) + netconfig_error_already_exists(context); + else if (err == -EPERM) + netconfig_error_permission_denied(context); + else + netconfig_error_wifi_driver_failed(context); + + return TRUE; } - err = __netconfig_wifi_try_to_load_driver(); + + netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0); + __netconfig_set_wifi_bssid(); + + wifi_complete_load_driver(wifi, context); + return TRUE; +} + +gboolean handle_remove_driver(Wifi *wifi, GDBusMethodInvocation *context) +{ + int err; + + DBG("Wi-Fi power off requested"); + + g_return_val_if_fail(wifi != NULL, TRUE); + + err = wifi_power_off(); if (err < 0) { if (err == -EINPROGRESS) - netconfig_error_wifi_load_inprogress(error); + netconfig_error_inprogress(context); + else if (err == -EALREADY) + netconfig_error_already_exists(context); + else if (err == -EPERM) + netconfig_error_permission_denied(context); else - netconfig_error_wifi_driver_failed(error); - - return FALSE; + netconfig_error_wifi_driver_failed(context); + return TRUE; } + netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0); + + wifi_complete_remove_driver(wifi, context); return TRUE; } -gboolean netconfig_iface_wifi_remove_driver(NetconfigWifi *wifi, GError **error) +gboolean handle_load_p2p_driver(Wifi *wifi, GDBusMethodInvocation *context) { - DBG("Wi-Fi power off requested"); + ERR("Deprecated"); - g_return_val_if_fail(wifi != NULL, FALSE); + wifi_complete_load_p2p_driver(wifi, context); + return TRUE; +} - if (power_in_progress) { - netconfig_error_wifi_driver_failed(error); - return FALSE; +gboolean handle_remove_p2p_driver(Wifi *wifi, GDBusMethodInvocation *context) +{ + ERR("Deprecated"); + + wifi_complete_remove_p2p_driver(wifi, context); + return TRUE; +} + +static int __netconfig_get_random_mac(unsigned char *mac_buf, int mac_len) +{ + DBG("Generate Random Mac address of ethernet"); + FILE *fp; + int rc; + + fp = fopen(OS_RANDOM_FILE, "rb"); + + if (fp == NULL) { + ERR("Could not open /dev/urandom"); + return -1; } + rc = fread(mac_buf, 1, mac_len, fp); + if (fp) + fclose(fp); - if (__netconfig_wifi_try_to_remove_driver() != TRUE) { - netconfig_error_wifi_driver_failed(error); + return rc != mac_len ? -1 : 0; +} - return FALSE; +void __netconfig_set_ether_macaddr() +{ + DBG("Set wired Mac address "); + char *mac_addr = NULL; + char rand_addr[WLAN_MAC_ADDR_MAX]; + int rv = -1; + + mac_addr = vconf_get_str(VCONF_ETH_MAC_ADDRESS); + if (mac_addr == NULL) { + DBG("vconf_get_str Failed\n"); + return; } + /* Checking Invalid MAC Address */ + if ((strlen(mac_addr) == 0)) { + ERR("Failed to get valid MAC Address from vconf"); + /*Generate the Random Mac address*/ + unsigned char rand_mac_add[ETH_MAC_ADDR_SIZE+1]; + + if (__netconfig_get_random_mac(rand_mac_add, ETH_MAC_ADDR_SIZE) == -1) { + + ERR("Could not generate the Random Mac address"); + free(mac_addr); + return; + } + + rand_mac_add[0] &= 0xFE; /*Clear multicase bit*/ + rand_mac_add[0] |= 0x02; /*set local assignment bit*/ + + /*Set the Mac address in Vconf*/ + snprintf(rand_addr, WLAN_MAC_ADDR_MAX, "%x:%x:%x:%x:%x:%x", + rand_mac_add[0], rand_mac_add[1], + rand_mac_add[2], rand_mac_add[3], + rand_mac_add[4], rand_mac_add[5]); + + netconfig_set_vconf_str(VCONF_ETH_MAC_ADDRESS, rand_addr); + } else { /* Valid MAC address */ + g_strlcpy(rand_addr, mac_addr, WLAN_MAC_ADDR_MAX); + } + + DBG("MAC Address of eth0 [%s]", rand_addr); + const char *path = NET_EXEC_PATH; + char *const args[] = { "/sbin/ifconfig", "eth0", "hw", + "ether", rand_addr, "up", NULL}; + char *const envs[] = { NULL }; + rv = netconfig_execute_file(path, args, envs); + + if (rv < 0) + ERR("Unable to execute system command"); + free(mac_addr); - return TRUE; }