Merge "Maintain list for active wifi interfaces" into tizen
[platform/core/connectivity/net-config.git] / src / wifi-power.c
index 2ab8f4b..1d3368b 100755 (executable)
 #include <stdlib.h>
 #include <glib.h>
 #include <tzplatform_config.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
 
 #include "log.h"
 #include "util.h"
+#include "setting.h"
 #include "netdbus.h"
 #include "neterror.h"
 #include "wifi-wps.h"
+#include "wifi-scan.h"
 #include "wifi-bssid-scan.h"
 #include "wifi-power.h"
 #include "wifi-state.h"
 #include "wifi-firmware.h"
 #include "wifi-background-scan.h"
 
-
 #define WLAN_SUPPLICANT_SCRIPT         "/usr/bin/wpa_supp.sh"
 #define P2P_SUPPLICANT_SCRIPT          "/usr/bin/p2p_supp.sh"
 
 #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_ADDRESS_FILEPATH   "/sys/class/net/wlan0/address"
-#define WLAN_MAC_ADDR_MAX          20
-#define VCONF_WIFI_BSSID_ADDRESS       "db/wifi/bssid_address"
-
+#define WLAN_MAC_ADDR_MAX 20
 #define ETH_MAC_ADDR_SIZE 6
 #define VCONF_ETH_MAC_ADDRESS  "db/dnet/mac_address"
 #define NET_EXEC_PATH "/sbin/ifconfig"
 
 #define NETCONFIG_TECH_WAITING_INTERVAL 500
 #define NETCONFIG_TECH_WAITING_COUNT 6
+#define MAX_DRV_CMD_SIZE 248
+#define WLAN_IOCTL_SUSPEND (SIOCDEVPRIVATE + 1)
+
+typedef struct {
+       char *buf;
+       int used_len;
+       int total_len;
+} netconfig_wifi_priv_cmd;
 
