Merge tag 'upstream/1.40' into tizen.
[platform/upstream/connman.git] / src / ipconfig.c
index 46239fe..4a0e4ad 100755 (executable)
@@ -48,11 +48,14 @@ struct connman_ipconfig {
        const struct connman_ipconfig_ops *ops;
        void *ops_data;
 
-       bool enabled;
        enum connman_ipconfig_method method;
        struct connman_ipaddress *address;
        struct connman_ipaddress *system;
 
+#if defined TIZEN_EXT
+       int dhcp_lease_duration;
+#endif
+
        int ipv6_privacy_config;
        char *last_dhcp_address;
        char **last_dhcpv6_prefixes;
@@ -86,16 +89,101 @@ struct connman_ipdevice {
        int ipv6_privacy;
 };
 
+struct ipconfig_store {
+       GKeyFile *file;
+       const char *group;
+       const char *prefix;
+};
+
 static GHashTable *ipdevice_hash = NULL;
 static GList *ipconfig_list = NULL;
 static bool is_ipv6_supported = false;
 
-void __connman_ipconfig_clear_address(struct connman_ipconfig *ipconfig)
+static void store_set_str(struct ipconfig_store *store,
+                       const char *key, const char *val)
+
 {
-       if (!ipconfig)
+       char *pk;
+
+       if (!val || strlen(val) == 0)
+               return;
+
+       pk = g_strdup_printf("%s%s", store->prefix, key);
+       g_key_file_set_string(store->file, store->group, pk, val);
+       g_free(pk);
+}
+
+static char *store_get_str(struct ipconfig_store *store, const char *key)
+{
+       char *pk, *val;
+
+       pk = g_strdup_printf("%s%s", store->prefix, key);
+       val = g_key_file_get_string(store->file, store->group, pk, NULL);
+       g_free(pk);
+
+       return val;
+}
+
+static void store_set_strs(struct ipconfig_store *store,
+                       const char *key, char **val)
+{
+       guint len;
+       char *pk;
+
+       if (!val)
+               return;
+
+       len = g_strv_length(val);
+       if (len == 0)
+               return;
+
+       pk = g_strdup_printf("%s%s", store->prefix, key);
+       g_key_file_set_string_list(store->file, store->group,
+                               pk, (const gchar **)val, len);
+       g_free(pk);
+}
+
+static char **store_get_strs(struct ipconfig_store *store, const char *key)
+{
+       gsize len;
+       char *pk, **val;
+
+       pk = g_strdup_printf("%s%s", store->prefix, key);
+       val = g_key_file_get_string_list(store->file, store->group,
+                                       pk, &len, NULL);
+       g_free(pk);
+
+       if (val && len == 0) {
+               g_free(val);
+               return NULL;
+       }
+
+       return val;
+}
+
+static void store_set_int(struct ipconfig_store *store,
+                       const char *key, int val)
+{
+       char *pk;
+
+       if (val == 0)
                return;
 
-       connman_ipaddress_clear(ipconfig->address);
+       pk = g_strdup_printf("%s%s", store->prefix, key);
+       g_key_file_set_integer(store->file, store->group, pk, val);
+       g_free(pk);
+}
+
+static int store_get_int(struct ipconfig_store *store, const char *key)
+{
+       int val;
+       char *pk;
+
+       pk = g_strdup_printf("%s%s", store->prefix, key);
+       val = g_key_file_get_integer(store->file, store->group, pk, 0);
+       g_free(pk);
+
+       return val;
 }
 
 static void free_address_list(struct connman_ipdevice *ipdevice)
@@ -174,153 +262,165 @@ static const char *scope2str(unsigned char scope)
        return "";
 }
 
