Initial IPv6 support
authorMartin Xu <martin.xu@intel.com>
Wed, 28 Jul 2010 15:28:42 +0000 (17:28 +0200)
committerSamuel Ortiz <sameo@linux.intel.com>
Thu, 29 Jul 2010 00:12:54 +0000 (02:12 +0200)
Only manual/fixed setting supported for now.

13 files changed:
doc/service-api.txt
include/element.h
include/inet.h
include/ipconfig.h
include/property.h
src/connection.c
src/connman.h
src/element.c
src/inet.c
src/ipconfig.c
src/ipv4.c
src/network.c
src/service.c

index 9bf0907..29ef96a 100644 (file)
@@ -359,6 +359,42 @@ Properties string State [readonly]
                        until the new configuration has been successfully
                        installed.
 
+               dict IPv6 [readonly]
+
+                       string Method [readonly]
+
+                               Possible values are "dhcp", "manual"
+                               and "off".
+
+                               The value "fixed" indicates an IP address
+                               that can not be modified. For example
+                               cellular networks return fixed information.
+
+                               "dhcp" is not supported currently.
+
+                       string Address [readonly]
+
+                               The current configured IPv6 address.
+
+                       uint8 PrefixLength [readonly]
+
+                               The prefix length of the IPv6 address.
+
+                       string Gateway [readonly]
+
+                               The current configured IPv6 gateway.
+
+               dict IPv6.Configuration [readwrite]
+
+                       Same values as IPv6 property. The IPv6 represents
+                       the actual system configuration while this allows
+                       user configuration.
+
+                       Changing these settings will cause a state change
+                       of the service. The service will become unavailable
+                       until the new configuration has been successfully
+                       installed.
+
                dict Proxy [readonly]
 
                        string Method [readonly]
index eab567e..4161d7e 100644 (file)
@@ -109,6 +109,14 @@ struct connman_element {
                gchar *timeserver;
                gchar *pac;
        } ipv4;
+
+       struct {
+               enum connman_ipconfig_method method;
+               gchar *address;
+               int prefix_len;
+               gchar *gateway;
+               gchar *network;
+       } ipv6;
 };
 
 struct connman_element *connman_element_create(const char *name);
index 389a584..ce0a0b2 100644 (file)
@@ -51,6 +51,18 @@ int connman_inet_clear_gateway_address(int index, const char *gateway);
 int connman_inet_set_gateway_interface(int index);
 int connman_inet_clear_gateway_interface(int index);
 connman_bool_t connman_inet_compare_subnet(int index, const char *host);
+int connman_inet_set_ipv6_address(int index,
+               struct connman_ipaddress *ipaddress);
+int connman_inet_clear_ipv6_address(int index,
+               const char *address, int prefix_len);
+int connman_inet_add_ipv6_host_route(int index, const char *host,
+                                               const char *gateway);
+int connman_inet_del_ipv6_host_route(int index, const char *host);
+int connman_inet_set_ipv6_gateway_address(int index, const char *gateway);
+int connman_inet_clear_ipv6_gateway_address(int index, const char *gateway);
+
+void connman_ipaddress_set_ipv4(struct connman_ipaddress *ipaddress,
+               const char *address, const char *netmask, const char *gateway);
 
 #ifdef __cplusplus
 }
index 0b70252..5f67dcc 100644 (file)
@@ -86,10 +86,13 @@ const char *connman_ipconfig_get_ifname(struct connman_ipconfig *ipconfig);
 
 void connman_ipconfig_set_ops(struct connman_ipconfig *ipconfig,
                                const struct connman_ipconfig_ops *ops);
-
+int connman_ipaddress_set_ipv6(struct connman_ipaddress *ipaddress,
+                               const char *address, const char *gateway,
+                                               unsigned char prefix_length);
+struct connman_ipconfig *connman_ipconfig_get_ipv6config(
+                               struct connman_ipconfig *ipconfig);
 int connman_ipconfig_set_method(struct connman_ipconfig *ipconfig,
                                        enum connman_ipconfig_method method);
-
 void connman_ipconfig_bind(struct connman_ipconfig *ipconfig,
                                        struct connman_ipaddress *ipaddress);
 