-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
-
 static gboolean __is_wifi_restricted(void)
 {
 #if defined TIZEN_WEARABLE
@@ -94,6 +94,7 @@ static void __technology_reply(GObject *source_object, GAsyncResult *res, gpoint
        GVariant *reply;
        GDBusConnection *conn = NULL;
        GError *error = NULL;
+       char *interface_name = user_data;
 
        conn = G_DBUS_CONNECTION(source_object);
        reply = g_dbus_connection_call_finish(conn, res, &error);
@@ -102,18 +103,18 @@ static void __technology_reply(GObject *source_object, GAsyncResult *res, gpoint
                if (error != NULL) {
                        if (g_strstr_len(error->message, strlen(error->message),
                                        CONNMAN_ERROR_INTERFACE ".AlreadyEnabled") != NULL) {
-                               wifi_state_update_power_state(TRUE);
+                               wifi_state_update_power_state(interface_name, TRUE);
                        } else if (g_strstr_len(error->message, strlen(error->message),
                                        CONNMAN_ERROR_INTERFACE ".AlreadyDisabled") != NULL) {
-                               wifi_state_update_power_state(FALSE);
+                               wifi_state_update_power_state(interface_name, FALSE);
                        } else {
                                ERR("Fail to request status [%d: %s]", error->code, error->message);
-                               wifi_state_update_power_state(FALSE);
+                               wifi_state_update_power_state(interface_name, FALSE);
                        }
                        g_error_free(error);
                } else {
                        ERR("Fail to request status");
-                       wifi_state_update_power_state(FALSE);
+                       wifi_state_update_power_state(interface_name, FALSE);
                }
        } else {
                DBG("Successfully requested");
@@ -121,14 +122,21 @@ static void __technology_reply(GObject *source_object, GAsyncResult *res, gpoint
        }
 
        netconfig_gdbus_pending_call_unref();
+       g_free(interface_name);
 }
 
-static int __execute_supplicant(gboolean enable)
+int __execute_supplicant(gboolean enable)
 {
+       /*
+        * TODO: [EAP on Ethernet] Temporary blocked wpa_supp.sh stop
+        * untill ConnMan adds logic to trigger/control wpa_supplicant interface.
+        */
        int rv = 0;
        const char *path = WLAN_SUPPLICANT_SCRIPT;
        char *const args_enable[] = { "/usr/bin/wpa_supp.sh", "start", NULL };
+#if 0
        char *const args_disable[] = { "/usr/bin/wpa_supp.sh", "stop", NULL };
+#endif
        char *const envs[] = { NULL };
        static gboolean enabled = FALSE;
 
@@ -137,33 +145,27 @@ static int __execute_supplicant(gboolean enable)
 
        if (enable == TRUE)
                rv = netconfig_execute_file(path, args_enable, envs);
+#if 0
        else
                rv = netconfig_execute_file(path, args_disable, envs);
+#endif
        if (rv < 0)
                return -EIO;
 
        DBG("wpa_supplicant %s", enable == TRUE ? "started" : "stopped");
 
-       enabled = enable;
+       if (enable)
+               enabled = enable;
 
        return 0;
 }
 
-void netconfig_wifi_recover_firmware(void)
-{
-       wifi_firmware_recovery_mode = TRUE;
-
-       netconfig_wifi_bgscan_stop();
-
-       wifi_power_off();
-}
-
-static int _load_driver_and_supplicant(void)
+static int _load_driver_and_supplicant(const char *interface_name)
 {
        int err = 0;
        wifi_tech_state_e tech_state;
 
-       tech_state = wifi_state_get_technology_state();
+       tech_state = wifi_state_get_technology_state(interface_name);
        if (tech_state > NETCONFIG_WIFI_TECH_OFF)
                return -EALREADY;
 
@@ -171,29 +173,29 @@ static int _load_driver_and_supplicant(void)
        if (err < 0 && err != -EALREADY)
                return err;
 
-       err = netconfig_wifi_firmware(NETCONFIG_WIFI_STA, TRUE);
+       err = netconfig_wifi_firmware(NETCONFIG_WIFI_STA, interface_name, TRUE);
        if (err < 0 && err != -EALREADY) {
                __execute_supplicant(FALSE);
                return err;
        }
 
-       wifi_state_set_tech_state(NETCONFIG_WIFI_TECH_WPS_ONLY);
+       wifi_state_set_technology_state(interface_name, NETCONFIG_WIFI_TECH_WPS_ONLY);
 
        return 0;
 }
 
-static int _remove_driver_and_supplicant(void)
+static int _remove_driver_and_supplicant(const char *interface_name)
 {
        int err = 0;
 
        DBG("remove driver and supplicant");
        if (wifi_firmware_recovery_mode != TRUE &&
-                                       netconfig_wifi_is_bssid_scan_started() == TRUE) {
+               netconfig_wifi_bssidscan_get_mode(interface_name) == TRUE) {
                DBG("Wi-Fi WPS mode");
                return 0;
        }
 
-       err = netconfig_wifi_firmware(NETCONFIG_WIFI_STA, FALSE);
+       err = netconfig_wifi_firmware(NETCONFIG_WIFI_STA, interface_name, FALSE);
        if (err < 0 && err != -EALREADY)
                return err;
 
@@ -201,13 +203,13 @@ static int _remove_driver_and_supplicant(void)
        if (err < 0 && err != -EALREADY)
                return err;
 
-       wifi_state_set_tech_state(NETCONFIG_WIFI_TECH_OFF);
+       wifi_state_set_technology_state(interface_name, NETCONFIG_WIFI_TECH_OFF);
 
        // reset service state
-       wifi_state_set_service_state(NETCONFIG_WIFI_IDLE);
+       wifi_state_set_service_state(interface_name, NULL, NETCONFIG_WIFI_IDLE);
 
        if (wifi_firmware_recovery_mode == TRUE) {
-               if (wifi_power_on() < 0)
+               if (wifi_power_on(interface_name) < 0)
                        ERR("Failed to recover Wi-Fi firmware");
 
                wifi_firmware_recovery_mode = FALSE;
@@ -219,193 +221,92 @@ static int _remove_driver_and_supplicant(void)
 static gboolean __check_and_set_technology_enable(gpointer data)
 {
        static int retry_count = NETCONFIG_TECH_WAITING_COUNT;
+       wifi_tech_state_e tech_state = NETCONFIG_WIFI_TECH_UNKNOWN;
        gboolean value_enable = TRUE;
        gboolean reply = FALSE;
-       GVariant *param0 = NULL;
        GVariant *params = NULL;
-       char key[] = "Powered";
+       char *interface_name = data;
 
-       if (wifi_state_is_technology_available() == FALSE) {
+       tech_state = wifi_state_get_technology_state(interface_name);
+       if (tech_state == NETCONFIG_WIFI_TECH_UNKNOWN) {
                retry_count--;
                if (retry_count > 0)
                        return TRUE;
        }
 
-       param0 = g_variant_new_boolean(value_enable);
-       params = g_variant_new("(sv)", key, param0);
+       params = g_variant_new("(sb)", interface_name, value_enable);
 
        reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
                                        CONNMAN_WIFI_TECHNOLOGY_PREFIX,
                                        CONNMAN_TECHNOLOGY_INTERFACE,
-                                       "SetProperty", params, __technology_reply);
+                                       "SetDevicePower", params,
+                                       __technology_reply,
+                                       g_strdup(interface_name));
 
        if (reply != TRUE) {
                ERR("Fail to set technology enable");
-               wifi_state_update_power_state(FALSE);
+               wifi_state_update_power_state(interface_name, FALSE);
 
                retry_count = NETCONFIG_TECH_WAITING_COUNT;
+               g_free(interface_name);
                return FALSE;
        }
 
        retry_count = NETCONFIG_TECH_WAITING_COUNT;
+       g_free(interface_name);
        return FALSE;
 }
 
-static int _set_connman_technology_power(gboolean enable)
+static int _set_connman_technology_power(const char *interface_name, gboolean enable)
 {
        gboolean reply = FALSE;
-       GVariant *param0 = NULL;
        GVariant *params = NULL;
-       char key[] = "Powered";
        gboolean value_enable = TRUE;
        gboolean value_disable = FALSE;
+       gboolean powered = FALSE;
+       wifi_tech_state_e tech_state = NETCONFIG_WIFI_TECH_UNKNOWN;
 
-       if (connman_wifi_technology_state == enable)
-               return -EALREADY;
+       DBG("Set %s technology [%s]", interface_name, enable == TRUE ? "enable" : "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;
+       powered = wifi_state_get_powered(interface_name);
+       if (powered == enable) {
+               DBG("Already %s", enable ? "enabled" : "disabled");
+               return -EALREADY;
        }
 
-       if (enable == TRUE)
-               param0 = g_variant_new_boolean(value_enable);
-       else
-               param0 = g_variant_new_boolean(value_disable);
+       if (enable == TRUE) {
+               tech_state = wifi_state_get_technology_state(interface_name);
+               if (tech_state == NETCONFIG_WIFI_TECH_UNKNOWN) {
+                       netconfig_start_timer(NETCONFIG_TECH_WAITING_INTERVAL,
+                               __check_and_set_technology_enable, g_strdup(interface_name), NULL);
+                       wifi_state_set_powered(interface_name, enable);
+                       return 0;
+               }
+       }
 
-       params = g_variant_new("(sv)", key, param0);
+       params = g_variant_new("(sb)", interface_name, (enable == TRUE) ? value_enable : value_disable);
 
        reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
-                                       CONNMAN_WIFI_TECHNOLOGY_PREFIX, CONNMAN_TECHNOLOGY_INTERFACE,
-                                       "SetProperty", params, __technology_reply);
+               CONNMAN_WIFI_TECHNOLOGY_PREFIX, CONNMAN_TECHNOLOGY_INTERFACE,
+               "SetDevicePower", params, __technology_reply, g_strdup(interface_name));
 
        if (reply != TRUE) {
                ERR("Fail to set technology %s", enable == TRUE ? "enable" : "disable");
                return -ESRCH;
        }
 
-       /* 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);
+               wifi_state_set_technology_state(interface_name, NETCONFIG_WIFI_TECH_WPS_ONLY);
 
        return 0;
 }
 
-static void __netconfig_set_wifi_bssid(void)
-{
-       int rv = 0;
-       char bssid[WLAN_MAC_ADDR_MAX];
-
-       FILE *fp = fopen(WLAN_MAC_ADDRESS_FILEPATH, "r");
-
-       if (fp == NULL) {
-               ERR("Fail to open %s", WLAN_MAC_ADDRESS_FILEPATH);
-               return;
-       }
-
-       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 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");
-               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");
-               return -EPERM;
-       }
-
-       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;
-}
-
-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
+#if !defined TIZEN_WEARABLE
 static void __netconfig_wifi_restrict_mode(keynode_t *node, void *user_data)
 {
        int wifi_state = 0, restricted = 0;
-       int wifi_off_by_restricted = 0;
-
-       netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, &wifi_off_by_restricted);
+       GSList *list = NULL;
 
        netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
 
@@ -415,28 +316,39 @@ static void __netconfig_wifi_restrict_mode(keynode_t *node, void *user_data)
                netconfig_vconf_get_bool(VCONFKEY_SETAPPL_NETWORK_RESTRICT_MODE, &restricted);
 
        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");
+       DBG("wifi state: %d (0 off / 1 on / 2 connected)", wifi_state);
 
        if (restricted > 0) {
                /* network restricted on */
+               GSList *device_list = NULL;
+
                if (wifi_state == VCONFKEY_WIFI_OFF)
                        return;
 
-               wifi_power_off();
+               device_list = wifi_state_get_device_list();
+               for (list = device_list; list; list = list->next) {
+                       wifi_device_data_s *device_data = list->data;
+                       wifi_power_off(device_data->interface_name);
+                       netconfig_setting_update_interface_off_for_restricted(device_data->interface_name, TRUE);
+               }
 
                netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, 1);
        } else {
                /* network restricted off */
-               if (!wifi_off_by_restricted)
-                       return;
+               GSList *ifname_list = NULL;
 
                netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, 0);
 
-               if (wifi_state > VCONFKEY_WIFI_OFF)
-                       return;
+               ifname_list = netconfig_setting_get_interfaces_off_by_restricted();
+               for (list = ifname_list; list; list = list->next) {
+                       char *interface_name = list->data;
+
+                       if (wifi_state_get_technology_state(interface_name) > NETCONFIG_WIFI_TECH_OFF)
+                               continue;
 
-               wifi_power_on();
+                       netconfig_setting_update_interface_off_for_restricted(interface_name, FALSE);
+                       wifi_power_on(interface_name);
+               }
        }
 }
 #endif
