Fix some svace issues for memory leak and checking return value
[platform/core/connectivity/net-config.git] / src / wifi-power.c
index 72b8673..947716f 100755 (executable)
 #include <stdlib.h>
 #include <glib.h>
 #include <tzplatform_config.h>
-
-#if defined TIZEN_P2P_ENABLE && !defined WLAN_CONCURRENT_MODE
-#include <wifi-direct.h>
-#endif
+#include <net/if.h>
+#include <sys/ioctl.h>
 
 #include "log.h"
 #include "util.h"
 #include "netdbus.h"
 #include "neterror.h"
 #include "wifi-wps.h"
+#include "wifi-bssid-scan.h"
 #include "wifi-power.h"
 #include "wifi-state.h"
 #include "netsupplicant.h"
 #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 WLAN_MAC_INFO              tzplatform_mkpath(TZ_SYS_ETC, "/.mac.info")
 #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"
 #define NET_EXEC_PATH "/sbin/ifconfig"
 #define OS_RANDOM_FILE "/dev/urandom"
 
+#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)
 {
@@ -118,9 +120,9 @@ static void __technology_reply(GObject *source_object, GAsyncResult *res, gpoint
                }
        } else {
                DBG("Successfully requested");
+               g_variant_unref(reply);
        }
 
-       g_variant_unref(reply);
        netconfig_gdbus_pending_call_unref();
 }
 
@@ -150,28 +152,6 @@ static int __execute_supplicant(gboolean enable)
        return 0;
 }
 
-#if defined TIZEN_P2P_ENABLE && defined WLAN_CONCURRENT_MODE
-static int __netconfig_p2p_supplicant(gboolean enable)
-{
-       int rv = 0;
-       const char *path = P2P_SUPPLICANT_SCRIPT;
-       char *const args_enable[] = { P2P_SUPPLICANT_SCRIPT, "start", NULL };
-       char *const args_disable[] = { P2P_SUPPLICANT_SCRIPT, "stop", NULL };
-       char *const envs[] = { NULL };
-
-       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("p2p_supplicant %s", enable == TRUE ? "started" : "stopped");
-
-       return 0;
-}
-#endif
-
 void netconfig_wifi_recover_firmware(void)
 {
        wifi_firmware_recovery_mode = TRUE;
@@ -181,42 +161,6 @@ void netconfig_wifi_recover_firmware(void)
        wifi_power_off();
 }
 
-#if defined TIZEN_P2P_ENABLE && !defined WLAN_CONCURRENT_MODE
-static void __netconfig_wifi_direct_state_cb(int error_code, wifi_direct_device_state_e device_state, void *user_data)
-{
-       int err;
-
-       wifi_direct_unset_device_state_changed_cb();
-       wifi_direct_deinitialize();
-
-       if (device_state == WIFI_DIRECT_DEVICE_STATE_DEACTIVATED) {
-               err = wifi_power_on();
-               if (err < 0) {
-                       if (err == -EALREADY)
-                               wifi_state_update_power_state(TRUE);
-                       else
-                               wifi_state_emit_power_failed();
-               }
-       }
-}
-
-static gboolean __netconfig_wifi_direct_power_off(void)
-{
-       DBG("Wi-Fi direct is turning off");
-
-       if (wifi_direct_initialize() < 0)
-               return FALSE;
-
-       if (wifi_direct_set_device_state_changed_cb(__netconfig_wifi_direct_state_cb, NULL) < 0)
-               return FALSE;
-
-       if (wifi_direct_deactivate() < 0)
-               return FALSE;
-
-       return TRUE;
-}
-#endif
-
 static int _load_driver_and_supplicant(void)
 {
        int err = 0;
@@ -245,9 +189,9 @@ static int _remove_driver_and_supplicant(void)
 {
        int err = 0;
 
-       INFO("remove driver and supplicant");
+       DBG("remove driver and supplicant");
        if (wifi_firmware_recovery_mode != TRUE &&
-                                       netconfig_wifi_is_wps_enabled() == TRUE) {
+                                       netconfig_wifi_is_bssid_scan_started() == TRUE) {
                DBG("Wi-Fi WPS mode");
                return 0;
        }
@@ -275,10 +219,42 @@ static int _remove_driver_and_supplicant(void)
        return 0;
 }
 
+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 *params = NULL;
+       char key[] = "Powered";
+
+       if (wifi_state_is_technology_available() == FALSE) {
+               retry_count--;
+               if (retry_count > 0)
+                       return TRUE;
+       }
+
+       params = g_variant_new("(sv)", key, g_variant_new_boolean(value_enable));
+
+       reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
+                                       CONNMAN_WIFI_TECHNOLOGY_PREFIX,
+                                       CONNMAN_TECHNOLOGY_INTERFACE,
+                                       "SetProperty", params, __technology_reply);
+
+       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 int _set_connman_technology_power(gboolean enable)
 {
        gboolean reply = FALSE;
-       GVariant *param0 = NULL;
        GVariant *params = NULL;
        char key[] = "Powered";
        gboolean value_enable = TRUE;
@@ -287,12 +263,15 @@ static int _set_connman_technology_power(gboolean enable)
        if (connman_wifi_technology_state == enable)
                return -EALREADY;
 
-       if (enable == TRUE)
-               param0 = g_variant_new_boolean(value_enable);
-       else
-               param0 = g_variant_new_boolean(value_disable);
+       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;
+       }
 
