Fix path traversal
[platform/core/connectivity/net-config.git] / src / wifi-config.c
index 5c5082b..88cda23 100755 (executable)
@@ -20,6 +20,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 #include <sys/types.h>
 #include <dirent.h>
 #include <sys/stat.h>
@@ -28,6 +29,7 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <sys/time.h>
 
 #include <vconf.h>
 
@@ -35,6 +37,7 @@
 #include "util.h"
 #include "neterror.h"
 #include "wifi-config.h"
+#include "wifi-state.h"
 #include "netsupplicant.h"
 #include "wifi-key-encryption.h"
 
 #define WIFI_SECURITY_WEP              "wep"
 #define WIFI_SECURITY_WPA_PSK  "psk"
 #define WIFI_SECURITY_EAP              "ieee8021x"
-
-#define WIFI_CONFIG_PREFIX      "wifi_"
-#define MAC_ADDRESS_LENGTH             12
-#define WIFI_PREFIX_LENGTH             MAC_ADDRESS_LENGTH + 6  /* wifi_485a3f2f506a_ */
-#define PROFILE_PREFIX_LENGTH  WIFI_PREFIX_LENGTH + 21 /* /net/connman/service/wifi_485a3f2f506a_ */
-
-#define WIFI_MAC_ADD_LENGTH            17
-#define WIFI_MAC_ADD_PATH              "/sys/class/net/wlan0/address"
+#define WIFI_SECURITY_SAE              "sae"
 
 #define        NET_DNS_ADDR_MAX                2
 
+#define MAX_WIFI_PROFILES              200
+
 struct wifi_eap_config {
        gchar *anonymous_identity;
        gchar *ca_cert;
@@ -90,6 +88,7 @@ struct wifi_config {
        gchar *proxy_address;
        struct wifi_eap_config *eap_config;
        wifi_ip_info_s *ip_info;
+       guint frequency;
        gchar *last_error;
 };
 
@@ -136,42 +135,41 @@ static void __free_wifi_configuration(struct wifi_config *conf)
        g_free(conf);
 }
 
