--- 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