@@ -444,15 +356,9 @@ static void __netconfig_wifi_restrict_mode(keynode_t *node, void *user_data)
 static void __netconfig_wifi_airplane_mode(keynode_t *node, void *user_data)
 {
        int wifi_state = 0, airplane_state = 0;
-       int wifi_off_by_airplane = 0;
-
-       netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, &wifi_off_by_airplane);
+       GSList *list = NULL;
 
-#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);
@@ -460,54 +366,57 @@ static void __netconfig_wifi_airplane_mode(keynode_t *node, void *user_data)
                netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &airplane_state);
 
        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");
+       DBG("wifi state: %d (0 off / 1 on / 2 connected)", wifi_state);
 
        if (airplane_mode == airplane_state)
-               return ;
+               return;
 
        airplane_mode = airplane_state;
 
        if (airplane_state > 0) {
                /* airplane mode on */
+               GSList *device_list = NULL;
+
                if (wifi_state == VCONFKEY_WIFI_OFF)
                        return;
 
-               wifi_power_off();
+               device_list = wifi_state_get_device_list();
+               for (list = device_list; list; list = list->next) {
+                       wifi_device_data_s *device_data = list->data;
+                       if (device_data->tech_state > NETCONFIG_WIFI_TECH_OFF) {
+                               wifi_power_off(device_data->interface_name);
+                               netconfig_setting_update_interface_off_for_airplane(device_data->interface_name, TRUE);
+                       }
+               }
 
                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;
+               GSList *ifname_list = NULL;
 
                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
+               ifname_list = netconfig_setting_get_interfaces_off_by_airplane();
+               for (list = ifname_list; list; list = list->next) {
+                       char *interface_name = list->data;
+
+                       if (wifi_state_get_technology_state(interface_name) > NETCONFIG_WIFI_TECH_OFF)
+                               continue;
+
+                       netconfig_setting_update_interface_off_for_airplane(interface_name, FALSE);
+                       wifi_power_on(interface_name);
+               }
        }
 }
 
 static void __emergency_mode_changed_cb(keynode_t *node, void *user_data)
 {
        int wifi_state = 0, emergency = 0;
-       int wifi_off_by_emergency = 0;
+       GSList *list = NULL;
 #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);
 
 #if !defined TIZEN_WEARABLE
@@ -523,65 +432,147 @@ static void __emergency_mode_changed_cb(keynode_t *node, void *user_data)
                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");
+       DBG("wifi state: %d (0 off / 1 on / 2 connected)", wifi_state);
 
 #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 */
-               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);
+               GSList *device_list = NULL;
 
                if (wifi_state == VCONFKEY_WIFI_OFF)
                        return;
 