index c7f2a7b..d00c61b 100644 (file)
@@ -48,6 +48,11 @@ enum connman_property_id {
        CONNMAN_PROPERTY_ID_IPV4_NAMESERVER,
        CONNMAN_PROPERTY_ID_IPV4_TIMESERVER,
        CONNMAN_PROPERTY_ID_IPV4_PAC,
+
+       CONNMAN_PROPERTY_ID_IPV6_METHOD,
+       CONNMAN_PROPERTY_ID_IPV6_ADDRESS,
+       CONNMAN_PROPERTY_ID_IPV6_PREFIXLEN,
+       CONNMAN_PROPERTY_ID_IPV6_GATEWAY,
 };
 
 enum connman_property_type {
index cb0b528..319024f 100644 (file)
@@ -33,6 +33,7 @@
 struct gateway_data {
        int index;
        char *ipv4_gateway;
+       char *ipv6_gateway;
        struct connman_element *element;
        unsigned int order;
        gboolean active;
@@ -77,6 +78,10 @@ static int del_routes(struct gateway_data *data)
        } else if (g_strcmp0(data->ipv4_gateway, "0.0.0.0") == 0) {
                return connman_inet_clear_gateway_interface(data->index);
        } else {
+               connman_inet_del_ipv6_host_route(data->index,
+                                               data->ipv6_gateway);
+               connman_inet_clear_ipv6_gateway_address(data->index,
+                                                       data->ipv6_gateway);
                connman_inet_del_host_route(data->index, data->ipv4_gateway);
                return connman_inet_clear_gateway_address(data->index,
                                                        data->ipv4_gateway);
@@ -98,11 +103,15 @@ static void find_element(struct connman_element *element, gpointer user_data)
        data->element = element;
 }
 
-static struct gateway_data *add_gateway(int index, const char *gateway)
+static struct gateway_data *add_gateway(int index, const char *gateway,
+                                               const char *ipv6_gateway)
 {
        struct gateway_data *data;
        struct connman_service *service;
 
+       DBG("index %d gateway %s ipv6_gateway %s", index, gateway,
+                                                       ipv6_gateway);
+
        if (strlen(gateway) == 0)
                return NULL;
 
@@ -112,6 +121,7 @@ static struct gateway_data *add_gateway(int index, const char *gateway)
 
        data->index = index;
        data->ipv4_gateway = g_strdup(gateway);
+       data->ipv6_gateway = g_strdup(ipv6_gateway);
        data->active = FALSE;
        data->element = NULL;
        data->vpn_ip = NULL;
@@ -162,6 +172,8 @@ static void set_default_gateway(struct gateway_data *data)
                goto done;
        }
 
+       connman_inet_set_ipv6_gateway_address(element->index,
+                                               data->ipv6_gateway);
        if (connman_inet_set_gateway_address(element->index,
                                        data->ipv4_gateway) < 0)
                return;
@@ -249,7 +261,7 @@ static struct gateway_data *find_active_gateway(void)
 static int connection_probe(struct connman_element *element)
 {
        struct connman_service *service = NULL;
-       const char *gateway = NULL;
+       const char *gateway = NULL, *ipv6_gateway = NULL;
        const char *vpn_ip = NULL;
        struct gateway_data *active_gateway = NULL;
        struct gateway_data *new_gateway = NULL;
@@ -265,11 +277,13 @@ static int connection_probe(struct connman_element *element)
 
        connman_element_get_value(element,
                                CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
+       connman_element_get_value(element,
+                       CONNMAN_PROPERTY_ID_IPV6_GATEWAY, &ipv6_gateway);
 
        connman_element_get_value(element,
                                  CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &vpn_ip);
 
-       DBG("gateway %s", gateway);
+       DBG("gateway %s, ipv6_gateway %s", gateway, ipv6_gateway);
 
        /*
         * If gateway is NULL, it's a point to point link and the default
@@ -283,12 +297,14 @@ static int connection_probe(struct connman_element *element)
        connman_element_set_enabled(element, TRUE);
 
        active_gateway = find_active_gateway();
-       new_gateway = add_gateway(element->index, gateway);
+       new_gateway = add_gateway(element->index, gateway, ipv6_gateway);
        if (new_gateway == NULL)
                return 0;
 
        service = __connman_element_get_service(element);
 
+       connman_inet_add_ipv6_host_route(element->index,
+                                       new_gateway->ipv6_gateway, NULL);
        connman_inet_add_host_route(element->index,
                                        new_gateway->ipv4_gateway, NULL);
        __connman_service_nameserver_add_routes(service,
index f33f745..b014c2e 100644 (file)
@@ -236,14 +236,23 @@ void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
                                                        DBusMessageIter *iter);
 void __connman_ipconfig_append_ipv4config(struct connman_ipconfig *ipconfig,
                                                        DBusMessageIter *iter);
-int __connman_ipconfig_set_ipv4config(struct connman_ipconfig *ipconfig,
-                                                       DBusMessageIter *value);
+void __connman_ipconfig_append_ipv6(struct connman_ipconfig *ipconfig,
+                                                       DBusMessageIter *iter);
+void __connman_ipconfig_append_ipv6config(struct connman_ipconfig *ipconfig,
+                                                       DBusMessageIter *iter);
+int __connman_ipconfig_set_config(struct connman_ipconfig *ipconfig,
+               enum connman_ipconfig_type type, DBusMessageIter *array);
 void __connman_ipconfig_append_proxy(struct connman_ipconfig *ipconfig,
                                                        DBusMessageIter *iter);
 void __connman_ipconfig_append_ethernet(struct connman_ipconfig *ipconfig,
                                                        DBusMessageIter *iter);
 enum connman_ipconfig_method __connman_ipconfig_get_method(
                                struct connman_ipconfig *ipconfig);
+
+void __connman_ipconfig_set_element_ipv6_gateway(
+                       struct connman_ipconfig *ipconfig,
+                               struct connman_element *element);
+
 int __connman_ipconfig_set_gateway(struct connman_ipconfig *ipconfig,
                                        struct connman_element *parent);
 int __connman_ipconfig_set_address(struct connman_ipconfig *ipconfig);
index 27d078f..5bc11f2 100644 (file)
@@ -784,6 +784,13 @@ int connman_element_get_value(struct connman_element *element,
                                                                id, value);
                *((char **) value) = element->ipv4.pac;
                break;
+       case CONNMAN_PROPERTY_ID_IPV6_GATEWAY:
+               if (element->ipv6.gateway == NULL)
+                       return connman_element_get_value(element->parent,
+                                                               id, value);
+               *((char **) value) = element->ipv6.gateway;
+               break;
+
        default:
                return -EINVAL;
        }
index 094c788..3f1547a 100644 (file)
@@ -508,6 +508,47 @@ done:
        return device;
 }
 
+struct in6_ifreq {
+       struct in6_addr ifr6_addr;
+       __u32 ifr6_prefixlen;
+       unsigned int ifr6_ifindex;
+};
+
+int connman_inet_set_ipv6_address(int index,
+               struct connman_ipaddress *ipaddress)
+{
+       int sk, err;
+       struct in6_ifreq ifr6;
+
+       DBG("index %d ipaddress->local %s", index, ipaddress->local);
+
+       if (ipaddress->local == NULL)
+               return 0;
+
+       sk = socket(PF_INET6, SOCK_DGRAM, 0);
+       if (sk < 0) {
+               err = -1;
+               goto out;
+       }
+
+       memset(&ifr6, 0, sizeof(ifr6));
+
+       err = inet_pton(AF_INET6, ipaddress->local, &ifr6.ifr6_addr);
+       if (err < 0)
+               goto out;
+
+       ifr6.ifr6_ifindex = index;
+       ifr6.ifr6_prefixlen = ipaddress->prefixlen;
+
+       err = ioctl(sk, SIOCSIFADDR, &ifr6);
+       close(sk);
+out:
+       if (err < 0)
+               connman_error("Set IPv6 address error");
+
+       return err;
+}
+
 int connman_inet_set_address(int index, struct connman_ipaddress *ipaddress)
 {
        struct ifreq ifr;
@@ -574,8 +615,42 @@ int connman_inet_set_address(int index, struct connman_ipaddress *ipaddress)
        return 0;
 }
 
+int connman_inet_clear_ipv6_address(int index, const char *address,
+                                                       int prefix_len)
+{
+       struct in6_ifreq ifr6;
+       int sk, err;
+
+       DBG("index %d address %s prefix_len %d", index, address, prefix_len);
+
+       memset(&ifr6, 0, sizeof(ifr6));
+
+       err = inet_pton(AF_INET6, address, &ifr6.ifr6_addr);
+       if (err < 0)
+               goto out;
+
+       ifr6.ifr6_ifindex = index;
+       ifr6.ifr6_prefixlen = prefix_len;
+
+       sk = socket(PF_INET6, SOCK_DGRAM, 0);
+       if (sk < 0) {
+               err = -1;
+               goto out;
+       }
+
+       err = ioctl(sk, SIOCDIFADDR, &ifr6);
+       close(sk);
+out:
+       if (err < 0)
+               connman_error("Clear IPv6 address error");
+
+       return err;
+}
+
 int connman_inet_clear_address(int index)
 {
+
+
        struct ifreq ifr;
        struct sockaddr_in addr;
        int sk, err;
@@ -709,6 +784,160 @@ int connman_inet_del_host_route(int index, const char *host)
        return err;
 }
 
+int connman_inet_del_ipv6_host_route(int index, const char *host)
+{
+       struct in6_rtmsg rt;
+       int sk, err;
+
+       DBG("index %d host %s", index, host);
+
+       if (host == NULL)
+               return -EINVAL;
+
+       memset(&rt, 0, sizeof(rt));
+
+       rt.rtmsg_dst_len = 128;
+
+       err = inet_pton(AF_INET6, host, &rt.rtmsg_dst);
+       if (err < 0)
+               goto out;
+
+       rt.rtmsg_flags = RTF_UP | RTF_HOST;
+
+       rt.rtmsg_metric = 1;
+       rt.rtmsg_ifindex = index;
+
+       sk = socket(AF_INET6, SOCK_DGRAM, 0);
+       if (sk < 0) {
+               err = -1;
+               goto out;
+       }
+
+       err = ioctl(sk, SIOCDELRT, &rt);
+       close(sk);
+out:
+       if (err < 0)
+               connman_error("Del IPv6 host route error");
+
+       return err;
+}
+
+int connman_inet_add_ipv6_host_route(int index, const char *host,
+                                               const char *gateway)
+{
+       struct in6_rtmsg rt;
+       int sk, err;
+
+       DBG("index %d host %s gateway %s", index, host, gateway);
+
+       if (host == NULL)
+               return -EINVAL;
+
+       memset(&rt, 0, sizeof(rt));
+
+       rt.rtmsg_dst_len = 128;
+
+       err = inet_pton(AF_INET6, host, &rt.rtmsg_dst);
+       if (err < 0)
+               goto out;
+
+       rt.rtmsg_flags = RTF_UP | RTF_HOST;
+
+       if (gateway != NULL) {
+               rt.rtmsg_flags |= RTF_GATEWAY;
+               inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway);
+       }
+
+       rt.rtmsg_metric = 1;
+       rt.rtmsg_ifindex = index;
+
+       sk = socket(AF_INET6, SOCK_DGRAM, 0);
+       if (sk < 0) {
+               err = -1;
+               goto out;
+       }
+
+       err = ioctl(sk, SIOCADDRT, &rt);
+       close(sk);
+out:
+       if (err < 0)
+               connman_error("Set IPv6 host route error");
+
+       return err;
+}
+
+int connman_inet_set_ipv6_gateway_address(int index, const char *gateway)
+{
+       struct in6_rtmsg rt;
+       int sk, err;
+
+       DBG("index %d, gateway %s", index, gateway);
+
+       if (gateway == NULL)
+               return -EINVAL;
+
+       memset(&rt, 0, sizeof(rt));
+
+       err = inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway);
+       if (err < 0)
+               goto out;
+
+       rt.rtmsg_flags = RTF_UP | RTF_GATEWAY;
+       rt.rtmsg_metric = 1;
+       rt.rtmsg_dst_len = 0;
+       rt.rtmsg_ifindex = index;
+
+       sk = socket(AF_INET6, SOCK_DGRAM, 0);
+       if (sk < 0) {
+               err = -1;
+               goto out;
+       }
+
+       err = ioctl(sk, SIOCADDRT, &rt);
+       close(sk);
+out:
+       if (err < 0)
+               connman_error("Set default IPv6 gateway error");
+
+       return err;
+}
+
+int connman_inet_clear_ipv6_gateway_address(int index, const char *gateway)
+{
+       struct in6_rtmsg rt;
+       int sk, err;
+
+       DBG("index %d, gateway %s", index, gateway);
+
+       if (gateway == NULL)
+               return -EINVAL;
+
+       memset(&rt, 0, sizeof(rt));
+
+       err = inet_pton(AF_INET6, gateway, &rt.rtmsg_gateway);
+       if (err < 0)
+               goto out;
+
+       rt.rtmsg_flags = RTF_UP | RTF_GATEWAY;
+       rt.rtmsg_metric = 1;
+       rt.rtmsg_dst_len = 0;
+       rt.rtmsg_ifindex = index;
+
+       sk = socket(AF_INET6, SOCK_DGRAM, 0);
+       if (sk < 0) {
+               err = -1;
+               goto out;
+       }
+
+       err = ioctl(sk, SIOCDELRT, &rt);
+       close(sk);
+out:
+       if (err < 0)
+               connman_error("Clear default IPv6 gateway error");
+
+       return err;
+}
+
 int connman_inet_set_gateway_address(int index, const char *gateway)
 {
        struct ifreq ifr;
index c589223..f486c99 100644 (file)
@@ -26,6 +26,8 @@
 #include <net/if.h>
 #include <net/if_arp.h>
 #include <linux/if_link.h>
+#include <string.h>
+#include <stdlib.h>
 
 #ifndef IFF_LOWER_UP
 #define IFF_LOWER_UP   0x10000
@@ -38,6 +40,7 @@
 struct connman_ipconfig {
        gint refcount;
        int index;
+       enum connman_ipconfig_type type;
 
        struct connman_ipconfig *origin;
 
@@ -47,6 +50,8 @@ struct connman_ipconfig {
        enum connman_ipconfig_method method;
        struct connman_ipaddress *address;
        struct connman_ipaddress *system;
+
+       struct connman_ipconfig *ipv6;
 };
 
 struct connman_ipdevice {
@@ -85,6 +90,12 @@ struct connman_ipaddress *connman_ipaddress_alloc(void)
        if (ipaddress == NULL)
                return NULL;
 
+       ipaddress->prefixlen = 0;
+       ipaddress->local = NULL;
+       ipaddress->peer = NULL;
+       ipaddress->broadcast = NULL;
+       ipaddress->gateway = NULL;
+
        return ipaddress;
 }
 
@@ -116,7 +127,46 @@ static unsigned char netmask2prefixlen(const char *netmask)
        return bits;
 }
 
-void connman_ipaddress_set(struct connman_ipaddress *ipaddress,
+static gboolean check_ipv6_address(const char *address)
+{
+       unsigned char buf[sizeof(struct in6_addr)];
+       int err;
+
+       err = inet_pton(AF_INET6, address, buf);
+       if (err > 0)
+               return TRUE;
+
+       return FALSE;
+}
+
+int connman_ipaddress_set_ipv6(struct connman_ipaddress *ipaddress,
+                               const char *address, const char *gateway,
+                                               unsigned char prefix_length)
+{
+       if (ipaddress == NULL)
+               return -EINVAL;
+
+       if (check_ipv6_address(address) == FALSE)
+               return -EINVAL;
+
+       if (check_ipv6_address(gateway) == FALSE)
+               return -EINVAL;
+
+       DBG("prefix_len %d address %s gateway %s",
+                       prefix_length, address, gateway);
+
+       ipaddress->prefixlen = prefix_length;
+
+       g_free(ipaddress->local);
+       ipaddress->local = g_strdup(address);
+
+       g_free(ipaddress->gateway);
+       ipaddress->gateway = g_strdup(gateway);
+
+       return 0;
+}
+
+void connman_ipaddress_set_ipv4(struct connman_ipaddress *ipaddress,
                const char *address, const char *netmask, const char *gateway)
 {
        if (ipaddress == NULL)
@@ -354,6 +404,9 @@ static void __connman_ipconfig_lower_down(struct connman_ipdevice *ipdevice)
        ipdevice->driver_config = NULL;
 
        connman_inet_clear_address(ipdevice->index);
+       connman_inet_clear_ipv6_address(ipdevice->index,
+                       ipdevice->driver_config->address->local,
+                       ipdevice->driver_config->address->prefixlen);
 }
 
 static void update_stats(struct connman_ipdevice *ipdevice,
@@ -759,6 +812,37 @@ const char *__connman_ipconfig_get_gateway(int index)
 void __connman_ipconfig_set_index(struct connman_ipconfig *ipconfig, int index)
 {
        ipconfig->index = index;
+
+       if (ipconfig->ipv6 != NULL)
+               ipconfig->ipv6->index = index;
+}
+
+static struct connman_ipconfig *create_ipv6config(int index)
+{
+       struct connman_ipconfig *ipv6config;
+
+       DBG("index %d", index);
+
+       ipv6config = g_try_new0(struct connman_ipconfig, 1);
+       if (ipv6config == NULL)
+               return NULL;
+
+       ipv6config->index = index;
+       ipv6config->type = CONNMAN_IPCONFIG_TYPE_IPV6;
+
+       ipv6config->address = connman_ipaddress_alloc();
+       if (ipv6config->address == NULL) {
+               g_free(ipv6config);
+               return NULL;
+       }
+
+       ipv6config->system = connman_ipaddress_alloc();
+
+       ipv6config->ipv6 = NULL;
+
+       DBG("ipconfig %p", ipv6config);
+
+       return ipv6config;
 }
 
 /**
@@ -781,6 +865,7 @@ struct connman_ipconfig *connman_ipconfig_create(int index)
        ipconfig->refcount = 1;
 
        ipconfig->index = index;
+       ipconfig->type = CONNMAN_IPCONFIG_TYPE_IPV4;
 
        ipconfig->address = connman_ipaddress_alloc();
        if (ipconfig->address == NULL) {
@@ -790,6 +875,8 @@ struct connman_ipconfig *connman_ipconfig_create(int index)
 
        ipconfig->system = connman_ipaddress_alloc();
 
+       ipconfig->ipv6 = create_ipv6config(index);
+
        DBG("ipconfig %p", ipconfig);
 
        return ipconfig;
@@ -834,6 +921,17 @@ struct connman_ipconfig *connman_ipconfig_ref(struct connman_ipconfig *ipconfig)
        return ipconfig;
 }
 
+static void  free_ipv6config(struct connman_ipconfig *ipconfig)
+{
+       if (ipconfig == NULL)
+               return;
+
+       connman_ipconfig_set_ops(ipconfig, NULL);
+       connman_ipaddress_free(ipconfig->system);
+       connman_ipaddress_free(ipconfig->address);
+       g_free(ipconfig->ipv6);
+}
+
 /**
  * connman_ipconfig_unref:
  * @ipconfig: ipconfig structure
@@ -854,6 +952,7 @@ void connman_ipconfig_unref(struct connman_ipconfig *ipconfig)
 
                connman_ipaddress_free(ipconfig->system);
                connman_ipaddress_free(ipconfig->address);
+               free_ipv6config(ipconfig->ipv6);
                g_free(ipconfig);
        }
 }
@@ -935,6 +1034,15 @@ void connman_ipconfig_set_ops(struct connman_ipconfig *ipconfig,
        ipconfig->ops = ops;
 }
 
+struct connman_ipconfig *connman_ipconfig_get_ipv6config(
+                               struct connman_ipconfig *ipconfig)
+{
+       if (ipconfig == NULL)
+               return NULL;
+
+       return ipconfig->ipv6;
+}
+
 /**
  * connman_ipconfig_set_method:
  * @ipconfig: ipconfig structure
@@ -977,7 +1085,17 @@ void connman_ipconfig_bind(struct connman_ipconfig *ipconfig,
        connman_inet_set_address(origin->index, origin->address);
 }
 
-/* FIXME: The element soulution should be removed in the future */
+void __connman_ipconfig_set_element_ipv6_gateway(
+                       struct connman_ipconfig *ipconfig,
+                               struct connman_element *element)
+{
+       element->ipv6.gateway = ipconfig->ipv6->address->gateway;
+}
+
+/*
+ * FIXME: The element soulution should be removed in the future
+ * Set IPv4 and IPv6 gateway
+ */
 int __connman_ipconfig_set_gateway(struct connman_ipconfig *ipconfig,
                                                struct connman_element *parent)
 {
@@ -985,9 +1103,12 @@ int __connman_ipconfig_set_gateway(struct connman_ipconfig *ipconfig,
 
        connection = connman_element_create(NULL);
 
+       DBG("ipconfig %p", ipconfig);
+
        connection->type  = CONNMAN_ELEMENT_TYPE_CONNECTION;
        connection->index = ipconfig->index;
        connection->ipv4.gateway = ipconfig->address->gateway;
+       connection->ipv6.gateway = ipconfig->ipv6->address->gateway;
 
        if (connman_element_register(connection, parent) < 0)
                connman_element_unref(connection);
@@ -1006,8 +1127,12 @@ int __connman_ipconfig_set_address(struct connman_ipconfig *ipconfig)
        case CONNMAN_IPCONFIG_METHOD_DHCP:
                break;
        case CONNMAN_IPCONFIG_METHOD_MANUAL:
-               return connman_inet_set_address(ipconfig->index,
-                                               ipconfig->address);
+               if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV4)
+                       return connman_inet_set_address(ipconfig->index,
+                                                       ipconfig->address);
+               else if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6)
+                       return connman_inet_set_ipv6_address(
+                                       ipconfig->index, ipconfig->address);
        }
 
        return 0;
@@ -1029,11 +1154,16 @@ int __connman_ipconfig_clear_address(struct connman_ipconfig *ipconfig)
        case CONNMAN_IPCONFIG_METHOD_DHCP:
                break;
        case CONNMAN_IPCONFIG_METHOD_MANUAL:
-               return connman_inet_clear_address(ipconfig->index);
+               if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV4)
+                       return connman_inet_clear_address(ipconfig->index);
+               else if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6)
+                       return connman_inet_clear_ipv6_address(
+                                               ipconfig->index,
+                                               ipconfig->address->local,
+                                               ipconfig->address->prefixlen);
        }
 
        return 0;
