[net-config] Suspend/Resume WLAN driver
[platform/core/connectivity/net-config.git] / src / wifi-power.c
index 477c089..c900012 100755 (executable)
@@ -24,6 +24,8 @@
 #include <stdlib.h>
 #include <glib.h>
 #include <tzplatform_config.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
 
 #include "log.h"
 #include "util.h"
@@ -46,9 +48,6 @@
 #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 VCONF_WIFI_WEARABLE_WIFI_USE                   "db/private/wifi/wearable_wifi_use"
-#endif
 #if !defined TIZEN_WEARABLE
 #define VCONFKEY_SETAPPL_NETWORK_PERMIT_WITH_LCD_OFF_LIMIT     "db/setting/network_with_lcd_off_limit"
 #endif
 
 #define NETCONFIG_TECH_WAITING_INTERVAL 500
 #define NETCONFIG_TECH_WAITING_COUNT 6
+#define MAX_DRV_CMD_SIZE 248
+#define WLAN_IOCTL_SUSPEND (SIOCDEVPRIVATE + 1)
 
 static gboolean connman_wifi_technology_state = FALSE;
 static gboolean wifi_firmware_recovery_mode = FALSE;
 static int airplane_mode = 0;
 
-#if defined TIZEN_WEARABLE
-static int psmode_wifi_use = 1;
-#endif
+typedef struct {
+       char *buf;
+       int used_len;
+       int total_len;
+} netconfig_wifi_priv_cmd;
 
 static gboolean __is_wifi_restricted(void)
 {
@@ -221,7 +224,6 @@ static gboolean __check_and_set_technology_enable(gpointer data)
        static int retry_count = NETCONFIG_TECH_WAITING_COUNT;
        gboolean value_enable = TRUE;
        gboolean reply = FALSE;
-       GVariant *param0 = NULL;
        GVariant *params = NULL;
        char key[] = "Powered";
 
@@ -231,8 +233,7 @@ static gboolean __check_and_set_technology_enable(gpointer data)
                        return TRUE;
        }
 
-       param0 = g_variant_new_boolean(value_enable);
-       params = g_variant_new("(sv)", key, param0);
+       params = g_variant_new("(sv)", key, g_variant_new_boolean(value_enable));
 
        reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
                                        CONNMAN_WIFI_TECHNOLOGY_PREFIX,
@@ -254,7 +255,6 @@ static gboolean __check_and_set_technology_enable(gpointer data)
 static int _set_connman_technology_power(gboolean enable)
 {
        gboolean reply = FALSE;
-       GVariant *param0 = NULL;
        GVariant *params = NULL;
        char key[] = "Powered";
        gboolean value_enable = TRUE;
@@ -270,12 +270,8 @@ static int _set_connman_technology_power(gboolean enable)
                return 0;
        }
 
-       if (enable == TRUE)
-               param0 = g_variant_new_boolean(value_enable);
-       else
-               param0 = g_variant_new_boolean(value_disable);
-
-       params = g_variant_new("(sv)", key, param0);
+       params = g_variant_new("(sv)", key, (enable == TRUE) ?
+               g_variant_new_boolean(value_enable) : g_variant_new_boolean(value_disable));
 
        reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
                                        CONNMAN_WIFI_TECHNOLOGY_PREFIX, CONNMAN_TECHNOLOGY_INTERFACE,
@@ -332,26 +328,15 @@ void netconfig_wifi_disable_technology_state_by_only_connman_signal(void)
 int netconfig_wifi_on_wearable(gboolean device_picker_test)
 {
        int err = 0;
-       int wifi_use;
        int ps_mode;
 
-       if (netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use) < 0) {
-               ERR("Fail to get VCONF_WIFI_WEARABLE_WIFI_USE");
+       if (netconfig_vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &ps_mode) < 0) {
+               ERR("Fail to get VCONFKEY_SETAPPL_PSMODE");
                return -EIO;
        }
 
-       if (wifi_use > 0) {
-               if (netconfig_vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &ps_mode) < 0) {
-                       ERR("Fail to get VCONFKEY_SETAPPL_PSMODE");
-                       return -EIO;
-               }
-
-               if (ps_mode > SETTING_PSMODE_NORMAL) {
-                       WARN("ps mode is on(%d), Not turn on Wi-Fi", ps_mode);
-                       return -EPERM;
-               }
-       } else {
-               WARN("Not permitted Wi-Fi on");
+       if (ps_mode > SETTING_PSMODE_NORMAL) {
+               WARN("ps mode is on(%d), Not turn on Wi-Fi", ps_mode);
                return -EPERM;
        }
 
@@ -366,39 +351,6 @@ int netconfig_wifi_on_wearable(gboolean device_picker_test)
 
        return err;
 }
-
-static void __wearable_wifi_use_changed_cb(keynode_t* node, void* user_data)
-{
-       int wifi_state;
-       int wifi_use = 1;
-
-       if (netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state) < 0) {
-               ERR("Fail to get VCONFKEY_WIFI_STATE");
-               return;
-       }
-
-       if (node != NULL)
-               wifi_use = vconf_keynode_get_int(node);
-       else
-               netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use);
-
-       if (wifi_use > 0) {
-               DBG("wifi use on");
-               if (wifi_state > VCONFKEY_WIFI_OFF) {
-                       WARN("Wi-Fi is already turned on");
-                       return;
-               }
-               wifi_power_on_wearable(TRUE);
-       } else {
-               ERR("## wifi use [OFF]");
-               if (wifi_state == VCONFKEY_WIFI_OFF) {
-                       WARN("Wi-Fi is already turned off");
-                       return;
-               }
-
-               wifi_power_off();
-       }
-}
 #else
 static void __netconfig_wifi_restrict_mode(keynode_t *node, void *user_data)
 {
@@ -447,12 +399,7 @@ static void __netconfig_wifi_airplane_mode(keynode_t *node, void *user_data)
        int wifi_off_by_airplane = 0;
 
        netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, &wifi_off_by_airplane);