-               wifi_power_off();
+               device_list = wifi_state_get_device_list();
+               for (list = device_list; list; list = list->next) {
+                       wifi_device_data_s *device_data = list->data;
+                       wifi_power_off(device_data->interface_name);
+                       netconfig_setting_update_interface_off_for_emergency(device_data->interface_name, TRUE);
+               }
+
                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;
+               GSList *ifname_list = NULL;
 
                netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 0);
-               if (wifi_state > VCONFKEY_WIFI_OFF)
-                       return;
+               ifname_list = netconfig_setting_get_interfaces_off_by_emergency();
+               for (list = ifname_list; list; list = list->next) {
+                       char *interface_name = list->data;
 
-               wifi_power_on_wearable(TRUE);
+                       if (wifi_state_get_technology_state(interface_name) > NETCONFIG_WIFI_TECH_OFF)
+                               continue;
+
+                       netconfig_setting_update_interface_off_for_emergency(interface_name, FALSE);
+                       wifi_power_on_wearable(interface_name, TRUE);
+               }
        }
 #else
        if (emergency > SETTING_PSMODE_POWERFUL) {
                /* emergency mode on */
+               GSList *device_list = NULL;
+
                if (wifi_state == VCONFKEY_WIFI_OFF)
                        return;
 
-               wifi_power_off();
+               device_list = wifi_state_get_device_list();
+               for (list = device_list; list; list = list->next) {
+                       wifi_device_data_s *device_data = list->data;
+                       wifi_power_off(device_data->interface_name);
+                       netconfig_setting_update_interface_off_for_emergency(device_data->interface_name, TRUE);
+               }
 
                netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 1);
        } else {
                /* emergency mode off */
-               if (!wifi_off_by_emergency)
-                       return;
+               GSList *ifname_list = NULL;
 
                netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 0);
 
