/*
* 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.
*
*/
-#include <stdio.h>
-#include <unistd.h>
+#include <errno.h>
#include <vconf.h>
#include <vconf-keys.h>
-#include <wifi-direct.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <tzplatform_config.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
-#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/sbin/wpa_supp.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 void __netconfig_wifi_technology_reply(DBusPendingCall *call, void *data)
-{
- DBusMessage *message;
+#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"
- message = dbus_pending_call_steal_reply(call);
+#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"
- if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR) {
- ERR("%s", dbus_message_get_error_name(message));
+#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 (dbus_message_is_error(message,
- CONNMAN_ERROR_INTERFACE ".AlreadyEnabled") == TRUE) {
- netconfig_wifi_update_power_state(TRUE);
- power_in_progress = FALSE;
- } else if (dbus_message_is_error(message,
- CONNMAN_ERROR_INTERFACE ".AlreadyDisabled") == TRUE) {
- netconfig_wifi_update_power_state(FALSE);
- power_in_progress = FALSE;
- }
- } else {
- DBG("Successfully requested");
- }
+static gboolean connman_wifi_technology_state = FALSE;
+static gboolean wifi_firmware_recovery_mode = FALSE;
+static int airplane_mode = 0;
- dbus_message_unref(message);
- dbus_pending_call_unref(call);
-}
+typedef struct {
+ char *buf;
+ int used_len;
+ int total_len;
+} netconfig_wifi_priv_cmd;
-static gboolean __netconfig_wifi_enable_technology(void)
+static gboolean __is_wifi_restricted(void)
{
- gboolean reply = FALSE;
- char param0[] = "string:Powered";
- char param1[] = "variant:boolean:true";
- char *param_array[] = { NULL, NULL, NULL };
-
- param_array[0] = param0;
- param_array[1] = param1;
-
- reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
- CONNMAN_WIFI_TECHNOLOGY_PREFIX, CONNMAN_TECHNOLOGY_INTERFACE,
- "SetProperty", param_array, __netconfig_wifi_technology_reply);
+#if defined TIZEN_WEARABLE
+ return FALSE;
+#endif
+ int restricted_mode = 0;
- if (reply != TRUE)
- ERR("Fail to enable Wi-Fi");
+ 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 reply;
+ return FALSE;
}
-static gboolean __netconfig_wifi_disable_technology(void)
+static void __technology_reply(GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- gboolean reply = FALSE;
- char param0[] = "string:Powered";
- char param1[] = "variant:boolean:false";
- char *param_array[] = { NULL, NULL, NULL };
-
- param_array[0] = param0;
- param_array[1] = param1;
-
- reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
- CONNMAN_WIFI_TECHNOLOGY_PREFIX, CONNMAN_TECHNOLOGY_INTERFACE,
- "SetProperty", param_array, __netconfig_wifi_technology_reply);
-
- if (reply != TRUE)
- ERR("Fail to disable Wi-Fi");
+ GVariant *reply;
+ GDBusConnection *conn = NULL;
+ GError *error = NULL;
+
+ conn = G_DBUS_CONNECTION(source_object);
+ reply = g_dbus_connection_call_finish(conn, res, &error);
+
+ if (reply == NULL) {
+ 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);
+ }
- return reply;
+ netconfig_gdbus_pending_call_unref();
}
-static int __netconfig_wifi_supplicant(gboolean enable)
+static int __execute_supplicant(gboolean enable)
{
int rv = 0;
const char *path = WLAN_SUPPLICANT_SCRIPT;
- char *const args_enable[] = { "/usr/sbin/wpa_supp.sh", "start", NULL };
- char *const args_disable[] = { "/usr/sbin/wpa_supp.sh", "stop", NULL };
+ 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;
return 0;
}
-
-static gboolean __netconfig_wifi_load_driver(void)
+void netconfig_wifi_recover_firmware(void)
{
- gboolean rv = FALSE;
+ wifi_firmware_recovery_mode = TRUE;
- if (netconfig_emulator_is_emulated() == TRUE)
- return rv;
+ netconfig_wifi_bgscan_stop();
-#if defined EMBEDDED_TARGET
- const char *path = WLAN_DRIVER_SCRIPT;
- char *const args[] = { "wlan.sh", "start", NULL };
- char *const envs[] = { NULL };
+ wifi_power_off();
+}
- rv = netconfig_execute_file(path, args, envs);
- if (rv != TRUE) {
- DBG("Failed to load wireless device driver");
- return FALSE;
- }
-#else
- /*start the Supplicant Daemon*/
+static int _load_driver_and_supplicant(void)
+{
int err = 0;
- err = __netconfig_wifi_supplicant(TRUE);
+ 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;
-#endif
+ err = netconfig_wifi_firmware(NETCONFIG_WIFI_STA, TRUE);
+ if (err < 0 && err != -EALREADY) {
+ __execute_supplicant(FALSE);
+ return err;
+ }
+ wifi_state_set_tech_state(NETCONFIG_WIFI_TECH_WPS_ONLY);
- DBG("Successfully loaded wireless device driver");
- return TRUE;
+ return 0;
}
-gboolean netconfig_wifi_remove_driver(void)
+static int _remove_driver_and_supplicant(void)
{
- gboolean rv = FALSE;
+ int err = 0;
- if (netconfig_emulator_is_emulated() == TRUE)
- return rv;
+ 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;
+ }
-#if defined EMBEDDED_TARGET
- const char *path = WLAN_DRIVER_SCRIPT;
- char *const args[] = { "wlan.sh", "stop", NULL };
- char *const env[] = { NULL };
+ err = netconfig_wifi_firmware(NETCONFIG_WIFI_STA, FALSE);
+ if (err < 0 && err != -EALREADY)
+ return err;
- rv = netconfig_execute_file(path, args, env);
- if (rv != TRUE) {
- DBG("Failed to remove wireless device driver");
- return FALSE;
- }
-#else
- /*Stop the Supplicant Daemon*/
- int err = 0;
- err = __netconfig_wifi_supplicant(FALSE);
+ err = __execute_supplicant(FALSE);
if (err < 0 && err != -EALREADY)
return err;
-#endif
+ wifi_state_set_tech_state(NETCONFIG_WIFI_TECH_OFF);
+ // reset service state
+ wifi_state_set_service_state(NETCONFIG_WIFI_IDLE);
- DBG("Successfully removed wireless device driver");
- return TRUE;
-}
-
-static int __netconfig_wifi_try_to_load_driver(void);
-static gboolean __netconfig_wifi_try_to_remove_driver(void);
+ if (wifi_firmware_recovery_mode == TRUE) {
+ if (wifi_power_on() < 0)
+ ERR("Failed to recover Wi-Fi firmware");
-void netconfig_wifi_notify_power_completed(gboolean power_on)
-{
- DBusMessage *signal;
- DBusConnection *connection;
- DBusError error;
- char *sig_name;
+ wifi_firmware_recovery_mode = FALSE;
+ }
- if (power_on)
- sig_name = "PowerOnCompleted";
- else
- sig_name = "PowerOffCompleted";
+ return 0;
+}
- dbus_error_init(&error);
+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";
- 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;
+ if (wifi_state_is_technology_available() == FALSE) {
+ retry_count--;
+ if (retry_count > 0)
+ return TRUE;
}
- signal = dbus_message_new_signal(NETCONFIG_WIFI_PATH,
- NETCONFIG_WIFI_INTERFACE, sig_name);
- if (signal == NULL)
- return;
+ 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);
- dbus_connection_send(connection, signal, NULL);
+ if (reply != TRUE) {
+ ERR("Fail to set technology enable");
+ wifi_state_update_power_state(FALSE);
- dbus_message_unref(signal);
- dbus_connection_unref(connection);
+ retry_count = NETCONFIG_TECH_WAITING_COUNT;
+ return FALSE;
+ }
- INFO("(%s)", sig_name);
+ retry_count = NETCONFIG_TECH_WAITING_COUNT;
+ return FALSE;
}
-static void __netconfig_wifi_direct_state_cb(int error_code,
- wifi_direct_device_state_e device_state, void *user_data)
+static int _set_connman_technology_power(gboolean enable)
{
- wifi_direct_unset_device_state_changed_cb();
- wifi_direct_deinitialize();
+ gboolean reply = FALSE;
+ GVariant *params = NULL;
+ char key[] = "Powered";
+ gboolean value_enable = TRUE;
+ gboolean value_disable = FALSE;
- if (device_state == WIFI_DIRECT_DEVICE_STATE_DEACTIVATED) {
- if (__netconfig_wifi_try_to_load_driver() < 0) {
- power_in_progress = FALSE;
+ if (connman_wifi_technology_state == enable)
+ return -EALREADY;
- /* TODO: error report */
+ 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;
+ }
- return;
- }
+ 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,
+ "SetProperty", params, __technology_reply);
+
+ 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);
+
+ return 0;
}
-static gboolean __netconfig_wifi_direct_power_off(void)
+static void __netconfig_set_wifi_bssid(void)
{
- DBG("Wi-Fi direct is turning off");
+ int rv = 0;
+ char bssid[WLAN_MAC_ADDR_MAX];
- if (wifi_direct_initialize() < 0)
- return FALSE;
+ FILE *fp = fopen(WLAN_MAC_ADDRESS_FILEPATH, "r");
- if (wifi_direct_set_device_state_changed_cb(
- __netconfig_wifi_direct_state_cb, NULL) < 0)
- return FALSE;
+ if (fp == NULL) {
+ ERR("Fail to open %s", WLAN_MAC_ADDRESS_FILEPATH);
+ return;
+ }
- if (wifi_direct_deactivate() < 0)
- return FALSE;
+ fseek(fp, 0L, SEEK_SET);
+ rv = fscanf(fp, "%17s", bssid);
- return TRUE;
+ if (rv < 0)
+ ERR("Fail to read bssid");
+
+ netconfig_set_vconf_str(VCONF_WIFI_BSSID_ADDRESS, bssid);
+
+ fclose(fp);
}
-static int __netconfig_wifi_try_to_load_driver(void)
+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 (netconfig_is_wifi_allowed() != TRUE)
- return -EPERM;
+#if defined TIZEN_WEARABLE
+int netconfig_wifi_on_wearable(gboolean device_picker_test)
+{
+ int err = 0;
+ int ps_mode;
- if (netconfig_is_wifi_tethering_on() == TRUE) {
- /* TODO: Wi-Fi tethering turns off here */
- /* return TRUE; */
- return -EBUSY;
+ if (netconfig_vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &ps_mode) < 0) {
+ ERR("Fail to get VCONFKEY_SETAPPL_PSMODE");
+ return -EIO;
}
- if (netconfig_is_wifi_direct_on() == TRUE) {
- if (__netconfig_wifi_direct_power_off() == TRUE) {
- power_in_progress = TRUE;
- return -EINPROGRESS;
- } else
- return -EBUSY;
+ if (ps_mode > SETTING_PSMODE_NORMAL) {
+ WARN("ps mode is on(%d), Not turn on Wi-Fi", ps_mode);
+ return -EPERM;
}
- if (__netconfig_wifi_load_driver() != TRUE) {
- netconfig_wifi_remove_driver();
+ err = wifi_power_driver_and_supplicant(TRUE);
+ if (err < 0 && err != -EALREADY)
+ return err;
- return -EIO;
- }
+ err = _set_connman_technology_power(TRUE);
- if (__netconfig_wifi_enable_technology() != TRUE) {
- netconfig_wifi_remove_driver();
- return -EIO;
- }
+ 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)
+{
+ int wifi_state = 0, restricted = 0;
+ int wifi_off_by_restricted = 0;
- power_in_progress = TRUE;
+ netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_RESTRICTED, &wifi_off_by_restricted);
- return 0;
+ 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);
+
+ 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");
+
+ 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 gboolean __netconfig_wifi_try_to_remove_driver(void)
+static void __netconfig_wifi_airplane_mode(keynode_t *node, void *user_data)
{
- netconfig_wifi_device_picker_service_stop();
+ int wifi_state = 0, airplane_state = 0;
+ int wifi_off_by_airplane = 0;
- netconfig_wifi_statistics_update_powered_off();
+ netconfig_vconf_get_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, &wifi_off_by_airplane);
+ netconfig_vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
- if (__netconfig_wifi_disable_technology() != TRUE)
- return FALSE;
+ if (node != NULL)
+ airplane_state = vconf_keynode_get_bool(node);
+ else
+ netconfig_vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &airplane_state);
- power_in_progress = TRUE;
+ 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");
- return TRUE;
+ if (airplane_mode == airplane_state)
+ return ;
+
+ airplane_mode = airplane_state;
+
+ if (airplane_state > 0) {
+ /* airplane mode on */
+ if (wifi_state == VCONFKEY_WIFI_OFF)
+ return;
+
+ wifi_power_off();
+
+ netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 1);
+ } else {
+ /* airplane mode off */
+ if (!wifi_off_by_airplane)
+ return;
+
+ netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_AIRPLANE, 0);
+ if (wifi_state > VCONFKEY_WIFI_OFF)
+ return;
+
+ wifi_power_on();
+ }
}
-static void __netconfig_wifi_airplane_mode(keynode_t* node,
- void* user_data)
+static void __emergency_mode_changed_cb(keynode_t *node, void *user_data)
{
- int value = 0;
- int wifi_state = 0;
- static gboolean powered_off_by_flightmode = FALSE;
+ 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 (power_in_progress) {
- fm_waiting = TRUE;
+#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);
- fm_waiting = FALSE;
+ 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;
- vconf_get_bool(VCONFKEY_TELEPHONY_FLIGHT_MODE, &value);
- vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
+ 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;
- 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");
+ netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 0);
+ if (wifi_state > VCONFKEY_WIFI_OFF)
+ return;
- if (value > 0) {
- /* flight mode enabled */
+ wifi_power_on_wearable(TRUE);
+ }
+#else
+ if (emergency > SETTING_PSMODE_POWERFUL) {
+ /* emergency mode on */
if (wifi_state == VCONFKEY_WIFI_OFF)
return;
- DBG("Turning Wi-Fi off");
+ 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_wifi_try_to_remove_driver();
+ netconfig_set_vconf_int(VCONF_WIFI_OFF_STATE_BY_EMERGENCY, 0);
- powered_off_by_flightmode = TRUE;
- } else if (value == 0) {
- /* flight mode disabled */
if (wifi_state > VCONFKEY_WIFI_OFF)
return;
- if (powered_off_by_flightmode != TRUE)
- return;
+ wifi_power_on();
+ }
+#endif
- __netconfig_wifi_try_to_load_driver();
+}
- powered_off_by_flightmode = FALSE;
- } else
- DBG("Invalid value (%d)", value);
+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 __netconfig_wifi_pm_state_mode(keynode_t* node,
- void* user_data)
+static void __pm_state_changed_cb(keynode_t* node, void* user_data)
{
- int value = -1;
+ 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();
}
+}
+
+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;
+}
- DBG("Old state: %d, current: %d", prev_state, value);
+void wifi_power_recover_firmware(void)
+{
+ wifi_firmware_recovery_mode = TRUE;
- if((value == VCONFKEY_PM_STATE_NORMAL) && (prev_state >= VCONFKEY_PM_STATE_LCDOFF)) {
- DBG("PM state : Wake UP!");
+ netconfig_wifi_bgscan_stop();
- netconfig_wifi_bgscan_stop();
- netconfig_wifi_bgscan_start();
+ 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;
+ }
+
+ 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;
}
- prev_state = value;
+ 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;
}