-
-#if defined TIZEN_WEARABLE
-       netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_state)
-#else
        netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
-#endif
 
        if (node != NULL)
                airplane_state = vconf_keynode_get_bool(node);
@@ -476,23 +423,16 @@ static void __netconfig_wifi_airplane_mode(keynode_t *node, void *user_data)
                wifi_power_off();
 
                netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 1);
-#if defined TIZEN_WEARABLE
-               netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, 0);
-#endif
        } else {
                /* airplane mode off */
                if (!wifi_off_by_airplane)
                        return;
 
                netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
-#if defined TIZEN_WEARABLE
-               netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, 1);
-#else
                if (wifi_state > VCONFKEY_WIFI_OFF)
                        return;
 
                wifi_power_on();
-#endif
        }
 }
 
@@ -503,10 +443,6 @@ static void __emergency_mode_changed_cb(keynode_t *node, void *user_data)
 #if !defined TIZEN_WEARABLE
        int emergency_by_fmm = 0;
 #endif
-#if defined TIZEN_WEARABLE
-       int wifi_use = 1;
-#endif
-
        netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, &wifi_off_by_emergency);
        netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
 
@@ -530,11 +466,6 @@ static void __emergency_mode_changed_cb(keynode_t *node, void *user_data)
                /* basic power saving mode on */
        } else if (emergency == SETTING_PSMODE_WEARABLE_ENHANCED) {
                /* enhanced power saving mode on */
-               netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use);
-               psmode_wifi_use = wifi_use;
-               if (wifi_use != 0)
-                       netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, 0);
-
                if (wifi_state == VCONFKEY_WIFI_OFF)
                        return;
 
@@ -542,7 +473,6 @@ static void __emergency_mode_changed_cb(keynode_t *node, void *user_data)
                netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 1);
        } else {
                /* power saving mode off */
-               netconfig_set_vconf_int(VCONF_WIFI_WEARABLE_WIFI_USE, psmode_wifi_use);
                if (!wifi_off_by_emergency)
                        return;
 
@@ -577,6 +507,66 @@ static void __emergency_mode_changed_cb(keynode_t *node, void *user_data)
 
 }
 
+void wifi_set_early_suspend(gboolean value)
+{
+       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;
+
+       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");
+               return;
+       }
+
+       ret = ioctl(ioctl_sock, WLAN_IOCTL_SUSPEND, &ifr);
+
+       if (ret < 0)
+               ERR("Fail to issue private commands: %d. %s", ret, strerror(errno));
+       else {
+               old_state = value;
+       }
+
+       close(ioctl_sock);
+}
+
 static void __pm_state_changed_cb(keynode_t* node, void* user_data)
 {
        int new_state = -1;
@@ -603,9 +593,18 @@ static void __pm_state_changed_cb(keynode_t* node, void* user_data)
        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");
        }
 
        prev_state = new_state;
@@ -736,23 +735,12 @@ int wifi_power_off(void)
 int wifi_power_on_wearable(gboolean device_picker_test)
 {
        int err = 0;
-       int wifi_use = 1;
        wifi_tech_state_e tech_state;
 
        tech_state = wifi_state_get_technology_state();
        if (tech_state >= NETCONFIG_WIFI_TECH_POWERED)
                return -EALREADY;
 
-       if (netconfig_vconf_get_int(VCONF_WIFI_WEARABLE_WIFI_USE, &wifi_use) < 0) {
-               ERR("Fail to get VCONF_WIFI_WEARABLE_WIFI_USE");
-               return -EIO;
-       }
-
-       if (wifi_use == 0) {
-               WARN("VCONF_WIFI_WEARABLE_WIFI_USE is OFF");
-               return -EPERM;
-       }
-
        err = wifi_power_driver_and_supplicant(TRUE);
        if (err < 0 && err != -EALREADY)
                return err;
@@ -798,8 +786,6 @@ void wifi_power_initialize(void)
        }
 
 #if defined TIZEN_WEARABLE
-       vconf_notify_key_changed(VCONF_WIFI_WEARABLE_WIFI_USE, __wearable_wifi_use_changed_cb, NULL);
-
        vconf_notify_key_changed(VCONFKEY_TELEPHONY_FLIGHT_MODE,
                        __netconfig_wifi_airplane_mode, NULL);
 #else
@@ -824,7 +810,7 @@ gboolean handle_load_driver(Wifi *wifi,
 
        DBG("Wi-Fi power on requested");
 
-       g_return_val_if_fail(wifi != NULL, FALSE);
+       g_return_val_if_fail(wifi != NULL, TRUE);
 
        if (!netconfig_dpm_update_from_wifi()) {
                DBG("DPM policy restricts Wi-Fi");
@@ -844,9 +830,7 @@ gboolean handle_load_driver(Wifi *wifi,
                netconfig_wifi_enable_device_picker_test();
 #endif
        if (err < 0) {
-               if (err == -EINPROGRESS)
-                       netconfig_error_inprogress(context);
-               else if (err == -EALREADY)
+               if (err == -EALREADY)
                        netconfig_error_already_exists(context);
                else if (err == -EPERM)
                        netconfig_error_permission_denied(context);
@@ -870,7 +854,7 @@ gboolean handle_remove_driver(Wifi *wifi, GDBusMethodInvocation *context)
 
        DBG("Wi-Fi power off requested");
 
-       g_return_val_if_fail(wifi != NULL, FALSE);
+       g_return_val_if_fail(wifi != NULL, TRUE);
 
        err = wifi_power_off();
        if (err < 0) {