-static bool get_ipv6_state(gchar *ifname)
+#define PROC_IPV4_CONF_PREFIX "/proc/sys/net/ipv4/conf"
+#define PROC_IPV6_CONF_PREFIX "/proc/sys/net/ipv6/conf"
+
+static int read_conf_value(const char *prefix, const char *ifname,
+                                       const char *suffix, int *value)
 {
-       int disabled;
        gchar *path;
        FILE *f;
-       bool enabled = false;
-
-       if (!ifname)
-               path = g_strdup("/proc/sys/net/ipv6/conf/all/disable_ipv6");
-       else
-               path = g_strdup_printf(
-                       "/proc/sys/net/ipv6/conf/%s/disable_ipv6", ifname);
+       int err;
 
+       path = g_build_filename(prefix, ifname ? ifname : "all", suffix, NULL);
        if (!path)
-               return enabled;
+               return -ENOMEM;
 
+       errno = 0;
        f = fopen(path, "r");
+       if (!f) {
+               err = -errno;
+       } else {
+               errno = 0; /* Avoid stale errno values with fscanf */
 
-       g_free(path);
+               err = fscanf(f, "%d", value);
+               if (err <= 0 && errno)
+                       err = -errno;
 
-       if (f) {
-               if (fscanf(f, "%d", &disabled) > 0)
-                       enabled = !disabled;
                fclose(f);
        }
 
-       return enabled;
+       if (err <= 0)
+               connman_error("failed to read %s", path);
+
+       g_free(path);
+
+       return err;
+}
+
+static int read_ipv4_conf_value(const char *ifname, const char *suffix,
+                                                               int *value)
+{
+       return read_conf_value(PROC_IPV4_CONF_PREFIX, ifname, suffix, value);
 }
 
-static void set_ipv6_state(gchar *ifname, bool enable)
+static int read_ipv6_conf_value(const char *ifname, const char *suffix,
+                                                               int *value)
 {
+       return read_conf_value(PROC_IPV6_CONF_PREFIX, ifname, suffix, value);
+}
+
+static int write_conf_value(const char *prefix, const char *ifname,
+                                       const char *suffix, int value) {
        gchar *path;
        FILE *f;
+       int rval;
 
-       if (!ifname)
-               path = g_strdup("/proc/sys/net/ipv6/conf/all/disable_ipv6");
-       else
-               path = g_strdup_printf(
-                       "/proc/sys/net/ipv6/conf/%s/disable_ipv6", ifname);
-
+       path = g_build_filename(prefix, ifname ? ifname : "all", suffix, NULL);
        if (!path)
-               return;
+               return -ENOMEM;
 
        f = fopen(path, "r+");
+       if (!f) {
+               rval = -errno;
+       } else {
+               rval = fprintf(f, "%d", value);
+               fclose(f);
+       }
+
+       if (rval <= 0)
+               connman_error("failed to set %s value %d", path, value);
 
        g_free(path);
 
-       if (!f)
-               return;
+       return rval;
+}
 
-       if (!enable)
-               fprintf(f, "1");
-       else
-               fprintf(f, "0");
+static int write_ipv4_conf_value(const char *ifname, const char *suffix,
+                                                               int value)
+{
+       return write_conf_value(PROC_IPV4_CONF_PREFIX, ifname, suffix, value);
+}
 
-       fclose(f);
+static int write_ipv6_conf_value(const char *ifname, const char *suffix,
+                                                               int value)
+{
+       return write_conf_value(PROC_IPV6_CONF_PREFIX, ifname, suffix, value);
 }
 
-static int get_ipv6_privacy(gchar *ifname)
+static bool get_ipv6_state(gchar *ifname)
 {
-       gchar *path;
-       FILE *f;
-       int value;
+       int disabled;
+       bool enabled = false;
 
-       if (!ifname)
-               return 0;
+       if (read_ipv6_conf_value(ifname, "disable_ipv6", &disabled) > 0)
+               enabled = !disabled;
 
-       path = g_strdup_printf("/proc/sys/net/ipv6/conf/%s/use_tempaddr",
-                                                               ifname);
+       return enabled;
+}
 
-       if (!path)
-               return 0;
+static int set_ipv6_state(gchar *ifname, bool enable)
+{
+       int disabled = enable ? 0 : 1;
 
-       f = fopen(path, "r");
+       DBG("%s %d", ifname, disabled);
 
-       g_free(path);
+       return write_ipv6_conf_value(ifname, "disable_ipv6", disabled);
+}
 
-       if (!f)
+static int get_ipv6_privacy(gchar *ifname)
+{
+       int value;
+
+       if (!ifname)
                return 0;
 
-       if (fscanf(f, "%d", &value) <= 0)
+       if (read_ipv6_conf_value(ifname, "use_tempaddr", &value) < 0)
                value = 0;
 
-       fclose(f);
-
        return value;
 }
 
 /* Enable the IPv6 privacy extension for stateless address autoconfiguration.
  * The privacy extension is described in RFC 3041 and RFC 4941
  */
-static void set_ipv6_privacy(gchar *ifname, int value)
+static int set_ipv6_privacy(gchar *ifname, int value)
 {
-       gchar *path;
-       FILE *f;
-
        if (!ifname)
-               return;
-
-       path = g_strdup_printf("/proc/sys/net/ipv6/conf/%s/use_tempaddr",
-                                                               ifname);
-
-       if (!path)
-               return;
+               return -EINVAL;
 
        if (value < 0)
                value = 0;
 
-       f = fopen(path, "r+");
-
-       g_free(path);
-
-       if (!f)
-               return;
-
-       fprintf(f, "%d", value);
-       fclose(f);
+       return write_ipv6_conf_value(ifname, "use_tempaddr", value);
 }
 
 static int get_rp_filter(void)
 {
-       FILE *f;
-       int value = -EINVAL, tmp;
-
-       f = fopen("/proc/sys/net/ipv4/conf/all/rp_filter", "r");
+       int value;
 
-       if (f) {
-               if (fscanf(f, "%d", &tmp) == 1)
-                       value = tmp;
-               fclose(f);
-       }
+       if (read_ipv4_conf_value(NULL, "rp_filter", &value) < 0)
+               value = -EINVAL;
 
        return value;
 }
 
-static void set_rp_filter(int value)
+static int set_rp_filter(int value)
 {
-       FILE *f;
-
-       f = fopen("/proc/sys/net/ipv4/conf/all/rp_filter", "r+");
-
-       if (!f)
-               return;
-
-       fprintf(f, "%d", value);
+       /* 0 = no validation, 1 = strict mode, 2 = loose mode */
+       switch (value) {
+       case -1:
+               value = 0;
+               /* fall through */
+       case 0:
+       case 1:
+       case 2:
+               break;
+       default:
+               return -EINVAL;
+       }
 
-       fclose(f);
+       return write_ipv4_conf_value(NULL, "rp_filter", value);
 }
 
 int __connman_ipconfig_set_rp_filter()
@@ -400,47 +500,15 @@ static void free_ipdevice(gpointer data)
 
        g_free(ipdevice->address);
 
-       set_ipv6_state(ifname, ipdevice->ipv6_enabled);
-       set_ipv6_privacy(ifname, ipdevice->ipv6_privacy);
+       if (ifname) {
+               set_ipv6_state(ifname, ipdevice->ipv6_enabled);
+               set_ipv6_privacy(ifname, ipdevice->ipv6_privacy);
+       }
 
        g_free(ifname);
        g_free(ipdevice);
 }
 