-       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,
@@ -321,22 +300,26 @@ static void __netconfig_set_wifi_bssid(void)
        int rv = 0;
        char bssid[WLAN_MAC_ADDR_MAX];
 
-       FILE *fp = fopen(WLAN_MAC_INFO, "r");
+       FILE *fp = fopen(WLAN_MAC_ADDRESS_FILEPATH, "r");
 
        if (fp == NULL) {
-               ERR("Fail to open %s", WLAN_MAC_INFO);
-               fp = fopen(WLAN_MAC_ADDRESS_FILEPATH, "r");
-               if (fp == NULL) {
-                       ERR("Fail to open %s", WLAN_MAC_ADDRESS_FILEPATH);
-                       return;
-               }
+               ERR("Fail to open %s", WLAN_MAC_ADDRESS_FILEPATH);
+               return;
        }
 
-       fseek(fp, 0L, SEEK_SET);
-       rv = fscanf(fp, "%17s", bssid);
+       rv = fseek(fp, 0L, SEEK_SET);
+       if (rv != 0) {
+               ERR("Fail to seek file");
+               fclose(fp);
+               return;
+       }
 
-       if (rv < 0)
+       rv = fscanf(fp, "%17s", bssid);
+       if (rv < 0) {
                ERR("Fail to read bssid");
+               fclose(fp);
+               return;
+       }
 
        netconfig_set_vconf_str(VCONF_WIFI_BSSID_ADDRESS, bssid);
 
@@ -353,26 +336,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;
        }
 
@@ -387,39 +359,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)
 {
@@ -468,12 +407,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);
@@ -497,23 +431,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
        }
 }
 
@@ -524,10 +451,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);
 
@@ -551,11 +474,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;
 
@@ -563,7 +481,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;
 
@@ -598,6 +515,68 @@ 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;
+       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;
@@ -621,11 +600,21 @@ static void __pm_state_changed_cb(keynode_t* node, void* user_data)
                netconfig_vconf_get_int(VCONFKEY_PM_STATE, &new_state);
 
        DBG("wifi state: %d (0 off / 1 on / 2 connected)", wifi_state);
-       DBG("Old PM state: %d, current: %d", prev_state, new_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");
        }
 
        prev_state = new_state;
@@ -732,17 +721,6 @@ int wifi_power_on(void)
                return -EBUSY;
        }
 
-#if defined TIZEN_P2P_ENABLE && !defined WLAN_CONCURRENT_MODE
-       if (netconfig_is_wifi_direct_on() == TRUE) {
-               if (__netconfig_wifi_direct_power_off() == TRUE)
-                       return -EINPROGRESS;
-               else {
-                       ERR("Failed to turn Wi-Fi direct off");
-                       return -EBUSY;
-               }
-       }
-#endif
-
        err = wifi_power_driver_and_supplicant(TRUE);
        if (err < 0 && err != -EALREADY)
                return err;
@@ -767,23 +745,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;
@@ -829,8 +796,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
@@ -855,7 +820,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");
@@ -875,9 +840,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);
@@ -901,7 +864,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) {