-static gboolean __get_mac_address(gchar **mac_address)
+static gboolean __get_mac_address(const gchar *interface_name, gchar **mac_address)
 {
+       FILE *fp = NULL;
+       char buf[WIFI_MAC_ADDR_LENGTH + 1];
+       char path[WIFI_MAC_PATH_LENGTH];
        gchar *tmp_mac = NULL;
        gchar *tmp = NULL;
        gchar mac[13] = { 0, };
        gint i = 0, j = 0;
 
-       if (TIZEN_TV) {
-               FILE *fp = NULL;
-               char buf[WIFI_MAC_ADD_LENGTH + 1];
-               if (0 == access(WIFI_MAC_ADD_PATH, F_OK))
-                       fp = fopen(WIFI_MAC_ADD_PATH, "r");
+       snprintf(path, WIFI_MAC_PATH_LENGTH, WIFI_MAC_ADDR_PATH, interface_name);
 
-               if (fp == NULL) {
-                       ERR("Failed to open file %s\n", WIFI_MAC_ADD_PATH);
-                       *mac_address = NULL;
-                       return FALSE;
-               }
+       if (0 == access(path, F_OK))
+               fp = fopen(path, "r");
 
+       if (fp) {
                if (fgets(buf, sizeof(buf), fp) == NULL) {
-                       ERR("Failed to get MAC info from %s\n", WIFI_MAC_ADD_PATH);
+                       ERR("Failed to get MAC info from %s\n", path);
                        *mac_address = NULL;
                        fclose(fp);
                        return FALSE;
                }
-               tmp_mac = (gchar *)malloc(WIFI_MAC_ADD_LENGTH + 1);
+               tmp_mac = (gchar *)malloc(WIFI_MAC_ADDR_LENGTH + 1);
                if (tmp_mac == NULL) {
                        ERR("malloc() failed");
                        *mac_address = NULL;
                        fclose(fp);
                        return FALSE;
                }
-               memset(tmp_mac, 0, WIFI_MAC_ADD_LENGTH + 1);
-               g_strlcpy(tmp_mac, buf, WIFI_MAC_ADD_LENGTH + 1);
+               memset(tmp_mac, 0, WIFI_MAC_ADDR_LENGTH + 1);
+               g_strlcpy(tmp_mac, buf, WIFI_MAC_ADDR_LENGTH + 1);
                fclose(fp);
        } else {
+               ERR("Failed to open file %s\n", path);
+
                tmp_mac = vconf_get_str(VCONFKEY_WIFI_BSSID_ADDRESS);
                if (tmp_mac == NULL) {
                        ERR("vconf_get_str(WIFI_BSSID_ADDRESS) Failed");
@@ -179,6 +177,7 @@ static gboolean __get_mac_address(gchar **mac_address)
                        return FALSE;
                }
        }
+
        tmp = g_ascii_strdown(tmp_mac, (gssize)strlen(tmp_mac));
        free(tmp_mac);
        while (tmp && tmp[i]) {
@@ -193,13 +192,19 @@ static gboolean __get_mac_address(gchar **mac_address)
        return TRUE;
 }
 
-static gboolean __get_group_name(const gchar *prefix, const gchar *config_id, gchar **group_name)
+gboolean wifi_config_get_group_name(const gchar *prefix,
+               const gchar *interface_name, const gchar *config_id, gchar **group_name)
 {
        gchar *mac_address = NULL;
        gchar *g_name = NULL;
        gboolean ret = FALSE;
 
-       ret = __get_mac_address(&mac_address);
+       if (__netconfig_is_valid_config_id(config_id) == FALSE) {
+               ERR("Invalid config_id [%s]", config_id);
+               return FALSE;
+       }
+
+       ret = __get_mac_address(interface_name, &mac_address);
        if ((ret != TRUE) || (strlen(mac_address) == 0)) {
                ERR("Cannot get WIFI MAC address");
                g_free(mac_address);
@@ -230,6 +235,8 @@ static gboolean __get_security_type(const gchar *config_id, gchar **type)
                *type = g_strdup(WIFI_SECURITY_WPA_PSK);
        } else if (g_str_has_suffix(config_id, WIFI_SECURITY_EAP) == TRUE) {
                *type = g_strdup(WIFI_SECURITY_EAP);
+       } else if (g_str_has_suffix(config_id, WIFI_SECURITY_SAE) == TRUE) {
+               *type = g_strdup(WIFI_SECURITY_SAE);
        } else {
                *type = NULL;
                return FALSE;
@@ -283,16 +290,37 @@ static gboolean __remove_file(const gchar *pathname, const gchar *filename)
        return ret;
 }
 
+static gboolean __remove_all_files(const gchar *pathname)
+{
+       DIR *dir_ptr = NULL;
+       struct dirent *file = NULL;
+
+       if ((dir_ptr = opendir(pathname)) == NULL)
+               return TRUE;
+
+       while ((file = readdir(dir_ptr)) != NULL) {
+               if (strncmp(file->d_name, ".", 1) == 0 || strncmp(file->d_name, "..", 2) == 0)
+                       continue;
+
+               if (__remove_file(pathname, file->d_name) != TRUE) {
+                       ERR("Cannot remove [%s/%s]", pathname, file->d_name);
+                       closedir(dir_ptr);
+
+                       return FALSE;
+               }
+       }
+
+       closedir(dir_ptr);
+
+       return TRUE;
+}
+
 static gboolean __remove_configuration(const gchar *pathname)
 {
        int ret = 0;
 
-       if (__remove_file(pathname, "settings") != TRUE) {
-               ERR("Cannot remove [%s/settings]", pathname);
-               return FALSE;
-       }
-       if (__remove_file(pathname, "data") != TRUE) {
-               ERR("Cannot remove [%s/data]", pathname);
+       if (__remove_all_files(pathname) != TRUE) {
+               ERR("Cannot remove [%s] directory", pathname);
                return FALSE;
        }
 
@@ -301,18 +329,19 @@ static gboolean __remove_configuration(const gchar *pathname)
                ERR("Cannot remove [%s]", pathname);
                return FALSE;
        }
-
        return TRUE;
 }
 
-static gboolean _load_configuration(const gchar *config_id, struct wifi_config *config)
+static gboolean _load_configuration(const gchar *interface_name,
+               const gchar *config_id, struct wifi_config *config)
 {
        GKeyFile *keyfile;
        gchar *group_name;
        gboolean hidden = FALSE;
        gboolean ret = FALSE;
 
-       ret = __get_group_name(WIFI_CONFIG_PREFIX, config_id, &group_name);
+       ret = wifi_config_get_group_name(WIFI_CONFIG_PREFIX,
+                       interface_name, config_id, &group_name);
        if (ret != TRUE) {
                ERR("Fail to get_wifi_config_group_name");
                return FALSE;
@@ -328,6 +357,13 @@ static gboolean _load_configuration(const gchar *config_id, struct wifi_config *
        config->name = g_key_file_get_string(keyfile, group_name, WIFI_CONFIG_NAME, NULL);
        DBG("name [%s]", config->name);
 
+       if (config->name == NULL) {
+               ERR("Fail to get Name of [%s]", group_name);
+               g_key_file_free(keyfile);
+               g_free(group_name);
+               return FALSE;
+       }
+
        __get_security_type(config_id, &config->security_type);
        if (config->security_type == NULL) {
                ERR("Fail to _get_security_type");
@@ -351,8 +387,11 @@ static gboolean _load_configuration(const gchar *config_id, struct wifi_config *
                config->is_hidden = g_strdup("FALSE");
        DBG("is_hidden [%s]", config->is_hidden);
 
+       config->frequency = g_key_file_get_integer(keyfile, group_name, WIFI_CONFIG_FREQUENCY, NULL);
+       if (config->frequency)
+               DBG("Frequency [%d]", config->frequency);
+
        if (config->ip_info) {
-               GError *error = NULL;
                config->ip_info->ip_type = g_key_file_get_string(keyfile, group_name,
                                WIFI_CONFIG_IPV4_METHOD, NULL);
                if (config->ip_info->ip_type)
@@ -367,6 +406,7 @@ static gboolean _load_configuration(const gchar *config_id, struct wifi_config *
                in_addr_t addr;
                struct in_addr netmask;
                char *mask;
+               GError *error = NULL;
                prefix_len = g_key_file_get_integer(keyfile, group_name,
                                WIFI_CONFIG_IPV4_SUBNET_MASK, &error);
                if (error != NULL) {
@@ -453,14 +493,16 @@ static gboolean _load_configuration(const gchar *config_id, struct wifi_config *
        return TRUE;
 }
 
-static gboolean _save_configuration(const gchar *config_id, GKeyFile *keyfile)
+gboolean wifi_config_save_configuration(const gchar *interface_name,
+               const gchar *config_id, GKeyFile *keyfile)
 {
        gchar *dir;
        gchar *path;
        gchar *group_name;
        gboolean ret = FALSE;
 
-       ret = __get_group_name(WIFI_CONFIG_PREFIX, config_id, &group_name);
+       ret = wifi_config_get_group_name(WIFI_CONFIG_PREFIX,
+                       interface_name, config_id, &group_name);
        if (ret != TRUE) {
                ERR("Fail to get_wifi_config_group_name");
                return FALSE;
@@ -492,13 +534,14 @@ static gboolean _save_configuration(const gchar *config_id, GKeyFile *keyfile)
        return TRUE;
 }
 
-static gboolean _remove_configuration(const gchar *config_id)
+static gboolean _remove_configuration(const gchar *interface_name, const gchar *config_id)
 {
        gboolean ret = FALSE;
        gchar *dir;
        gchar *group_name;
 
-       ret = __get_group_name(WIFI_CONFIG_PREFIX, config_id, &group_name);
+       ret = wifi_config_get_group_name(WIFI_CONFIG_PREFIX,
+                       interface_name, config_id, &group_name);
        if (ret != TRUE) {
                ERR("Fail to get_wifi_config_group_name");
                return FALSE;
@@ -509,9 +552,10 @@ static gboolean _remove_configuration(const gchar *config_id)
                if (__remove_configuration(dir) != TRUE) {
                        ERR("[%s] is existed, but cannot remove", dir);
                        ret = FALSE;
+               } else {
+                       INFO("Success to remove [%s]", dir);
+                       ret = TRUE;
                }
-               INFO("Success to remove [%s]", dir);
-               ret = TRUE;
        } else {
                ERR("[%s] is not existed", dir);
                ret = FALSE;
@@ -524,13 +568,15 @@ static gboolean _remove_configuration(const gchar *config_id)
 }
 
 
-static gboolean _set_field(const gchar *config_id, const gchar *key, const gchar *value)
+static gboolean _set_field(const gchar *interface_name,
+               const gchar *config_id, const gchar *key, const gchar *value)
 {
        gboolean ret = TRUE;
        GKeyFile *keyfile;
        gchar *group_name;
 
-       ret = __get_group_name(WIFI_CONFIG_PREFIX, config_id, &group_name);
+       ret = wifi_config_get_group_name(WIFI_CONFIG_PREFIX,
+                       interface_name, config_id, &group_name);
        if (ret != TRUE) {
                ERR("Fail to get_wifi_config_group_name");
                return FALSE;
@@ -574,7 +620,7 @@ static gboolean _set_field(const gchar *config_id, const gchar *key, const gchar
                ret = FALSE;
        }
 
-       _save_configuration(config_id, keyfile);
+       wifi_config_save_configuration(interface_name, config_id, keyfile);
 
        g_key_file_free(keyfile);
        g_free(group_name);
@@ -582,7 +628,8 @@ static gboolean _set_field(const gchar *config_id, const gchar *key, const gchar
        return ret;
 }
 
-static gboolean _get_field(const gchar *config_id, const gchar *key, gchar **value)
+static gboolean _get_field(const gchar *interface_name,
+               const gchar *config_id, const gchar *key, gchar **value)
 {
        GKeyFile *keyfile;
        gchar *group_name;
@@ -590,7 +637,8 @@ static gboolean _get_field(const gchar *config_id, const gchar *key, gchar **val
        gboolean hidden = FALSE;
        gboolean ret = FALSE;
 
-       ret = __get_group_name(WIFI_CONFIG_PREFIX, config_id, &group_name);
+       ret = wifi_config_get_group_name(WIFI_CONFIG_PREFIX,
+                       interface_name, config_id, &group_name);
        if (ret != TRUE) {
                ERR("Fail to get_wifi_config_group_name");
                return FALSE;
@@ -607,7 +655,14 @@ static gboolean _get_field(const gchar *config_id, const gchar *key, gchar **val
        if (g_strcmp0(key, WIFI_CONFIG_NAME) == 0) {
                val = g_key_file_get_string(keyfile, group_name, WIFI_CONFIG_NAME, NULL);
        } else if (g_strcmp0(key, WIFI_CONFIG_PASSPHRASE) == 0) {
-               val = g_key_file_get_string(keyfile, group_name, WIFI_CONFIG_PASSPHRASE, NULL);
+               gchar *enc_pass = g_key_file_get_string(keyfile, group_name, WIFI_CONFIG_PASSPHRASE, NULL);
+               if (enc_pass) {
+                       val = _netconfig_decrypt_passphrase(enc_pass);
+                       g_free(enc_pass);
+
+                       if (!val)
+                               ERR("Failed to decrypt the passphrase");
+               }
        } else if (g_strcmp0(key, WIFI_CONFIG_PROXY_SERVER) == 0) {
                val = g_key_file_get_string(keyfile, group_name, WIFI_CONFIG_PROXY_SERVER, NULL);
        } else if (g_strcmp0(key, WIFI_CONFIG_HIDDEN) == 0) {
@@ -648,7 +703,7 @@ static gboolean _get_field(const gchar *config_id, const gchar *key, gchar **val
        return TRUE;
 }
 
-static GSList *_get_list(void)
+static GSList *_get_list(const char *mac_addr)
 {
        GSList *list = NULL;
        struct dirent *dp = NULL;
@@ -665,9 +720,15 @@ static GSList *_get_list(void)
                                strncmp(dp->d_name, WIFI_CONFIG_PREFIX, strlen(WIFI_CONFIG_PREFIX)) != 0) {
                        continue;
                }
-               gchar *config_id = g_strdup(dp->d_name + WIFI_PREFIX_LENGTH);
-               list = g_slist_append(list, g_strdup(config_id));
-               g_free(config_id);
+
+               DBG("%s", dp->d_name);
+
+               if (netconfig_check_mac_address(dp->d_name, mac_addr)) {
+                       gchar *config_id = g_strdup(dp->d_name + WIFI_PREFIX_LENGTH);
+                       DBG("%s", config_id);
+                       list = g_slist_append(list, g_strdup(config_id));
+                       g_free(config_id);
+               }
        }
        closedir(dir);
 
@@ -691,11 +752,12 @@ gboolean wifi_config_get_config_id(const gchar *service_profile, gchar **config_
        return ret;
 }
 
-gboolean wifi_config_remove_configuration(const gchar *config_id)
+gboolean wifi_config_remove_configuration(const gchar *interface_name,
+               const gchar *config_id)
 {
        gboolean ret = FALSE;
 
-       ret = _remove_configuration(config_id);
+       ret = _remove_configuration(interface_name, config_id);
 
        return ret;
 }
@@ -818,7 +880,7 @@ static int __netconfig_unpack_ay_malloc(unsigned char **dst, GVariantIter *iter)
        return length;
 }
 
-gboolean _add_vsie(int frame_id, const char* vsie)
+gboolean _add_vsie(const char *interface_name, int frame_id, const char* vsie)
 {
        GVariant *params = NULL;
        GVariant *message = NULL;
@@ -862,8 +924,7 @@ gboolean _add_vsie(int frame_id, const char* vsie)
        params = g_variant_new("(iay)", frame_id, bytearray_builder);
        g_variant_builder_unref(bytearray_builder);
 
-       if_path = netconfig_wifi_get_supplicant_interface();
-
+       if_path = netconfig_wifi_get_supplicant_interface_path(interface_name);
        if (if_path == NULL) {
                ERR("Fail to get wpa_supplicant DBus path");
                g_free(bytearray);
@@ -886,7 +947,7 @@ gboolean _add_vsie(int frame_id, const char* vsie)
        return TRUE;
 }
 
-gboolean _get_vsie(int frame_id, char **vsie)
+gboolean _get_vsie(const char *interface_name, int frame_id, char **vsie)
 {
        GVariant *params = NULL;
        GVariant *message = NULL;
@@ -897,7 +958,7 @@ gboolean _get_vsie(int frame_id, char **vsie)
                return FALSE;
        }
 
-       if_path = netconfig_wifi_get_supplicant_interface();
+       if_path = netconfig_wifi_get_supplicant_interface_path(interface_name);
        if (if_path == NULL) {
                ERR("Fail to get wpa_supplicant DBus path");
                return FALSE;
@@ -946,7 +1007,7 @@ gboolean _get_vsie(int frame_id, char **vsie)
 
 }
 
-gboolean _remove_vsie(int frame_id, const char *vsie)
+gboolean _remove_vsie(const char *interface_name, int frame_id, const char *vsie)
 {
        GVariant *params = NULL;
        GVariant *message = NULL;
@@ -990,7 +1051,7 @@ gboolean _remove_vsie(int frame_id, const char *vsie)
        params = g_variant_new("(iay)", frame_id, bytearray_builder);
        g_variant_builder_unref(bytearray_builder);
 
-       if_path = netconfig_wifi_get_supplicant_interface();
+       if_path = netconfig_wifi_get_supplicant_interface_path(interface_name);
        if (if_path == NULL) {
                ERR("Fail to get wpa_supplicant DBus path");
                g_free(bytearray);
@@ -1014,16 +1075,26 @@ gboolean _remove_vsie(int frame_id, const char *vsie)
 }
 
 /* dbus method */
-gboolean handle_get_config_ids(Wifi *wifi, GDBusMethodInvocation *context)
+gboolean handle_get_config_ids(Wifi *wifi, GDBusMethodInvocation *context,
+               const gchar *ifname)
 {
        guint i = 0;
        GSList *config_ids = NULL;
        guint length;
        gchar **result = NULL;
+       const gchar *mac_addr = NULL;
 
        g_return_val_if_fail(wifi != NULL, TRUE);
 
-       config_ids = _get_list();
+       mac_addr = wifi_state_get_mac_address(ifname);
+       if (!mac_addr) {
+               ERR("Fail to get mac-address");
+               netconfig_error_no_profile(context);
+               return TRUE;
+       }
+
+       DBG("%s", mac_addr);
+       config_ids = _get_list(mac_addr);
        if (config_ids == NULL) {
                ERR("Fail to get config list");
                netconfig_error_no_profile(context);
@@ -1053,7 +1124,7 @@ gboolean handle_get_config_ids(Wifi *wifi, GDBusMethodInvocation *context)
 }
 
 gboolean handle_load_configuration(Wifi *wifi, GDBusMethodInvocation *context,
-               const gchar *config_id)
+               const gchar *ifname, const gchar *config_id)
 {
        gboolean ret = FALSE;
        GVariantBuilder *b = NULL;
@@ -1064,7 +1135,7 @@ gboolean handle_load_configuration(Wifi *wifi, GDBusMethodInvocation *context,
        conf = g_new0(struct wifi_config, 1);
        conf->ip_info = g_new0(wifi_ip_info_s, 1);
 
-       ret = _load_configuration(config_id, conf);
+       ret = _load_configuration(ifname, config_id, conf);
        if (ret != TRUE) {
                g_free(conf->ip_info);
                g_free(conf);
@@ -1078,6 +1149,7 @@ gboolean handle_load_configuration(Wifi *wifi, GDBusMethodInvocation *context,
        g_variant_builder_add(b, "{sv}", WIFI_CONFIG_SECURITY_TYPE, g_variant_new_string(conf->security_type));
        g_variant_builder_add(b, "{sv}", WIFI_CONFIG_PASSPHRASE, g_variant_new_string(conf->passphrase));
        g_variant_builder_add(b, "{sv}", WIFI_CONFIG_HIDDEN, g_variant_new_string(conf->is_hidden));
+       g_variant_builder_add(b, "{sv}", WIFI_CONFIG_FREQUENCY, g_variant_new_uint32(conf->frequency));
 
        if (conf->proxy_address != NULL)
                g_variant_builder_add(b, "{sv}", WIFI_CONFIG_PROXYADDRESS, g_variant_new_string(conf->proxy_address));
@@ -1117,6 +1189,8 @@ gboolean handle_load_configuration(Wifi *wifi, GDBusMethodInvocation *context,
 
        __free_wifi_configuration(conf);
 
+       INFO("Success to load configuration [%s:%s]", ifname, config_id);
+
        wifi_complete_load_configuration(wifi, context, g_variant_builder_end(b));
        g_variant_builder_unref(b);
        return TRUE;
@@ -1146,8 +1220,29 @@ static unsigned char __netconfig_convert_netmask_to_prefixlen(
        return bits;
 }
 
+gboolean __netconfig_is_valid_config_id(const gchar *config_id)
+{
+       int length;
+
+       if (!config_id)
+               return FALSE;
+
+       length = strlen(config_id);
+       if (length < 1 || length > WIFI_CONFIG_ID_LENGTH)
+               return FALSE;
+
+       for (int i = 0; i < length; i++) {
+               if (!(islower(config_id[i])) &&
+                               !(isdigit(config_id[i])) &&
+                               config_id[i] != '_')
+                       return FALSE;
+       }
+
+       return TRUE;
+}
+
 gboolean handle_save_configuration(Wifi *wifi, GDBusMethodInvocation *context,
-               const gchar *config_id, GVariant *configuration)
+               const gchar *ifname, const gchar *config_id, GVariant *configuration)
 {
        gboolean ret = FALSE;
        struct wifi_config *conf = NULL;
@@ -1157,8 +1252,12 @@ gboolean handle_save_configuration(Wifi *wifi, GDBusMethodInvocation *context,
        gchar *field;
        gchar *group_name = NULL;
        int order = 0;
+       int rv;
+       struct timeval modified_time;
 
-       if ((wifi == NULL) || (config_id == NULL) || (configuration == NULL)) {
+       if ((wifi == NULL) ||
+                       (__netconfig_is_valid_config_id(config_id) == FALSE) ||
+                       (configuration == NULL)) {
                ERR("Invalid parameter");
                netconfig_error_invalid_parameter(context);
                return TRUE;
@@ -1197,6 +1296,13 @@ gboolean handle_save_configuration(Wifi *wifi, GDBusMethodInvocation *context,
                        } else {
                                conf->is_hidden = NULL;
                        }
+               } else if (g_strcmp0(field, WIFI_CONFIG_FREQUENCY) == 0) {
+                       if (g_variant_is_of_type(value, G_VARIANT_TYPE_UINT32)) {
+                               conf->frequency = g_variant_get_uint32(value);
+                               DBG("frequency [%d]", conf->frequency);
+                       } else {
+                               conf->frequency = 0;
+                       }
                } else if (g_strcmp0(field, WIFI_CONFIG_CREATED) == 0) {
                        if (g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
                                conf->is_created = g_variant_get_boolean(value);
@@ -1267,7 +1373,8 @@ gboolean handle_save_configuration(Wifi *wifi, GDBusMethodInvocation *context,
        conf->favorite = TRUE;
        conf->autoconnect = TRUE;
 
-       ret = __get_group_name(WIFI_CONFIG_PREFIX, config_id, &group_name);
+       ret = wifi_config_get_group_name(WIFI_CONFIG_PREFIX,
+                       ifname, config_id, &group_name);
        if (ret != TRUE) {
                __free_wifi_configuration(conf);
                ERR("Fail to get_wifi_config_group_name");
@@ -1300,6 +1407,23 @@ gboolean handle_save_configuration(Wifi *wifi, GDBusMethodInvocation *context,
        g_key_file_set_boolean(keyfile, group_name, WIFI_CONFIG_FAVORITE, conf->favorite);
        g_key_file_set_boolean(keyfile, group_name, WIFI_CONFIG_AUTOCONNECT, conf->autoconnect);
 
+       rv = gettimeofday(&modified_time, NULL);
+       if (!rv) {
+               struct tm modified_tm;
+               char time_buf[255];
+               time_t modified_t = modified_time.tv_sec;
+
+               if (localtime_r(&modified_t, &modified_tm)) {
+                       if (strftime(time_buf, sizeof(time_buf), "%FT%TZ", &modified_tm)) {
+                               field = g_strdup(time_buf);
+                               if (field) {
+                                       g_key_file_set_string(keyfile, group_name, WIFI_CONFIG_MODIFIED, field);
+                                       g_free(field);
+                               }
+                       }
+               }
+       }
+
        /* Optional field */
        if (conf->proxy_address != NULL) {
                g_key_file_set_string(keyfile, group_name, WIFI_CONFIG_PROXY_METHOD, "manual");
@@ -1313,6 +1437,10 @@ gboolean handle_save_configuration(Wifi *wifi, GDBusMethodInvocation *context,
                g_key_file_set_boolean(keyfile, group_name, WIFI_CONFIG_HIDDEN, hidden);
        }
 
+       if (conf->frequency > 0)
+               g_key_file_set_integer(keyfile, group_name,
+                       WIFI_CONFIG_FREQUENCY, conf->frequency);
+
        if (conf->ip_info->ip_type != NULL)
                g_key_file_set_string(keyfile, group_name,
                        WIFI_CONFIG_IPV4_METHOD, conf->ip_info->ip_type);
@@ -1351,10 +1479,25 @@ gboolean handle_save_configuration(Wifi *wifi, GDBusMethodInvocation *context,
                i += 1;
        }
 
-       ret = _save_configuration(config_id, keyfile);
+       ret = wifi_config_save_configuration(ifname, config_id, keyfile);
        if (ret == TRUE) {
                INFO("Success to save configuration [%s]", config_id);
                wifi_complete_save_configuration(wifi, context);
+               char *file;
+               if (get_files_count(CONNMAN_STORAGE) > MAX_WIFI_PROFILES) {
+                       file = get_least_recently_profile(CONNMAN_STORAGE);
+                       if (file) {
+                               gchar *profileName = g_strdup_printf(CONNMAN_STORAGE "/%s", file);
+                               INFO("least modified file:  %s", profileName);
+                               if (profileName) {
+                                       if (__remove_configuration(profileName) != TRUE)
+                                               DBG("Failed to remove profile: [%s]", profileName);
+                               } else
+                                       ERR("Profile: [%s] does not exist", file);
+
+                               g_free(profileName);
+                       }
+               }
        } else {
                INFO("Fail to save configuration [%s]", config_id);
                netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "FailSaveConfiguration");
@@ -1370,7 +1513,7 @@ gboolean handle_save_configuration(Wifi *wifi, GDBusMethodInvocation *context,
 }
 
 gboolean handle_load_eap_configuration(Wifi *wifi, GDBusMethodInvocation *context,
-               const gchar *config_id)
+               const gchar *ifname, const gchar *config_id)
 {
        gboolean ret = FALSE;
        GVariantBuilder *b = NULL;
@@ -1382,7 +1525,7 @@ gboolean handle_load_eap_configuration(Wifi *wifi, GDBusMethodInvocation *contex
        conf->eap_config = g_new0(struct wifi_eap_config, 1);
        conf->ip_info = g_new0(wifi_ip_info_s, 1);
 
-       ret = _load_configuration(config_id, conf);
+       ret = _load_configuration(ifname, config_id, conf);
        if (ret != TRUE) {
                g_free(conf->eap_config);
                g_free(conf->ip_info);
@@ -1396,6 +1539,8 @@ gboolean handle_load_eap_configuration(Wifi *wifi, GDBusMethodInvocation *contex
        g_variant_builder_add(b, "{sv}", WIFI_CONFIG_NAME, g_variant_new_string(conf->name));
        g_variant_builder_add(b, "{sv}", WIFI_CONFIG_SECURITY_TYPE, g_variant_new_string(conf->security_type));
        g_variant_builder_add(b, "{sv}", WIFI_CONFIG_HIDDEN, g_variant_new_string(conf->is_hidden));
+       g_variant_builder_add(b, "{sv}", WIFI_CONFIG_FREQUENCY, g_variant_new_uint32(conf->frequency));
+
        if (conf->proxy_address != NULL)
                g_variant_builder_add(b, "{sv}", WIFI_CONFIG_PROXYADDRESS, g_variant_new_string(conf->proxy_address));
        else
@@ -1461,7 +1606,7 @@ gboolean handle_load_eap_configuration(Wifi *wifi, GDBusMethodInvocation *contex
 }
 
 gboolean handle_save_eap_configuration(Wifi *wifi, GDBusMethodInvocation *context,
-               const gchar *config_id, GVariant *configuration)
+               const gchar *ifname, const gchar *config_id, GVariant *configuration)
 {
        gboolean ret = FALSE;
        struct wifi_config *conf = NULL;
@@ -1510,6 +1655,13 @@ gboolean handle_save_eap_configuration(Wifi *wifi, GDBusMethodInvocation *contex
                        } else {
                                conf->is_hidden = NULL;
                        }
+               } else if (g_strcmp0(field, WIFI_CONFIG_FREQUENCY) == 0) {
+                       if (g_variant_is_of_type(value, G_VARIANT_TYPE_UINT32)) {
+                               conf->frequency = g_variant_get_uint32(value);
+                               DBG("frequency [%d]", conf->frequency);
+                       } else {
+                               conf->frequency = 0;
+                       }
                } else if (g_strcmp0(field, WIFI_CONFIG_CREATED) == 0) {
                        if (g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
                                conf->is_created = g_variant_get_boolean(value);
@@ -1592,7 +1744,8 @@ gboolean handle_save_eap_configuration(Wifi *wifi, GDBusMethodInvocation *contex
        conf->favorite = TRUE;
        conf->autoconnect = TRUE;
 
-       ret = __get_group_name(WIFI_CONFIG_PREFIX, config_id, &group_name);
+       ret = wifi_config_get_group_name(WIFI_CONFIG_PREFIX,
+                       ifname, config_id, &group_name);
        if (ret != TRUE) {
                __free_wifi_configuration(conf);
                ERR("Fail to get_wifi_config_group_name");
@@ -1636,6 +1789,10 @@ gboolean handle_save_eap_configuration(Wifi *wifi, GDBusMethodInvocation *contex
                g_key_file_set_boolean(keyfile, group_name, WIFI_CONFIG_HIDDEN, hidden);
        }
 
+       if (conf->frequency > 0)
+               g_key_file_set_integer(keyfile, group_name,
+                       WIFI_CONFIG_FREQUENCY, conf->frequency);
+
        if (conf->eap_config->anonymous_identity != NULL)
                g_key_file_set_string(keyfile, group_name,
                        WIFI_CONFIG_EAP_ANONYMOUS_IDENTITY, conf->eap_config->anonymous_identity);
@@ -1672,7 +1829,7 @@ gboolean handle_save_eap_configuration(Wifi *wifi, GDBusMethodInvocation *contex
                g_key_file_set_string(keyfile, group_name,
                        WIFI_CONFIG_EAP_SUBJECT_MATCH, conf->eap_config->subject_match);
 
-       ret = _save_configuration(config_id, keyfile);
+       ret = wifi_config_save_configuration(ifname, config_id, keyfile);
        if (ret == TRUE) {
                INFO("Success to save eap configuration [%s]", config_id);
                wifi_complete_save_eap_configuration(wifi, context);
@@ -1690,7 +1847,8 @@ gboolean handle_save_eap_configuration(Wifi *wifi, GDBusMethodInvocation *contex
        return TRUE;
 }
 
-gboolean handle_remove_configuration(Wifi *wifi, GDBusMethodInvocation *context, const gchar *config_id)
+gboolean handle_remove_configuration(Wifi *wifi, GDBusMethodInvocation *context,
+                       const gchar *ifname, const gchar *config_id)
 {
        gboolean ret = FALSE;
 
@@ -1700,7 +1858,7 @@ gboolean handle_remove_configuration(Wifi *wifi, GDBusMethodInvocation *context,
                return TRUE;
        }
 
-       ret = _remove_configuration(config_id);
+       ret = _remove_configuration(ifname, config_id);
        if (ret != TRUE) {
                /* no configuration or error */
                ERR("No [%s] configuration", config_id);
@@ -1712,6 +1870,52 @@ gboolean handle_remove_configuration(Wifi *wifi, GDBusMethodInvocation *context,
        return TRUE;
 }
 
+gboolean handle_reset_wifi_config(Wifi *wifi, GDBusMethodInvocation *context)
+{
+       DIR *dir_ptr = NULL;
+       struct dirent *file = NULL;
+       struct stat buf;
+       char dir_name[512] = { 0, };
+       char file_name[1024] = { 0, };
+
+       g_return_val_if_fail(wifi != NULL, TRUE);
+
+       DBG("Try to remove connman Wi-Fi config files...");
+
+       if ((dir_ptr = opendir(CONNMAN_STORAGE)) != NULL) {
+               while ((file = readdir(dir_ptr)) != NULL) {
+                       if (strncmp(file->d_name, ".", 1) == 0 || strncmp(file->d_name, "..", 2) == 0 ||
+                                       strncmp(file->d_name, WIFI_CONFIG_PREFIX, strlen(WIFI_CONFIG_PREFIX)) != 0) {
+                               continue;
+                       }
+
+                       snprintf(dir_name, 512, CONNMAN_STORAGE"/%s", file->d_name);
+
+                       if (lstat(dir_name, &buf) == -1)
+                               continue;
+
+                       DBG("Remove wifi config: %s", file->d_name);
+
+                       if (S_ISDIR(buf.st_mode)) {
+                               memset(file_name, 0, 1024);
+                               snprintf(file_name, 1024, "%s/data", dir_name);
+                               unlink(file_name);
+                               memset(file_name, 0, 1024);
+                               snprintf(file_name, 1024, "%s/settings", dir_name);
+                               unlink(file_name);
+                       }
+                       rmdir(dir_name);
+               }
+
+               closedir(dir_ptr);
+               sync();
+       }
+
+       wifi_complete_reset_wifi_config(wifi, context);
+
+       return TRUE;
+}
+
 /* config field key / value */
 /*
  * [wifi_macaddress_config_id]
@@ -1733,7 +1937,7 @@ gboolean handle_remove_configuration(Wifi *wifi, GDBusMethodInvocation *context,
  * Proxy.Servers=trst.com:8888; (O)
  */
 gboolean handle_set_config_field(Wifi *wifi, GDBusMethodInvocation *context,
-               const gchar *config_id, const gchar *key, const gchar *value)
+               const gchar *ifname, const gchar *config_id, const gchar *key, const gchar *value)
 {
        gboolean ret = FALSE;
        gchar *keyfile_key = NULL;
@@ -1745,7 +1949,7 @@ gboolean handle_set_config_field(Wifi *wifi, GDBusMethodInvocation *context,
        DBG("Key[%s] Value[%s]", key, value);
 
        if (g_strcmp0(key, WIFI_CONFIG_PROXYADDRESS) == 0) {
-               ret = _set_field(config_id, WIFI_CONFIG_PROXY_METHOD, "manual");
+               ret = _set_field(ifname, config_id, WIFI_CONFIG_PROXY_METHOD, "manual");
                if (!ret) {
                        ERR("Fail to [%s]set_wifi_config_field(%s/manual)", config_id, WIFI_CONFIG_PROXY_METHOD);
                        netconfig_error_invalid_parameter(context);
@@ -1776,7 +1980,7 @@ gboolean handle_set_config_field(Wifi *wifi, GDBusMethodInvocation *context,
                return TRUE;
        }
 
-       ret = _set_field(config_id, keyfile_key, (const gchar *)value);
+       ret = _set_field(ifname, config_id, keyfile_key, (const gchar *)value);
        if (!ret) {
                ERR("Fail to [%s]set_wifi_config_field(%s/%s)", config_id, key, value);
        }
@@ -1788,18 +1992,19 @@ gboolean handle_set_config_field(Wifi *wifi, GDBusMethodInvocation *context,
        return TRUE;
 }
 
-gboolean handle_get_config_passphrase(Wifi *wifi, GDBusMethodInvocation *context, const gchar *config_id)
+gboolean handle_get_config_passphrase(Wifi *wifi, GDBusMethodInvocation *context,
+                       const gchar *ifname, const gchar *config_id)
 {
        gboolean ret = FALSE;
        gchar *passphrase = NULL;
 
-       if ((wifi == NULL) || (config_id == NULL)) {
+       if ((wifi == NULL) || (ifname == NULL) || (config_id == NULL)) {
                ERR("Invalid parameter");
                netconfig_error_invalid_parameter(context);
                return TRUE;
        }
 
-       ret = _get_field(config_id, WIFI_CONFIG_PASSPHRASE, &passphrase);
+       ret = _get_field(ifname, config_id, WIFI_CONFIG_PASSPHRASE, &passphrase);
        if (!ret) {
                ERR("Fail to [%s] _get_field(%s)", config_id, WIFI_CONFIG_PASSPHRASE);
                netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "OperationFailed");
@@ -1813,7 +2018,7 @@ gboolean handle_get_config_passphrase(Wifi *wifi, GDBusMethodInvocation *context
 }
 
 gboolean handle_add_vsie(Wifi *wifi, GDBusMethodInvocation *context,
-               int frame_id, const gchar *vsie)
+               const gchar *ifname, int frame_id, const gchar *vsie)
 {
        DBG("Frame ID: [%d] VSIE: [%s]", frame_id, vsie);
 
@@ -1822,7 +2027,7 @@ gboolean handle_add_vsie(Wifi *wifi, GDBusMethodInvocation *context,
 
        gboolean ret = FALSE;
 
-       ret = _add_vsie(frame_id, vsie);
+       ret = _add_vsie(ifname, frame_id, vsie);
        if (!ret) {
                DBG("Failed to add vsie: %s", vsie);
                netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "OperationFailed");
@@ -1834,7 +2039,7 @@ gboolean handle_add_vsie(Wifi *wifi, GDBusMethodInvocation *context,
 }
 
 gboolean handle_get_vsie(Wifi *wifi, GDBusMethodInvocation *context,
-               int frame_id)
+               const gchar *ifname, int frame_id)
 {
        DBG("Frame ID: [%d]", frame_id);
 
@@ -1843,7 +2048,7 @@ gboolean handle_get_vsie(Wifi *wifi, GDBusMethodInvocation *context,
        gboolean ret = FALSE;
        gchar *vsie = NULL;
 
-       ret = _get_vsie(frame_id, &vsie);
+       ret = _get_vsie(ifname, frame_id, &vsie);
        if (!ret) {
                DBG("Failed to get vsie for frame:[%d]", frame_id);
                netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "OperationFailed");
@@ -1857,7 +2062,7 @@ gboolean handle_get_vsie(Wifi *wifi, GDBusMethodInvocation *context,
 }
 
 gboolean handle_remove_vsie(Wifi *wifi, GDBusMethodInvocation *context,
-               int frame_id, const gchar *vsie)
+               const gchar *ifname, int frame_id, const gchar *vsie)
 {
        DBG("Frame ID: [%d] VSIE: [%s]", frame_id, vsie);
 
@@ -1866,7 +2071,7 @@ gboolean handle_remove_vsie(Wifi *wifi, GDBusMethodInvocation *context,
 
        gboolean ret = FALSE;
 
-       ret = _remove_vsie(frame_id, vsie);
+       ret = _remove_vsie(ifname, frame_id, vsie);
        if (!ret) {
                DBG("Failed to remove vsie: %s", vsie);
                netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "OperationFailed");