---
 include/ipconfig.h |    1 +
 src/connman.h      |    3 ++-
 src/ipconfig.c     |   42 +++++++++++++++++++++++++++++++++++++++---
 src/rtnl.c         |   15 ++++++++-------
 4 files changed, 50 insertions(+), 11 deletions(-)

diff --git a/include/ipconfig.h b/include/ipconfig.h
index ed03081..c80d9d6 100644
--- a/include/ipconfig.h
+++ b/include/ipconfig.h
@@ -39,6 +39,7 @@ struct connman_ipaddress {
        char *peer;
        char *broadcast;
        char *gateway;
+       void *address; /* either in_addr or in6_addr */
 };
 
 struct connman_ipaddress *connman_ipaddress_alloc(int family);
diff --git a/src/connman.h b/src/connman.h
index 03eda92..03d8c51 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -210,7 +210,8 @@ void __connman_ipconfig_newlink(int index, unsigned short 
type,
                                                struct rtnl_link_stats *stats);
 void __connman_ipconfig_dellink(int index, struct rtnl_link_stats *stats);
 void __connman_ipconfig_newaddr(int index, int family, const char *label,
-                               unsigned char prefixlen, const char *address);
+                               unsigned char prefixlen, const char *address,
+                               void *ipaddress);
 void __connman_ipconfig_deladdr(int index, int family, const char *label,
                                unsigned char prefixlen, const char *address);
 void __connman_ipconfig_newroute(int index, int family, unsigned char scope,
diff --git a/src/ipconfig.c b/src/ipconfig.c
index 3ba83d4..77911df 100644
--- a/src/ipconfig.c
+++ b/src/ipconfig.c
@@ -71,6 +71,7 @@ struct connman_ipdevice {
        GSList *address_list;
        char *ipv4_gateway;
        char *ipv6_gateway;
+       struct connman_ipaddress *ipv6_ll;
 
        char *pac;
 
@@ -95,6 +96,7 @@ struct connman_ipaddress *connman_ipaddress_alloc(int family)
        ipaddress->peer = NULL;
        ipaddress->broadcast = NULL;
        ipaddress->gateway = NULL;
+       ipaddress->address = NULL;
 
        return ipaddress;
 }
@@ -108,6 +110,7 @@ void connman_ipaddress_free(struct connman_ipaddress 
*ipaddress)
        g_free(ipaddress->peer);
        g_free(ipaddress->local);
        g_free(ipaddress->gateway);
+       g_free(ipaddress->address);
        g_free(ipaddress);
 }
 
@@ -315,6 +318,7 @@ static void free_ipdevice(gpointer data)
 
        g_free(ipdevice->address);
        g_free(ipdevice->ifname);
+       connman_ipaddress_free(ipdevice->ipv6_ll);
        g_free(ipdevice);
 }
 
@@ -525,6 +529,21 @@ void __connman_ipconfig_dellink(int index, struct 
rtnl_link_stats *stats)
        g_hash_table_remove(ipdevice_hash, GINT_TO_POINTER(index));
 }
 
+static inline gboolean is_autoconf_address(struct connman_ipaddress *ipaddress,
+                               struct connman_ipaddress *linklocal_address)
+{
+       if (!linklocal_address)
+               return FALSE;
+
+       if (((__const uint32_t *)(linklocal_address->address))[2] ==
+               ((__const uint32_t *)(ipaddress->address))[2] &&
+               ((__const uint32_t *)(linklocal_address->address))[3] ==
+               ((__const uint32_t *)(ipaddress->address))[3])
+               return TRUE;
+       else
+               return FALSE;
+}
+
 static inline gint check_duplicate_address(gconstpointer a, gconstpointer b)
 {
        const struct connman_ipaddress *addr1 = a;
@@ -537,7 +556,8 @@ static inline gint check_duplicate_address(gconstpointer a, 
gconstpointer b)
 }
 
 void __connman_ipconfig_newaddr(int index, int family, const char *label,
-                               unsigned char prefixlen, const char *address)
+                               unsigned char prefixlen, const char *address,
+                               void *in_address)
 {
        struct connman_ipdevice *ipdevice;
        struct connman_ipaddress *ipaddress;
@@ -555,6 +575,17 @@ void __connman_ipconfig_newaddr(int index, int family, 
const char *label,
 
        ipaddress->prefixlen = prefixlen;
        ipaddress->local = g_strdup(address);
+       ipaddress->address = in_address;
+
+       if (family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(in_address)) {
+
+               DBG("ipv6 ll %s", address);
+               if (ipdevice->ipv6_ll)
+                       connman_ipaddress_free(ipdevice->ipv6_ll);
+
+               ipdevice->ipv6_ll = ipaddress;
+               return;
+       }
 
        if (g_slist_find_custom(ipdevice->address_list, ipaddress,
                                        check_duplicate_address)) {
@@ -572,10 +603,15 @@ void __connman_ipconfig_newaddr(int index, int family, 
const char *label,
                connman_ipaddress_copy(ipdevice->config_ipv4->system,
                                        ipaddress);
 
-       else if (ipdevice->config_ipv6 != NULL && family == AF_INET6)
+       else if (ipdevice->config_ipv6 != NULL && family == AF_INET6) {
                connman_ipaddress_copy(ipdevice->config_ipv6->system,
                                        ipaddress);
-       else
+
+               if (prefixlen == 64 && is_autoconf_address(ipaddress,
+                                       ipdevice->ipv6_ll))
+                       ipdevice->config_ipv6->method =
+                                       CONNMAN_IPCONFIG_METHOD_AUTOCONF;
+       } else
                return;
 
        if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) != (IFF_RUNNING | 
IFF_LOWER_UP))
diff --git a/src/rtnl.c b/src/rtnl.c
index b10d835..cf11148 100644
--- a/src/rtnl.c
+++ b/src/rtnl.c
@@ -585,22 +585,23 @@ static void process_newaddr(unsigned char family, 
unsigned char prefixlen,
                struct in_addr ipv4_addr = { INADDR_ANY };
 
                extract_ipv4_addr(msg, bytes, &label, &ipv4_addr, NULL, NULL);
-               src = &ipv4_addr;
+               src = g_try_new0(struct in_addr, 1);
+               memcpy(src, &ipv4_addr, sizeof(struct in_addr));
        } else if (family == AF_INET6) {
                struct in6_addr ipv6_address, ipv6_local;
 
                extract_ipv6_addr(msg, bytes, &ipv6_address, &ipv6_local);
-               if (IN6_IS_ADDR_LINKLOCAL(&ipv6_address))
-                       return;
-
-               src = &ipv6_address;
+               src = g_try_new0(struct in6_addr, 1);
+               memcpy(src, &ipv6_address, sizeof(struct in6_addr));
        }
 
-       if (inet_ntop(family, src, ip_string, INET6_ADDRSTRLEN) == NULL)
+       if (inet_ntop(family, src, ip_string, INET6_ADDRSTRLEN) == NULL) {
+               g_free(src);
                return;
+       }
 
        __connman_ipconfig_newaddr(index, family, label,
-                                       prefixlen, ip_string);
+                                       prefixlen, ip_string, src);
 }
 
 static void process_deladdr(unsigned char family, unsigned char prefixlen,
-- 
1.7.0.4

_______________________________________________
connman mailing list
connman@connman.net
http://lists.connman.net/listinfo/connman

Reply via email to