-static void __connman_ipconfig_lower_up(struct connman_ipdevice *ipdevice)
-{
-       DBG("ipconfig ipv4 %p ipv6 %p", ipdevice->config_ipv4,
-                       ipdevice->config_ipv6);
-#if defined TIZEN_EXT
-       if (ipdevice->config_ipv6 != NULL &&
-                       ipdevice->config_ipv6->enabled == TRUE)
-               return;
-
-       char *ifname = connman_inet_ifname(ipdevice->index);
-
-       if (__connman_device_isfiltered(ifname) == FALSE) {
-               ipdevice->ipv6_enabled = get_ipv6_state(ifname);
-               set_ipv6_state(ifname, FALSE);
-       }
-       g_free(ifname);
-#endif
-}
-
-static void __connman_ipconfig_lower_down(struct connman_ipdevice *ipdevice)
-{
-       DBG("ipconfig ipv4 %p ipv6 %p", ipdevice->config_ipv4,
-                                       ipdevice->config_ipv6);
-
-       if (ipdevice->config_ipv4)
-               connman_inet_clear_address(ipdevice->index,
-                                       ipdevice->config_ipv4->address);
-
-       if (ipdevice->config_ipv6)
-               connman_inet_clear_ipv6_address(ipdevice->index,
-                               ipdevice->config_ipv6->address->local,
-                               ipdevice->config_ipv6->address->prefixlen);
-}
-
 static void update_stats(struct connman_ipdevice *ipdevice,
                        const char *ifname, struct rtnl_link_stats *stats)
 {
@@ -600,11 +668,6 @@ update:
 
        g_list_free(ipconfig_copy);
 
-       if (lower_up)
-               __connman_ipconfig_lower_up(ipdevice);
-       if (lower_down)
-               __connman_ipconfig_lower_down(ipdevice);
-
 out:
        g_free(ifname);
 }
@@ -645,8 +708,6 @@ void __connman_ipconfig_dellink(int index, struct rtnl_link_stats *stats)
 
        g_free(ifname);
 
-       __connman_ipconfig_lower_down(ipdevice);
-
        g_hash_table_remove(ipdevice_hash, GINT_TO_POINTER(index));
 }
 
@@ -661,6 +722,25 @@ static inline gint check_duplicate_address(gconstpointer a, gconstpointer b)
        return g_strcmp0(addr1->local, addr2->local);
 }
 