-               if (wifi_state > VCONFKEY_WIFI_OFF)
-                       return;
+               ifname_list = netconfig_setting_get_interfaces_off_by_emergency();
+               for (list = ifname_list; list; list = list->next) {
+                       char *interface_name = list->data;
+
+                       if (wifi_state_get_technology_state(interface_name) > NETCONFIG_WIFI_TECH_OFF)
+                               continue;
 
-               wifi_power_on();
+                       netconfig_setting_update_interface_off_for_emergency(interface_name, FALSE);
+                       wifi_power_on(interface_name);
+               }
        }
 #endif
 
 }
 
+void wifi_set_early_suspend(const char *interface_name, 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(interface_name);
+
+       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, interface_name, 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;
+       GSList *list = NULL, *device_list = NULL;
 
        if (netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state) < 0) {
                ERR("Fail to get VCONFKEY_WIFI_STATE");
@@ -603,17 +594,34 @@ 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)) {
-               netconfig_wifi_bgscan_stop();
-               netconfig_wifi_bgscan_set_interval(SCAN_EXPONENTIAL_MIN);
-               netconfig_wifi_bgscan_start(TRUE);
+               /* Send early suspend mode based on LCD state and disallow early suspend count */
+               device_list = wifi_state_get_device_list();
+               for (list = device_list; list; list = list->next) {
+                       wifi_device_data_s *device_data = list->data;
+                       if (device_data->powered == TRUE) {
+                               wifi_set_early_suspend(device_data->interface_name, FALSE);
+                               DBG("Unset early suspend [%s]", device_data->interface_name);
+                       }
+                       netconfig_wifi_bgscan_stop(device_data->interface_name);
+                       netconfig_wifi_bgscan_set_interval(device_data->interface_name, SCAN_EXPONENTIAL_MIN);
+                       netconfig_wifi_bgscan_start(device_data->interface_name, TRUE);
+               }
+       } else if ((new_state == VCONFKEY_PM_STATE_LCDOFF) && (prev_state < VCONFKEY_PM_STATE_LCDOFF) && (wifi_state != VCONFKEY_WIFI_OFF)) {
+               device_list = wifi_state_get_device_list();
+               for (list = device_list; list; list = list->next) {
+                       wifi_device_data_s *device_data = list->data;
+                       wifi_set_early_suspend(device_data->interface_name, TRUE);
+                       DBG("Set early suspend [%s]", device_data->interface_name);
+               }
        }
 
        prev_state = new_state;
 }
 
