--- src/ipconfig.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 109 insertions(+), 4 deletions(-)
diff --git a/src/ipconfig.c b/src/ipconfig.c index 1fb8281..481133b 100644 --- a/src/ipconfig.c +++ b/src/ipconfig.c @@ -51,6 +51,8 @@ struct connman_ipconfig { enum connman_ipconfig_method method; struct connman_ipaddress *address; struct connman_ipaddress *system; + + int ipv6_privacy; }; struct connman_ipdevice { @@ -79,6 +81,7 @@ struct connman_ipdevice { struct connman_ipconfig *config_ipv6; gboolean ipv6_enabled; + int ipv6_privacy; }; static GHashTable *ipdevice_hash = NULL; @@ -352,6 +355,67 @@ static void set_ipv6_state(gchar *ifname, gboolean enable) fclose(f); } +static int get_ipv6_privacy(gchar *ifname) +{ + gchar *path; + FILE *f; + int value; + + if (ifname == NULL) + return 0; + + path = g_strdup_printf("/proc/sys/net/ipv6/conf/%s/use_tempaddr", + ifname); + + if (path == NULL) + return 0; + + f = fopen(path, "r"); + + g_free(path); + + if (f == NULL) + return 0; + + if (fscanf(f, "%d", &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) +{ + gchar *path; + FILE *f; + + if (ifname == NULL) + return; + + path = g_strdup_printf("/proc/sys/net/ipv6/conf/%s/use_tempaddr", + ifname); + + if (path == NULL) + return; + + if (value < 0) + value = 0; + + f = fopen(path, "r+"); + + g_free(path); + + if (f == NULL) + return; + + fprintf(f, "%d", value); + fclose(f); +} + static void free_ipdevice(gpointer data) { struct connman_ipdevice *ipdevice = data; @@ -377,6 +441,7 @@ static void free_ipdevice(gpointer data) g_free(ipdevice->address); set_ipv6_state(ipdevice->ifname, ipdevice->ipv6_enabled); + set_ipv6_privacy(ipdevice->ifname, ipdevice->ipv6_privacy); g_free(ipdevice->ifname); g_free(ipdevice); @@ -474,6 +539,7 @@ void __connman_ipconfig_newlink(int index, unsigned short type, ipdevice->type = type; ipdevice->ipv6_enabled = get_ipv6_state(ipdevice->ifname); + ipdevice->ipv6_privacy = get_ipv6_privacy(ipdevice->ifname); ipdevice->address = g_strdup(address); @@ -926,6 +992,7 @@ static struct connman_ipconfig *create_ipv6config(int index) ipv6config->index = index; ipv6config->type = CONNMAN_IPCONFIG_TYPE_IPV6; ipv6config->method = CONNMAN_IPCONFIG_METHOD_AUTO; + ipv6config->ipv6_privacy = 1; ipv6config->address = connman_ipaddress_alloc(AF_INET6); if (ipv6config->address == NULL) { @@ -1496,6 +1563,9 @@ void __connman_ipconfig_append_ipv6(struct connman_ipconfig *ipconfig, if (ipconfig->system->gateway != NULL) connman_dbus_dict_append_basic(iter, "Gateway", DBUS_TYPE_STRING, &ipconfig->system->gateway); + + connman_dbus_dict_append_basic(iter, "Privacy", + DBUS_TYPE_INT32, &ipconfig->ipv6_privacy); } void __connman_ipconfig_append_ipv6config(struct connman_ipconfig *ipconfig, @@ -1536,6 +1606,9 @@ void __connman_ipconfig_append_ipv6config(struct connman_ipconfig *ipconfig, if (ipconfig->address->gateway != NULL) connman_dbus_dict_append_basic(iter, "Gateway", DBUS_TYPE_STRING, &ipconfig->address->gateway); + + connman_dbus_dict_append_basic(iter, "Privacy", + DBUS_TYPE_INT32, &ipconfig->ipv6_privacy); } void __connman_ipconfig_append_ipv4config(struct connman_ipconfig *ipconfig, @@ -1610,6 +1683,9 @@ static void enable_ipv6(struct connman_ipconfig *ipconfig) if (ipdevice == NULL) return; + if (ipconfig->method == CONNMAN_IPCONFIG_METHOD_AUTO) + set_ipv6_privacy(ipdevice->ifname, ipconfig->ipv6_privacy); + set_ipv6_state(ipdevice->ifname, TRUE); } @@ -1618,8 +1694,8 @@ int __connman_ipconfig_set_config(struct connman_ipconfig *ipconfig, { enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN; const char *address = NULL, *netmask = NULL, *gateway = NULL, - *prefix_length_string = NULL; - int prefix_length = 0; + *prefix_length_string = NULL, *privacy_string = NULL; + int prefix_length = 0, privacy = 1; DBusMessageIter dict; DBG("ipconfig %p", ipconfig); @@ -1678,12 +1754,24 @@ int __connman_ipconfig_set_config(struct connman_ipconfig *ipconfig, return -EINVAL; dbus_message_iter_get_basic(&entry, &gateway); + } else if (g_str_equal(key, "Privacy") == TRUE) { + char *endptr; + long val; + + if (type != DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&entry, &privacy_string); + val = strtol(privacy_string, &endptr, 10); + if (endptr != privacy_string) + privacy = val; } dbus_message_iter_next(&dict); } - DBG("method %d address %s netmask %s gateway %s prefix_length %d", - method, address, netmask, gateway, prefix_length); + DBG("method %d address %s netmask %s gateway %s prefix_length %d " + "privacy %d", + method, address, netmask, gateway, prefix_length, privacy); switch (method) { case CONNMAN_IPCONFIG_METHOD_UNKNOWN: @@ -1701,6 +1789,7 @@ int __connman_ipconfig_set_config(struct connman_ipconfig *ipconfig, return -EINVAL; ipconfig->method = method; + ipconfig->ipv6_privacy = privacy; enable_ipv6(ipconfig); break; @@ -1827,6 +1916,15 @@ int __connman_ipconfig_load(struct connman_ipconfig *ipconfig, keyfile, identifier, key, NULL); g_free(key); + if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6) { + key = g_strdup_printf("%sprivacy", prefix); + ipconfig->ipv6_privacy = g_key_file_get_integer( + keyfile, identifier, key, NULL); + if (ipconfig->method == CONNMAN_IPCONFIG_METHOD_AUTO) + enable_ipv6(ipconfig); + g_free(key); + } + return 0; } @@ -1873,6 +1971,13 @@ int __connman_ipconfig_save(struct connman_ipconfig *ipconfig, key, ipconfig->address->gateway); g_free(key); + if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6) { + key = g_strdup_printf("%sprivacy", prefix); + g_key_file_set_integer(keyfile, identifier, + key, ipconfig->ipv6_privacy); + g_free(key); + } + return 0; } -- 1.7.0.4 _______________________________________________ connman mailing list connman@connman.net http://lists.connman.net/listinfo/connman