+static bool is_index_p2p_service(int index)
+{
+       struct connman_service *service;
+       enum connman_service_type type;
+
+       service = __connman_service_lookup_from_index(index);
+       if (!service)
+               return false;
+
+       type = connman_service_get_type(service);
+       switch (type) {
+       case CONNMAN_SERVICE_TYPE_P2P:
+       case CONNMAN_SERVICE_TYPE_VPN:
+               return true;
+       default:
+               return false;
+       }
+}
+
 int __connman_ipconfig_newaddr(int index, int family, const char *label,
                                unsigned char prefixlen, const char *address)
 {
@@ -683,6 +763,9 @@ int __connman_ipconfig_newaddr(int index, int family, const char *label,
        ipaddress->prefixlen = prefixlen;
        ipaddress->local = g_strdup(address);
 
+       if (is_index_p2p_service(index))
+               connman_ipaddress_set_p2p(ipaddress, true);
+
        if (g_slist_find_custom(ipdevice->address_list, ipaddress,
                                        check_duplicate_address)) {
                connman_ipaddress_free(ipaddress);
@@ -1098,6 +1181,14 @@ void __connman_ipconfig_set_gateway(struct connman_ipconfig *ipconfig,
 }
 
 #if defined TIZEN_EXT
+void __connman_ipconfig_set_dhcp_lease_duration(struct connman_ipconfig *ipconfig,
+               int dhcp_lease_duration)
+{
+       ipconfig->dhcp_lease_duration = dhcp_lease_duration;
+}
+#endif
+
+#if defined TIZEN_EXT
 int __connman_ipconfig_gateway_add(struct connman_ipconfig *ipconfig, struct connman_service *service)
 #else
 int __connman_ipconfig_gateway_add(struct connman_ipconfig *ipconfig)
@@ -1159,13 +1250,20 @@ void __connman_ipconfig_set_prefixlen(struct connman_ipconfig *ipconfig,
        ipconfig->address->prefixlen = prefixlen;
 }
 
+static void ipconfig_set_p2p(int index, struct connman_ipconfig *ipconfig)
+{
+       if (!is_index_p2p_service(index))
+               return;
+
+       connman_ipaddress_set_p2p(ipconfig->address, true);
+       connman_ipaddress_set_p2p(ipconfig->system, true);
+}
+
 static struct connman_ipconfig *create_ipv6config(int index)
 {
        struct connman_ipconfig *ipv6config;
        struct connman_ipdevice *ipdevice;
 
-       DBG("index %d", index);
-
        ipv6config = g_try_new0(struct connman_ipconfig, 1);
        if (!ipv6config)
                return NULL;
@@ -1173,7 +1271,6 @@ static struct connman_ipconfig *create_ipv6config(int index)
        ipv6config->refcount = 1;
 
        ipv6config->index = index;
-       ipv6config->enabled = false;
        ipv6config->type = CONNMAN_IPCONFIG_TYPE_IPV6;
 
        if (!is_ipv6_supported)
@@ -1183,7 +1280,11 @@ static struct connman_ipconfig *create_ipv6config(int index)
 
        ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
        if (ipdevice)
+#if !defined TIZEN_EXT
                ipv6config->ipv6_privacy_config = ipdevice->ipv6_privacy;
+#else
+               ipv6config->ipv6_privacy_config = ipdevice->ipv6_privacy = 2;
+#endif
 
        ipv6config->address = connman_ipaddress_alloc(AF_INET6);
        if (!ipv6config->address) {
@@ -1193,7 +1294,9 @@ static struct connman_ipconfig *create_ipv6config(int index)
 
        ipv6config->system = connman_ipaddress_alloc(AF_INET6);
 
-       DBG("ipconfig %p method %s", ipv6config,
+       ipconfig_set_p2p(index, ipv6config);
+
+       DBG("ipconfig %p index %d method %s", ipv6config, index,
                __connman_ipconfig_method2string(ipv6config->method));
 
        return ipv6config;
@@ -1214,8 +1317,6 @@ struct connman_ipconfig *__connman_ipconfig_create(int index,
        if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
                return create_ipv6config(index);
 
-       DBG("index %d", index);
-
        ipconfig = g_try_new0(struct connman_ipconfig, 1);
        if (!ipconfig)
                return NULL;
@@ -1223,7 +1324,6 @@ struct connman_ipconfig *__connman_ipconfig_create(int index,
        ipconfig->refcount = 1;
 
        ipconfig->index = index;
-       ipconfig->enabled = false;
        ipconfig->type = CONNMAN_IPCONFIG_TYPE_IPV4;
 
        ipconfig->address = connman_ipaddress_alloc(AF_INET);
@@ -1234,7 +1334,12 @@ struct connman_ipconfig *__connman_ipconfig_create(int index,
 
        ipconfig->system = connman_ipaddress_alloc(AF_INET);
 
-       DBG("ipconfig %p", ipconfig);
+       ipconfig_set_p2p(index, ipconfig);
+
+#if defined TIZEN_EXT
+       if (!simplified_log)
+#endif
+       DBG("ipconfig %p index %d", ipconfig, index);
 
        return ipconfig;
 }
@@ -1269,7 +1374,9 @@ void __connman_ipconfig_unref_debug(struct connman_ipconfig *ipconfig,
 {
        if (!ipconfig)
                return;
-
+#if defined TIZEN_EXT
+       if (!simplified_log)
+#endif
        DBG("%p ref %d by %s:%d:%s()", ipconfig, ipconfig->refcount - 1,
                file, line, caller);
 
@@ -1367,8 +1474,6 @@ enum connman_ipconfig_method __connman_ipconfig_get_method(
 
 int __connman_ipconfig_address_add(struct connman_ipconfig *ipconfig)
 {
-       DBG("");
-
        switch (ipconfig->method) {
        case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
        case CONNMAN_IPCONFIG_METHOD_OFF:
@@ -1392,25 +1497,22 @@ int __connman_ipconfig_address_remove(struct connman_ipconfig *ipconfig)
 {
        int err;
 
-       DBG("");
-
        if (!ipconfig)
                return 0;
 
-       DBG("method %d", ipconfig->method);
-
        switch (ipconfig->method) {
        case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
        case CONNMAN_IPCONFIG_METHOD_OFF:
                break;
        case CONNMAN_IPCONFIG_METHOD_AUTO:
-       case CONNMAN_IPCONFIG_METHOD_FIXED:
        case CONNMAN_IPCONFIG_METHOD_DHCP:
-       case CONNMAN_IPCONFIG_METHOD_MANUAL:
                err = __connman_ipconfig_address_unset(ipconfig);
                connman_ipaddress_clear(ipconfig->address);
 
                return err;
+       case CONNMAN_IPCONFIG_METHOD_FIXED:
+       case CONNMAN_IPCONFIG_METHOD_MANUAL:
+               return __connman_ipconfig_address_unset(ipconfig);
        }
 
        return 0;
@@ -1420,12 +1522,14 @@ int __connman_ipconfig_address_unset(struct connman_ipconfig *ipconfig)
 {
        int err;
 
-       DBG("");
-
        if (!ipconfig)
                return 0;
 
+#if defined TIZEN_EXT
+       DBG("ipconfig method %d type %d", ipconfig->method, ipconfig->type);
+#else
        DBG("method %d", ipconfig->method);
+#endif
 
        switch (ipconfig->method) {
        case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
@@ -1439,10 +1543,8 @@ int __connman_ipconfig_address_unset(struct connman_ipconfig *ipconfig)
                        err = connman_inet_clear_address(ipconfig->index,
                                                        ipconfig->address);
                else if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6)
-                       err = connman_inet_clear_ipv6_address(
-                                               ipconfig->index,
-                                               ipconfig->address->local,
-                                               ipconfig->address->prefixlen);
+                       err = connman_inet_clear_ipv6_address(ipconfig->index,
+                                                       ipconfig->address);
                else
                        err = -EINVAL;
 
@@ -1457,8 +1559,6 @@ int __connman_ipconfig_set_proxy_autoconfig(struct connman_ipconfig *ipconfig,
 {
        struct connman_ipdevice *ipdevice;
 
-       DBG("ipconfig %p", ipconfig);
-
        if (!ipconfig || ipconfig->index < 0)
                return -ENODEV;
 
@@ -1477,8 +1577,6 @@ const char *__connman_ipconfig_get_proxy_autoconfig(struct connman_ipconfig *ipc
 {
        struct connman_ipdevice *ipdevice;
 
-       DBG("ipconfig %p", ipconfig);
-
        if (!ipconfig || ipconfig->index < 0)
                return NULL;
 
@@ -1631,8 +1729,6 @@ int __connman_ipconfig_enable(struct connman_ipconfig *ipconfig)
        } else
                return -EINVAL;
 
-       ipconfig->enabled = true;
-
        if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
                                        ipdevice->config_ipv4) {
                ipconfig_list = g_list_remove(ipconfig_list,
@@ -1641,6 +1737,9 @@ int __connman_ipconfig_enable(struct connman_ipconfig *ipconfig)
                connman_ipaddress_clear(ipdevice->config_ipv4->system);
 
                __connman_ipconfig_unref(ipdevice->config_ipv4);
+
+               g_free(ipdevice->ipv4_gateway);
+               ipdevice->ipv4_gateway = NULL;
        }
 
        if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
@@ -1651,6 +1750,9 @@ int __connman_ipconfig_enable(struct connman_ipconfig *ipconfig)
                connman_ipaddress_clear(ipdevice->config_ipv6->system);
 
                __connman_ipconfig_unref(ipdevice->config_ipv6);
+
+               g_free(ipdevice->ipv6_gateway);
+               ipdevice->ipv6_gateway = NULL;
        }
 
        if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
@@ -1693,7 +1795,9 @@ int __connman_ipconfig_enable(struct connman_ipconfig *ipconfig)
 int __connman_ipconfig_disable(struct connman_ipconfig *ipconfig)
 {
        struct connman_ipdevice *ipdevice;
-
+#if defined TIZEN_EXT
+       if (!simplified_log)
+#endif
        DBG("ipconfig %p", ipconfig);
 
        if (!ipconfig || ipconfig->index < 0)
@@ -1707,14 +1811,16 @@ int __connman_ipconfig_disable(struct connman_ipconfig *ipconfig)
        if (!ipdevice->config_ipv4 && !ipdevice->config_ipv6)
                return -EINVAL;
 
-       ipconfig->enabled = false;
-
        if (ipdevice->config_ipv4 == ipconfig) {
                ipconfig_list = g_list_remove(ipconfig_list, ipconfig);
 
                connman_ipaddress_clear(ipdevice->config_ipv4->system);
                __connman_ipconfig_unref(ipdevice->config_ipv4);
                ipdevice->config_ipv4 = NULL;
+
+               g_free(ipdevice->ipv4_gateway);
+               ipdevice->ipv4_gateway = NULL;
+
                return 0;
        }
 
@@ -1723,12 +1829,18 @@ int __connman_ipconfig_disable(struct connman_ipconfig *ipconfig)
 
 #if defined TIZEN_EXT
                if (ipdevice->config_ipv6->method ==
-                               CONNMAN_IPCONFIG_METHOD_AUTO)
+                               CONNMAN_IPCONFIG_METHOD_AUTO) {
                        disable_ipv6(ipdevice->config_ipv6);
+                       enable_ipv6(ipdevice->config_ipv6);
+               }
 #endif
                connman_ipaddress_clear(ipdevice->config_ipv6->system);
                __connman_ipconfig_unref(ipdevice->config_ipv6);
                ipdevice->config_ipv6 = NULL;
+
+               g_free(ipdevice->ipv6_gateway);
+               ipdevice->ipv6_gateway = NULL;
+
                return 0;
        }
 
@@ -1822,8 +1934,6 @@ int __connman_ipconfig_ipv6_set_privacy(struct connman_ipconfig *ipconfig,
        if (!ipconfig)
                return -EINVAL;
 
-       DBG("ipconfig %p privacy %s", ipconfig, value);
-
        privacy = string2privacy(value);
 
        ipconfig->ipv6_privacy_config = privacy;
@@ -1851,13 +1961,13 @@ void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
        switch (ipconfig->method) {
        case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
        case CONNMAN_IPCONFIG_METHOD_OFF:
-       case CONNMAN_IPCONFIG_METHOD_AUTO:
                return;
 
        case CONNMAN_IPCONFIG_METHOD_FIXED:
                append_addr = ipconfig->address;
                break;
 
+       case CONNMAN_IPCONFIG_METHOD_AUTO:
        case CONNMAN_IPCONFIG_METHOD_MANUAL:
        case CONNMAN_IPCONFIG_METHOD_DHCP:
                append_addr = ipconfig->system;
@@ -1890,6 +2000,20 @@ void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
        if (append_addr->gateway)
                connman_dbus_dict_append_basic(iter, "Gateway",
                                DBUS_TYPE_STRING, &append_addr->gateway);
+
+#if defined TIZEN_EXT
+       if (ipconfig->method == CONNMAN_IPCONFIG_METHOD_DHCP) {
+               char *server_ip;
+               server_ip = __connman_dhcp_get_server_address(ipconfig);
+               if (server_ip) {
+                       connman_dbus_dict_append_basic(iter, "DHCPServerIP",
+                                       DBUS_TYPE_STRING, &server_ip);
+                       g_free(server_ip);
+               }
+               connman_dbus_dict_append_basic(iter, "DHCPLeaseDuration",
+                               DBUS_TYPE_INT32, &ipconfig->dhcp_lease_duration);
+       }
+#endif
 }
 
 void __connman_ipconfig_append_ipv6(struct connman_ipconfig *ipconfig,
@@ -2052,8 +2176,6 @@ int __connman_ipconfig_set_config(struct connman_ipconfig *ipconfig,
        DBusMessageIter dict;
        int type = -1;
 
-       DBG("ipconfig %p", ipconfig);
-
        if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
                return -EINVAL;
 
@@ -2137,6 +2259,7 @@ int __connman_ipconfig_set_config(struct connman_ipconfig *ipconfig,
                if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6)
                        disable_ipv6(ipconfig);
 #endif
+
                break;
 
        case CONNMAN_IPCONFIG_METHOD_AUTO:
@@ -2149,6 +2272,7 @@ int __connman_ipconfig_set_config(struct connman_ipconfig *ipconfig,
 #if defined TIZEN_EXT
                enable_ipv6(ipconfig);
 #endif
+
                break;
 
        case CONNMAN_IPCONFIG_METHOD_MANUAL:
@@ -2230,65 +2354,56 @@ void __connman_ipconfig_append_ethernet(struct connman_ipconfig *ipconfig,
                                        DBUS_TYPE_UINT16, &ipdevice->mtu);
 }
 
-int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
+void __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
                GKeyFile *keyfile, const char *identifier, const char *prefix)
 {
        char *method;
-       char *key;
        char *str;
+       struct ipconfig_store is = { .file = keyfile,
+                                    .group = identifier,
+                                    .prefix = prefix };
 
        DBG("ipconfig %p identifier %s", ipconfig, identifier);
 
-       key = g_strdup_printf("%smethod", prefix);
-       method = g_key_file_get_string(keyfile, identifier, key, NULL);
+       method = store_get_str(&is, "method");
        if (!method) {
                switch (ipconfig->type) {
                case CONNMAN_IPCONFIG_TYPE_IPV4:
                        ipconfig->method = CONNMAN_IPCONFIG_METHOD_DHCP;
                        break;
+
                case CONNMAN_IPCONFIG_TYPE_IPV6:
                        ipconfig->method = CONNMAN_IPCONFIG_METHOD_AUTO;
                        break;
+
                case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
                case CONNMAN_IPCONFIG_TYPE_ALL:
                        ipconfig->method = CONNMAN_IPCONFIG_METHOD_OFF;
                        break;
                }
-       } else
+       } else {
                ipconfig->method = __connman_ipconfig_string2method(method);
+               g_free(method);
+       }
 
        if (ipconfig->method == CONNMAN_IPCONFIG_METHOD_UNKNOWN)
                ipconfig->method = CONNMAN_IPCONFIG_METHOD_OFF;
 
        if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6) {
-               gsize length;
-               char *pprefix;
-
                if (ipconfig->method == CONNMAN_IPCONFIG_METHOD_AUTO ||
-                       ipconfig->method == CONNMAN_IPCONFIG_METHOD_MANUAL) {
+                               ipconfig->method == CONNMAN_IPCONFIG_METHOD_MANUAL) {
                        char *privacy;
 
-                       pprefix = g_strdup_printf("%sprivacy", prefix);
-                       privacy = g_key_file_get_string(keyfile, identifier,
-                                                       pprefix, NULL);
+                       privacy = store_get_str(&is, "privacy");
                        ipconfig->ipv6_privacy_config = string2privacy(privacy);
-                       g_free(pprefix);
                        g_free(privacy);
                }
 
-               pprefix = g_strdup_printf("%sDHCP.LastPrefixes", prefix);
+               g_strfreev(ipconfig->last_dhcpv6_prefixes);
                ipconfig->last_dhcpv6_prefixes =
-                       g_key_file_get_string_list(keyfile, identifier, pprefix,
-                                               &length, NULL);
-               if (ipconfig->last_dhcpv6_prefixes && length == 0) {
-                       g_free(ipconfig->last_dhcpv6_prefixes);
-                       ipconfig->last_dhcpv6_prefixes = NULL;
-               }
-               g_free(pprefix);
+                       store_get_strs(&is, "DHCP.LastPrefixes");
        }
 
-       g_free(method);
-       g_free(key);
 
        switch (ipconfig->method) {
        case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
@@ -2297,153 +2412,95 @@ int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
 
        case CONNMAN_IPCONFIG_METHOD_FIXED:
        case CONNMAN_IPCONFIG_METHOD_MANUAL:
+               ipconfig->address->prefixlen =
+                       store_get_int(&is, "netmask_prefixlen");
 
-               key = g_strdup_printf("%snetmask_prefixlen", prefix);
-               ipconfig->address->prefixlen = g_key_file_get_integer(
-                               keyfile, identifier, key, NULL);
-               g_free(key);
-
-               key = g_strdup_printf("%slocal_address", prefix);
                g_free(ipconfig->address->local);
-               ipconfig->address->local = g_key_file_get_string(
-                       keyfile, identifier, key, NULL);
-               g_free(key);
+               ipconfig->address->local =
+                       store_get_str(&is, "local_address");
 
-               key = g_strdup_printf("%speer_address", prefix);
                g_free(ipconfig->address->peer);
-               ipconfig->address->peer = g_key_file_get_string(
-                               keyfile, identifier, key, NULL);
-               g_free(key);
+               ipconfig->address->peer =
+                       store_get_str(&is, "peer_address");
 
-               key = g_strdup_printf("%sbroadcast_address", prefix);
                g_free(ipconfig->address->broadcast);
-               ipconfig->address->broadcast = g_key_file_get_string(
-                               keyfile, identifier, key, NULL);
-               g_free(key);
+               ipconfig->address->broadcast =
+                       store_get_str(&is, "broadcast_address");
 
-               key = g_strdup_printf("%sgateway", prefix);
                g_free(ipconfig->address->gateway);
-               ipconfig->address->gateway = g_key_file_get_string(
-                               keyfile, identifier, key, NULL);
-               g_free(key);
+               ipconfig->address->gateway =
+                       store_get_str(&is, "gateway");
                break;
 
-       case CONNMAN_IPCONFIG_METHOD_DHCP:
+       case CONNMAN_IPCONFIG_METHOD_AUTO:
+               if (ipconfig->type != CONNMAN_IPCONFIG_TYPE_IPV4)
+                       break;
+
+               /*
+                * If the last used method for IPv4 was AUTO then we
+                * try first DHCP. We will try also to use the last
+                * used DHCP address, if exits.
+                */
+               __connman_ipconfig_set_method(ipconfig,
+                                       CONNMAN_IPCONFIG_METHOD_DHCP);
+               /* fall through */
 
-               key = g_strdup_printf("%sDHCP.LastAddress", prefix);
-               str = g_key_file_get_string(keyfile, identifier, key, NULL);
+       case CONNMAN_IPCONFIG_METHOD_DHCP:
+               str = store_get_str(&is, "DHCP.LastAddress");
                if (str) {
                        g_free(ipconfig->last_dhcp_address);
                        ipconfig->last_dhcp_address = str;
                }
-               g_free(key);
-
-               break;
 
-       case CONNMAN_IPCONFIG_METHOD_AUTO:
                break;
        }
-
-       return 0;
 }
 
-int __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
+void __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
                GKeyFile *keyfile, const char *identifier, const char *prefix)
 {
        const char *method;
-       char *key;
+       struct ipconfig_store is = { .file = keyfile,
+                                    .group = identifier,
+                                    .prefix = prefix };
 
        method = __connman_ipconfig_method2string(ipconfig->method);
-
        DBG("ipconfig %p identifier %s method %s", ipconfig, identifier,
                                                                method);
-       if (method) {
-               key = g_strdup_printf("%smethod", prefix);
-               g_key_file_set_string(keyfile, identifier, key, method);
-               g_free(key);
-       }
+       store_set_str(&is, "method", method);
 
        if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6) {
-               const char *privacy;
-               privacy = privacy2string(ipconfig->ipv6_privacy_config);
-               key = g_strdup_printf("%sprivacy", prefix);
-               g_key_file_set_string(keyfile, identifier, key, privacy);
-               g_free(key);
-
-               key = g_strdup_printf("%sDHCP.LastAddress", prefix);
-               if (ipconfig->last_dhcp_address &&
-                               strlen(ipconfig->last_dhcp_address) > 0)
-                       g_key_file_set_string(keyfile, identifier, key,
-                                       ipconfig->last_dhcp_address);
-               else
-                       g_key_file_remove_key(keyfile, identifier, key, NULL);
-               g_free(key);
-
-               key = g_strdup_printf("%sDHCP.LastPrefixes", prefix);
-               if (ipconfig->last_dhcpv6_prefixes &&
-                               ipconfig->last_dhcpv6_prefixes[0]) {
-                       guint len =
-                               g_strv_length(ipconfig->last_dhcpv6_prefixes);
-
-                       g_key_file_set_string_list(keyfile, identifier, key,
-                               (const gchar **)ipconfig->last_dhcpv6_prefixes,
-                                               len);
-               } else
-                       g_key_file_remove_key(keyfile, identifier, key, NULL);
-               g_free(key);
+               store_set_str(&is, "privacy",
+                               privacy2string(ipconfig->ipv6_privacy_config));
+
+               store_set_str(&is, "DHCP.LastAddress",
+                               ipconfig->last_dhcp_address);
+
+               store_set_strs(&is, "DHCP.LastPrefixes",
+                               ipconfig->last_dhcpv6_prefixes);
        }
 
        switch (ipconfig->method) {
        case CONNMAN_IPCONFIG_METHOD_FIXED:
        case CONNMAN_IPCONFIG_METHOD_MANUAL:
                break;
+
        case CONNMAN_IPCONFIG_METHOD_DHCP:
-               key = g_strdup_printf("%sDHCP.LastAddress", prefix);
-               if (ipconfig->last_dhcp_address &&
-                               strlen(ipconfig->last_dhcp_address) > 0)
-                       g_key_file_set_string(keyfile, identifier, key,
-                                       ipconfig->last_dhcp_address);
-               else
-                       g_key_file_remove_key(keyfile, identifier, key, NULL);
-               g_free(key);
+               store_set_str(&is, "DHCP.LastAddress",
+                               ipconfig->last_dhcp_address);
                /* fall through */
+
        case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
        case CONNMAN_IPCONFIG_METHOD_OFF:
        case CONNMAN_IPCONFIG_METHOD_AUTO:
-               return 0;
+               return;
        }
 
-       key = g_strdup_printf("%snetmask_prefixlen", prefix);
-       if (ipconfig->address->prefixlen != 0)
-               g_key_file_set_integer(keyfile, identifier,
-                               key, ipconfig->address->prefixlen);
-       g_free(key);
-
-       key = g_strdup_printf("%slocal_address", prefix);
-       if (ipconfig->address->local)
-               g_key_file_set_string(keyfile, identifier,
-                               key, ipconfig->address->local);
-       g_free(key);
-
-       key = g_strdup_printf("%speer_address", prefix);
-       if (ipconfig->address->peer)
-               g_key_file_set_string(keyfile, identifier,
-                               key, ipconfig->address->peer);
-       g_free(key);
-
-       key = g_strdup_printf("%sbroadcast_address", prefix);
-       if (ipconfig->address->broadcast)
-               g_key_file_set_string(keyfile, identifier,
-                       key, ipconfig->address->broadcast);
-       g_free(key);
-
-       key = g_strdup_printf("%sgateway", prefix);
-       if (ipconfig->address->gateway)
-               g_key_file_set_string(keyfile, identifier,
-                       key, ipconfig->address->gateway);
-       g_free(key);
-
-       return 0;
+       store_set_int(&is, "netmask_prefixlen", ipconfig->address->prefixlen);
+       store_set_str(&is, "local_address", ipconfig->address->local);
+       store_set_str(&is, "peer_address", ipconfig->address->peer);
+       store_set_str(&is, "broadcast_address", ipconfig->address->broadcast);
+       store_set_str(&is, "gateway", ipconfig->address->gateway);
 }
 
 int __connman_ipconfig_init(void)