-static void __netconfig_telephony_ready_changed_cb(keynode_t * node, void *data)
+static void __netconfig_telephony_ready_changed_cb(keynode_t *node, void *data)
 {
        int telephony_ready = 0;
+       char *interface_name = data;
 
        if (node != NULL)
                telephony_ready = vconf_keynode_get_bool(node);
@@ -632,16 +640,17 @@ static void __netconfig_telephony_ready_changed_cb(keynode_t * node, void *data)
        DBG("Turn Wi-Fi on automatically");
 
 #if defined TIZEN_WEARABLE
-       wifi_power_on_wearable(TRUE);
+       wifi_power_on_wearable(interface_name, TRUE);
 #else
-       wifi_power_on();
+       wifi_power_on(interface_name);
 #endif
 
 done:
        vconf_ignore_key_changed(VCONFKEY_TELEPHONY_READY, __netconfig_telephony_ready_changed_cb);
+       g_free(interface_name);
 }
 
-int wifi_power_driver_and_supplicant(gboolean enable)
+int wifi_power_driver_and_supplicant(const char *interface_name, 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.
@@ -653,52 +662,34 @@ int wifi_power_driver_and_supplicant(gboolean enable)
         *   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();
+               return _load_driver_and_supplicant(interface_name);
        } else {
-               if (connman_wifi_technology_state == TRUE)
+               if (wifi_state_get_powered(interface_name) == TRUE)
                        return -ENOSYS;
 
-               return _remove_driver_and_supplicant();
+               return _remove_driver_and_supplicant(interface_name);
        }
 }
 
-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;
-}
-
-void wifi_power_recover_firmware(void)
+void wifi_power_recover_firmware(const char *interface_name)
 {
        wifi_firmware_recovery_mode = TRUE;
 
-       netconfig_wifi_bgscan_stop();
+       netconfig_wifi_bgscan_stop(interface_name);
 
-       wifi_power_off();
+       wifi_power_off(interface_name);
 }
 
-int wifi_power_on(void)
+int wifi_power_on(const char *interface_name)
 {
        int err = 0;
        wifi_tech_state_e tech_state;
 
-       tech_state = wifi_state_get_technology_state();
+       tech_state = wifi_state_get_technology_state(interface_name);
        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;
+               INFO("Net-Config WiFi connman technology state %d", tech_state);
                return -EALREADY;
        }
 
@@ -712,52 +703,41 @@ int wifi_power_on(void)
                return -EBUSY;
        }
 
-       err = wifi_power_driver_and_supplicant(TRUE);
+       err = wifi_power_driver_and_supplicant(interface_name, TRUE);
        if (err < 0 && err != -EALREADY)
                return err;
 
-       err = _set_connman_technology_power(TRUE);
+       err = _set_connman_technology_power(interface_name, TRUE);
 
        return err;
 }
 
-int wifi_power_off(void)
+int wifi_power_off(const char *interface_name)
 {
        int err;
 
-       err = _set_connman_technology_power(FALSE);
+       err = _set_connman_technology_power(interface_name, FALSE);
        if (err == -EALREADY)
-               wifi_state_update_power_state(FALSE);
+               wifi_state_update_power_state(interface_name, FALSE);
 
-       return 0;
+       return err;
 }
 
 #if defined TIZEN_WEARABLE