-
 }
 
 int __connman_ipconfig_enable(struct connman_ipconfig *ipconfig)
@@ -1111,6 +1241,7 @@ int __connman_ipconfig_disable(struct connman_ipconfig *ipconfig)
        ipconfig_list = g_list_remove(ipconfig_list, ipconfig);
 
        connman_ipaddress_clear(ipdevice->config->system);
+       connman_ipaddress_clear(ipdevice->config->ipv6->system);
 
        connman_ipconfig_unref(ipdevice->config);
        ipdevice->config = NULL;
@@ -1155,6 +1286,8 @@ void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
 {
        const char *str;
 
+       DBG("");
+
        str = __connman_ipconfig_method2string(ipconfig->method);
        if (str == NULL)
                return;
@@ -1184,11 +1317,81 @@ void __connman_ipconfig_append_ipv4(struct connman_ipconfig *ipconfig,
                                DBUS_TYPE_STRING, &ipconfig->system->gateway);
 }
 
+void __connman_ipconfig_append_ipv6(struct connman_ipconfig *ipconfig,
+                                                       DBusMessageIter *iter)
+{
+       const char *str;
+
+       DBG("");
+
+       str = __connman_ipconfig_method2string(ipconfig->method);
+       if (str == NULL)
+               return;
+
+       connman_dbus_dict_append_basic(iter, "Method", DBUS_TYPE_STRING, &str);
+
+       if (ipconfig->system == NULL)
+               return;
+
+       if (ipconfig->system->local != NULL) {
+               connman_dbus_dict_append_basic(iter, "Address",
+                               DBUS_TYPE_STRING, &ipconfig->system->local);
+               connman_dbus_dict_append_basic(iter, "PrefixLength",
+                                               DBUS_TYPE_BYTE,
+                                               &ipconfig->system->prefixlen);
+       }
+
+       if (ipconfig->system->gateway != NULL)
+               connman_dbus_dict_append_basic(iter, "Gateway",
+                               DBUS_TYPE_STRING, &ipconfig->system->gateway);
+}
+
+void __connman_ipconfig_append_ipv6config(struct connman_ipconfig *ipconfig,
+                                                       DBusMessageIter *iter)
+{
+       const char *str;
+
+       DBG("");
+
+       str = __connman_ipconfig_method2string(ipconfig->method);
+       if (str == NULL)
+               return;
+
+       connman_dbus_dict_append_basic(iter, "Method", DBUS_TYPE_STRING, &str);
+
+       switch (ipconfig->method) {
+       case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
+       case CONNMAN_IPCONFIG_METHOD_OFF:
+       case CONNMAN_IPCONFIG_METHOD_DHCP:
+               return;
+       case CONNMAN_IPCONFIG_METHOD_FIXED:
+       case CONNMAN_IPCONFIG_METHOD_MANUAL:
+               break;
+       }
+
+       if (ipconfig->address == NULL)
+               return;
+
+       if (ipconfig->address->local != NULL) {
+               connman_dbus_dict_append_basic(iter, "Address",
+                               DBUS_TYPE_STRING, &ipconfig->address->local);
+               connman_dbus_dict_append_basic(iter, "PrefixLength",
+                                               DBUS_TYPE_BYTE,
+                                               &ipconfig->address->prefixlen);
+       }
+
+       if (ipconfig->address->gateway != NULL)
+               connman_dbus_dict_append_basic(iter, "Gateway",
+                               DBUS_TYPE_STRING, &ipconfig->address->gateway);
+}
+
 void __connman_ipconfig_append_ipv4config(struct connman_ipconfig *ipconfig,
                                                        DBusMessageIter *iter)
 {
        const char *str;
 
+       DBG("");
+
        str = __connman_ipconfig_method2string(ipconfig->method);
        if (str == NULL)
                return;
@@ -1228,14 +1431,20 @@ void __connman_ipconfig_append_ipv4config(struct connman_ipconfig *ipconfig,
                                DBUS_TYPE_STRING, &ipconfig->address->gateway);
 }
 