-int wifi_power_on_wearable(gboolean device_picker_test)
+int wifi_power_on_wearable(const char *interface_name, gboolean device_picker_test)
 {
        int err = 0;
-       int wifi_use = 1;
        wifi_tech_state_e tech_state;
 
-       tech_state = wifi_state_get_technology_state();
+       tech_state = wifi_state_get_technology_state(interface_name);
        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);
+       err = wifi_power_driver_and_supplicant(interface_name, TRUE);
        if (err < 0 && err != -EALREADY)
                return err;
 
-       err = _set_connman_technology_power(TRUE);
+       err = _set_connman_technology_power(interface_name, TRUE);
 
        if (device_picker_test == TRUE)
                netconfig_wifi_enable_device_picker_test();
@@ -768,22 +748,25 @@ int wifi_power_on_wearable(gboolean device_picker_test)
 
 void wifi_power_initialize(void)
 {
-       int wifi_last_power_state = 0;
+       GSList *interface_list = NULL;
 
        /* 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) {
+       interface_list = netconfig_setting_get_interfaces_for_last_powered();
+       for (; interface_list; interface_list = interface_list->next) {
+               const char *interface_name = interface_list->data;
+
                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);
+                                       __netconfig_telephony_ready_changed_cb,
+                                       g_strdup(interface_name));
                        } else {
                                if (netconfig_tapi_check_sim_state() == FALSE)
                                        DBG("SIM is not initialized yet");
@@ -791,15 +774,13 @@ void wifi_power_initialize(void)
                }
                DBG("Turn Wi-Fi on automatically");
 #if defined TIZEN_WEARABLE
-               wifi_power_on_wearable(TRUE);
+               wifi_power_on_wearable(interface_name, TRUE);
 #else
-               wifi_power_on();
+               wifi_power_on(interface_name);
 #endif
        }
 
 #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
@@ -809,7 +790,8 @@ void wifi_power_initialize(void)
                        __netconfig_wifi_airplane_mode, NULL);
 #endif
 
-       vconf_notify_key_changed(VCONFKEY_SETAPPL_PSMODE, __emergency_mode_changed_cb, NULL);
+       vconf_notify_key_changed(VCONFKEY_SETAPPL_PSMODE,
+               __emergency_mode_changed_cb, NULL);
        vconf_notify_key_changed(VCONFKEY_PM_STATE, __pm_state_changed_cb, NULL);
 }
 
@@ -818,11 +800,12 @@ void wifi_power_deinitialize(void)
 }
 
 gboolean handle_load_driver(Wifi *wifi,
-               GDBusMethodInvocation *context, gboolean device_picker_test)
+               GDBusMethodInvocation *context,
+               const gchar *ifname, gboolean device_picker_test)
 {
        int err;
 
-       DBG("Wi-Fi power on requested");
+       DBG("Wi-Fi power on requested [%s]", ifname);
 
        g_return_val_if_fail(wifi != NULL, TRUE);
 
@@ -836,9 +819,9 @@ gboolean handle_load_driver(Wifi *wifi,
                wifi_firmware_download();
 
 #if defined TIZEN_WEARABLE
-       err = wifi_power_on_wearable(device_picker_test);
+       err = wifi_power_on_wearable(ifname, device_picker_test);
 #else
-       err = wifi_power_on();
+       err = wifi_power_on(ifname);
 
        if (device_picker_test == TRUE)
                netconfig_wifi_enable_device_picker_test();
@@ -856,25 +839,23 @@ gboolean handle_load_driver(Wifi *wifi,
 
 
        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)
+gboolean handle_remove_driver(Wifi *wifi, GDBusMethodInvocation *context,
+                       const gchar *ifname)
 {
        int err;
 
-       DBG("Wi-Fi power off requested");
+       DBG("Wi-Fi power off requested [%s]", ifname);
 
        g_return_val_if_fail(wifi != NULL, TRUE);
 
-       err = wifi_power_off();
+       err = wifi_power_off(ifname);
        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);