-int __connman_ipconfig_set_ipv4config(struct connman_ipconfig *ipconfig,
-                                                       DBusMessageIter *array)
+int __connman_ipconfig_set_config(struct connman_ipconfig *ipconfig,
+               enum connman_ipconfig_type type, DBusMessageIter *array)
 {
        enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
-       const char *address = NULL, *netmask = NULL, *gateway = NULL;
+       const char *address = NULL, *netmask = NULL, *gateway = NULL,
+                       *prefix_length_string = NULL;
+       int prefix_length = 0;
        DBusMessageIter dict;
 
-       DBG("ipconfig %p", ipconfig);
+       DBG("ipconfig %p type %d", ipconfig, type);
+
+       if (type != CONNMAN_IPCONFIG_TYPE_IPV4 &&
+                       type != CONNMAN_IPCONFIG_TYPE_IPV6)
+               return -EINVAL;
 
        if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
                return -EINVAL;
@@ -1270,6 +1479,17 @@ int __connman_ipconfig_set_ipv4config(struct connman_ipconfig *ipconfig,
                                return -EINVAL;
 
                        dbus_message_iter_get_basic(&entry, &address);
+               } else if (g_str_equal(key, "PrefixLength") == TRUE) {
+                       if (type != DBUS_TYPE_STRING)
+                               return -EINVAL;
+
+                       dbus_message_iter_get_basic(&entry,
+                                                       &prefix_length_string);
+
+                       prefix_length = atoi(prefix_length_string);
+                       if (prefix_length < 0 || prefix_length > 128)
+                               return -EINVAL;
+
                } else if (g_str_equal(key, "Netmask") == TRUE) {
                        if (type != DBUS_TYPE_STRING)
                                return -EINVAL;
@@ -1284,8 +1504,8 @@ int __connman_ipconfig_set_ipv4config(struct connman_ipconfig *ipconfig,
                dbus_message_iter_next(&dict);
        }
 
-       DBG("method %d address %s netmask %s gateway %s",
-                               method, address, netmask, gateway);
+       DBG("method %d address %s netmask %s gateway %s prefix_length %d",
+                       method, address, netmask, gateway, prefix_length);
 
        switch (method) {
        case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
@@ -1298,8 +1518,14 @@ int __connman_ipconfig_set_ipv4config(struct connman_ipconfig *ipconfig,
                        return -EINVAL;
 
                ipconfig->method = method;
-               connman_ipaddress_set(ipconfig->address,
-                               address, netmask, gateway);
+
+               if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
+                       connman_ipaddress_set_ipv4(ipconfig->address,
+                                               address, netmask, gateway);
+               else
+                       return connman_ipaddress_set_ipv6(
+                                       ipconfig->address, address,
+                                               gateway, prefix_length);
                break;
 
        case CONNMAN_IPCONFIG_METHOD_DHCP:
index 4fc6a9f..1267e5a 100644 (file)
@@ -164,6 +164,8 @@ static char *index2name(int index)
 
 static int ipv4_probe(struct connman_element *element)
 {
+       struct connman_service *service;
+       struct connman_ipconfig *ipconfig;
        struct connman_element *connection;
        struct connman_ipv4 ipv4;
        const char *address = NULL, *netmask = NULL, *broadcast = NULL;
@@ -202,12 +204,10 @@ static int ipv4_probe(struct connman_element *element)
 
        set_ipv4(element, &ipv4);
 
-       if (nameserver != NULL) {
-               struct connman_service *service;
+       service = __connman_element_get_service(element);
 
-               service = __connman_element_get_service(element);
+       if (nameserver != NULL)
                __connman_service_append_nameserver(service, nameserver);
-       }
 
        connman_timeserver_append(timeserver);
 
@@ -217,6 +217,11 @@ static int ipv4_probe(struct connman_element *element)
        connection->index   = element->index;
        connection->devname = index2name(element->index);
 
+       ipconfig = __connman_service_get_ipconfig(service);
+       if (ipconfig != NULL)
+               __connman_ipconfig_set_element_ipv6_gateway(
+                                               ipconfig, connection);
+
        if (connman_element_register(connection, element) < 0)
                connman_element_unref(connection);
 
index c36298e..a74043c 100644 (file)
@@ -845,6 +845,31 @@ static int set_connected_dhcp(struct connman_network *network)
        return 0;
 }
 
+static int manual_ipv6_set(struct connman_network *network,
+                               struct connman_ipconfig *ipconfig_ipv6)
+{
+       struct connman_service *service;
+       int err;
+
+       service = __connman_service_lookup_from_network(network);
+       if (service == NULL)
+               return -EINVAL;
+
+       err = __connman_ipconfig_set_address(ipconfig_ipv6);
+       if (err < 0) {
+               connman_network_set_error(network,
+                       CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
+               return err;
+       }
+
+       /*
+        * READY state will be indicated by IPV4 setting
+        * gateway will be set by IPV4 setting
+        */
+
+       return 0;
+}
+
 static gboolean set_connected(gpointer user_data)
 {
        struct connman_network *network = user_data;
@@ -861,6 +886,29 @@ static gboolean set_connected(gpointer user_data)
        DBG("method %d", method);
 
        if (network->connected == TRUE) {
+               enum connman_ipconfig_method ipv6_method;
+               struct connman_ipconfig *ipv6config;
+               int ret;
+
+               ipv6config = connman_ipconfig_get_ipv6config(ipconfig);
+               ipv6_method = __connman_ipconfig_get_method(ipv6config);
+               switch (ipv6_method) {
+               case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
+               case CONNMAN_IPCONFIG_METHOD_OFF:
+                       break;
+               case CONNMAN_IPCONFIG_METHOD_FIXED:
+               case CONNMAN_IPCONFIG_METHOD_MANUAL:
+                       ret = manual_ipv6_set(network, ipv6config);
+                       if (ret != 0) {
+                               connman_network_set_error(network,
+                                       CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
+                               return FALSE;
+                       }
+                       break;
+               case CONNMAN_IPCONFIG_METHOD_DHCP:
+                       break;
+               }
+
                switch (method) {
                case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
                case CONNMAN_IPCONFIG_METHOD_OFF:
@@ -974,6 +1022,7 @@ connman_bool_t connman_network_get_associating(struct connman_network *network)
  */
 int __connman_network_connect(struct connman_network *network)
 {
+       struct connman_service *service;
        int err;
 
        DBG("network %p", network);
@@ -994,6 +1043,8 @@ int __connman_network_connect(struct connman_network *network)
 
        network->connecting = TRUE;
 
+       service = __connman_service_lookup_from_network(network);
+
        err = network->driver->connect(network);
        if (err < 0) {
                if (err == -EINPROGRESS)
@@ -1141,9 +1192,31 @@ int __connman_network_clear_ipconfig(struct connman_network *network,
        return 0;
 }
 
-int __connman_network_set_ipconfig(struct connman_network *network, struct connman_ipconfig *ipconfig)
+int __connman_network_set_ipconfig(struct connman_network *network,
+                                       struct connman_ipconfig *ipconfig)
 {
+       struct connman_ipconfig *ipv6config;
        enum connman_ipconfig_method method;
+       int ret;
+
+       ipv6config = connman_ipconfig_get_ipv6config(ipconfig);
+       method = __connman_ipconfig_get_method(ipv6config);
+       switch (method) {
+       case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
+       case CONNMAN_IPCONFIG_METHOD_OFF:
+               break;
+       case CONNMAN_IPCONFIG_METHOD_FIXED:
+       case CONNMAN_IPCONFIG_METHOD_MANUAL:
+               ret = manual_ipv6_set(network, ipv6config);
+               if (ret != 0) {
+                       connman_network_set_error(network,
+                               CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
+                       return FALSE;
+               }
+               break;
+       case CONNMAN_IPCONFIG_METHOD_DHCP:
+               break;
+       }
 
        method = __connman_ipconfig_get_method(ipconfig);
 
index 8aa0634..5723aab 100644 (file)
@@ -791,6 +791,24 @@ static void append_ipv4(DBusMessageIter *iter, void *user_data)
                __connman_ipconfig_append_ipv4(service->ipconfig, iter);
 }
 
+static void append_ipv6(DBusMessageIter *iter, void *user_data)
+{
+       struct connman_service *service = user_data;
+       struct connman_ipconfig *ipv6config;
+
+       if (is_connected(service) == FALSE)
+               return;
+
+       if (service->ipconfig == NULL)
+               return;
+
+       ipv6config = connman_ipconfig_get_ipv6config(service->ipconfig);
+       if (ipv6config == NULL)
+               return;
+
+       __connman_ipconfig_append_ipv6(ipv6config, iter);
+}
+
 static void append_ipv4config(DBusMessageIter *iter, void *user_data)
 {
        struct connman_service *service = user_data;
@@ -799,6 +817,21 @@ static void append_ipv4config(DBusMessageIter *iter, void *user_data)
                __connman_ipconfig_append_ipv4config(service->ipconfig, iter);
 }
 
+static void append_ipv6config(DBusMessageIter *iter, void *user_data)
+{
+       struct connman_service *service = user_data;
+       struct connman_ipconfig *ipv6config;
+
+       if (service->ipconfig == NULL)
+               return;
+
+       ipv6config = connman_ipconfig_get_ipv6config(service->ipconfig);
+       if (ipv6config == NULL)
+               return;
+
+       __connman_ipconfig_append_ipv6config(ipv6config, iter);
+}
+
 static void append_dns(DBusMessageIter *iter, void *user_data)
 {
        struct connman_service *service = user_data;
@@ -873,6 +906,10 @@ static void settings_changed(struct connman_service *service)
        connman_dbus_property_changed_dict(service->path,
                                        CONNMAN_SERVICE_INTERFACE, "IPv4",
                                                        append_ipv4, service);
+
+       connman_dbus_property_changed_dict(service->path,
+                                       CONNMAN_SERVICE_INTERFACE, "IPv6",
+                                                       append_ipv6, service);
 }
 
 static void ipv4_configuration_changed(struct connman_service *service)
@@ -884,6 +921,15 @@ static void ipv4_configuration_changed(struct connman_service *service)
                                                        service);
 }
 
+static void ipv6_configuration_changed(struct connman_service *service)
+{
+       connman_dbus_property_changed_dict(service->path,
+                                       CONNMAN_SERVICE_INTERFACE,
+                                                       "IPv6.Configuration",
+                                                       append_ipv6config,
+                                                       service);
+}
+
 static void dns_changed(struct connman_service *service)
 {
        if (is_connected(service) == FALSE)
@@ -1045,6 +1091,11 @@ static void append_properties(DBusMessageIter *dict, dbus_bool_t limited,
        connman_dbus_dict_append_dict(dict, "IPv4.Configuration",
                                                append_ipv4config, service);
 
+       connman_dbus_dict_append_dict(dict, "IPv6", append_ipv6, service);
+
+       connman_dbus_dict_append_dict(dict, "IPv6.Configuration",
+                                               append_ipv6config, service);
+
        connman_dbus_dict_append_array(dict, "Nameservers",
                                DBUS_TYPE_STRING, append_dns, service);
 
@@ -1331,29 +1382,51 @@ static DBusMessage *set_property(DBusConnection *conn,
                domain_configuration_changed(service);
 
                __connman_storage_save_service(service);
-       } else if (g_str_equal(name, "IPv4.Configuration") == TRUE) {
-               int err;
+       } else if (g_str_equal(name, "IPv4.Configuration") == TRUE ||
+                       g_str_equal(name, "IPv6.Configuration")) {
+
+               enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
+               int err = 0;
+               struct connman_ipconfig *ipv6config;
+
+               DBG("%s", name);
 
+               ipv6config = connman_ipconfig_get_ipv6config(
+                                               service->ipconfig);
                if (service->ipconfig == NULL)
                        return __connman_error_invalid_property(msg);
 
                if (is_connecting(service) ||
-                               is_connected(service))
+                               is_connected(service)) {
                        __connman_network_clear_ipconfig(service->network,
                                                        service->ipconfig);
+                       __connman_network_clear_ipconfig(service->network,
+                                                               ipv6config);
+               }
+
+               if (g_str_equal(name, "IPv4.Configuration") == TRUE) {
+                       type = CONNMAN_IPCONFIG_TYPE_IPV4;
+                       err = __connman_ipconfig_set_config(
+                                       service->ipconfig, type, &value);
+               } else if (g_str_equal(name, "IPv6.Configuration") == TRUE) {
+                       type = CONNMAN_IPCONFIG_TYPE_IPV6;
+                       err = __connman_ipconfig_set_config(
+                                               ipv6config, type, &value);
+               }
 
-               err = __connman_ipconfig_set_ipv4config(service->ipconfig,
-                                                               &value);
                if (err < 0) {
                        if (is_connected(service) ||
                                        is_connecting(service))
-                               __connman_network_set_ipconfig(service->network,
+                               __connman_network_set_ipconfig(
+                                                       service->network,
                                                        service->ipconfig);
-
                        return __connman_error_failed(msg, -err);
                }
 
-               ipv4_configuration_changed(service);
+               if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
+                       ipv4_configuration_changed(service);
+               else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
+                       ipv6_configuration_changed(service);
 
                if (is_connecting(service) ||
                                is_connected(service))
@@ -2464,6 +2537,7 @@ int __connman_service_connect(struct connman_service *service)
 
 int __connman_service_disconnect(struct connman_service *service)
 {
+       struct connman_ipconfig *ipv6config;
        int err;
 
        DBG("service %p", service);
@@ -2475,6 +2549,10 @@ int __connman_service_disconnect(struct connman_service *service)
 
        __connman_ipconfig_clear_address(service->ipconfig);
 
+       ipv6config = connman_ipconfig_get_ipv6config(service->ipconfig);
+
+       __connman_ipconfig_clear_address(ipv6config);
+
        __connman_ipconfig_disable(service->ipconfig);
 
        if (err < 0) {
@@ -2883,6 +2961,7 @@ static void setup_ipconfig(struct connman_service *service, int index)
 void __connman_service_create_ipconfig(struct connman_service *service,
                                                                int index)
 {
+       struct connman_ipconfig *ipv6config;
        const char *ident = service->profile;
        GKeyFile *keyfile;
 
@@ -2898,6 +2977,12 @@ void __connman_service_create_ipconfig(struct connman_service *service,
        if (keyfile == NULL)
                return;
 
+
+       ipv6config = connman_ipconfig_get_ipv6config(service->ipconfig);
+       if (ipv6config != NULL)
+               __connman_ipconfig_load(ipv6config, keyfile,
+                                       service->identifier, "IPv6.");
+
        __connman_ipconfig_load(service->ipconfig, keyfile,
                                        service->identifier, "IPv4.");
        g_key_file_free(keyfile);
@@ -3443,9 +3528,18 @@ static int service_load(struct connman_service *service)
                service->passphrase = str;
        }
 
-       if (service->ipconfig != NULL)
+       if (service->ipconfig != NULL) {
+               struct connman_ipconfig *ipv6config;
+
+               ipv6config = connman_ipconfig_get_ipv6config(
+                                               service->ipconfig);
+               if (ipv6config != NULL)
+                       __connman_ipconfig_load(ipv6config, keyfile,
+                                       service->identifier, "IPv6.");
+
                __connman_ipconfig_load(service->ipconfig, keyfile,
                                        service->identifier, "IPv4.");
+       }
 
        service->nameservers = g_key_file_get_string_list(keyfile,
                        service->identifier, "Nameservers", &length, NULL);
@@ -3591,9 +3685,17 @@ update:
                g_key_file_remove_key(keyfile, service->identifier,
                                                        "Passphrase", NULL);
 
-       if (service->ipconfig != NULL)
+       if (service->ipconfig != NULL) {
+               struct connman_ipconfig *ipv6config;
+
+               ipv6config = connman_ipconfig_get_ipv6config(service->ipconfig);
+               if (ipv6config != NULL)
+                       __connman_ipconfig_save(ipv6config, keyfile,
+                                               service->identifier, "IPv6.");
+
                __connman_ipconfig_save(service->ipconfig, keyfile,
                                        service->identifier, "IPv4.");
+       }
 
        if (service->nameservers != NULL) {
                guint len = g_strv_length(service->nameservers);