Track IPv6 address changes through rtnl
authorSamuel Ortiz <sameo@linux.intel.com>
Wed, 28 Jul 2010 17:55:36 +0000 (19:55 +0200)
committerSamuel Ortiz <sameo@linux.intel.com>
Thu, 29 Jul 2010 00:12:54 +0000 (02:12 +0200)
src/connman.h
src/ipconfig.c
src/rtnl.c

index b014c2e..0dd87d2 100644 (file)
@@ -210,9 +210,9 @@ void __connman_ipconfig_newlink(int index, unsigned short type,
                                                        unsigned short mtu,
                                                struct rtnl_link_stats *stats);
 void __connman_ipconfig_dellink(int index, struct rtnl_link_stats *stats);
-void __connman_ipconfig_newaddr(int index, const char *label,
+void __connman_ipconfig_newaddr(int index, int family, const char *label,
                                unsigned char prefixlen, const char *address);
-void __connman_ipconfig_deladdr(int index, const char *label,
+void __connman_ipconfig_deladdr(int index, int family, const char *label,
                                unsigned char prefixlen, const char *address);
 void __connman_ipconfig_newroute(int index, unsigned char scope,
                                        const char *dst, const char *gateway);
index f486c99..e3bff4c 100644 (file)
@@ -583,7 +583,7 @@ void __connman_ipconfig_dellink(int index, struct rtnl_link_stats *stats)
        g_hash_table_remove(ipdevice_hash, GINT_TO_POINTER(index));
 }
 
-void __connman_ipconfig_newaddr(int index, const char *label,
+void __connman_ipconfig_newaddr(int index, int family, const char *label,
                                unsigned char prefixlen, const char *address)
 {
        struct connman_ipdevice *ipdevice;
@@ -609,8 +609,14 @@ void __connman_ipconfig_newaddr(int index, const char *label,
        connman_info("%s {add} address %s/%u label %s", ipdevice->ifname,
                                                address, prefixlen, label);
 
-       if (ipdevice->config != NULL)
-               connman_ipaddress_copy(ipdevice->config->system, ipaddress);
+       if (ipdevice->config != NULL) {
+               if (family == AF_INET6 && ipdevice->config->ipv6 != NULL)
+                       connman_ipaddress_copy(ipdevice->config->ipv6->system,
+                                                       ipaddress);
+               else
+                       connman_ipaddress_copy(ipdevice->config->system,
+                                                       ipaddress);
+       }
 
        if ((ipdevice->flags & (IFF_RUNNING | IFF_LOWER_UP)) != (IFF_RUNNING | IFF_LOWER_UP))
                return;
@@ -633,7 +639,7 @@ void __connman_ipconfig_newaddr(int index, const char *label,
        }
 }
 
-void __connman_ipconfig_deladdr(int index, const char *label,
+void __connman_ipconfig_deladdr(int index, int family, const char *label,
                                unsigned char prefixlen, const char *address)
 {
        struct connman_ipdevice *ipdevice;
index 7e8d3b6..c67a0ed 100644 (file)
@@ -497,7 +497,7 @@ static void process_dellink(unsigned short type, int index, unsigned flags,
        g_hash_table_remove(interface_list, GINT_TO_POINTER(index));
 }
 
-static void extract_addr(struct ifaddrmsg *msg, int bytes,
+static void extract_ipv4_addr(struct ifaddrmsg *msg, int bytes,
                                                const char **label,
                                                struct in_addr *local,
                                                struct in_addr *address,
@@ -528,34 +528,83 @@ static void extract_addr(struct ifaddrmsg *msg, int bytes,
        }
 }
 
+static void extract_ipv6_addr(struct ifaddrmsg *msg, int bytes,
+                                               struct in6_addr *addr,
+                                               struct in6_addr *local)
+{
+       struct rtattr *attr;
+
+       for (attr = IFA_RTA(msg); RTA_OK(attr, bytes);
+                                       attr = RTA_NEXT(attr, bytes)) {
+               switch (attr->rta_type) {
+               case IFA_ADDRESS:
+                       if (addr != NULL)
+                               *addr = *((struct in6_addr *) RTA_DATA(attr));
+                       break;
+               case IFA_LOCAL:
+                       if (local != NULL)
+                               *local = *((struct in6_addr *) RTA_DATA(attr));
+                       break;
+               }
+       }
+}
+
 static void process_newaddr(unsigned char family, unsigned char prefixlen,
                                int index, struct ifaddrmsg *msg, int bytes)
 {
-       struct in_addr address = { INADDR_ANY };
        const char *label = NULL;
+       void *src;
+       char ip_string[INET6_ADDRSTRLEN];
 
-       if (family != AF_INET)
+       if (family != AF_INET && family != AF_INET6)
                return;
 
-       extract_addr(msg, bytes, &label, &address, NULL, NULL);
+       if (family == AF_INET) {
+               struct in_addr ipv4_addr = { INADDR_ANY };
+
+               extract_ipv4_addr(msg, bytes, &label, &ipv4_addr, NULL, NULL);
+               src = &ipv4_addr;
+       } else if (family == AF_INET6) {
+               struct in6_addr ipv6_address, ipv6_local;
+
+               extract_ipv6_addr(msg, bytes, &ipv6_address, &ipv6_local);
+               src = &ipv6_address;
+       }
+
+       if (inet_ntop(family, src, ip_string, INET6_ADDRSTRLEN) == NULL)
+               return;
 
-       __connman_ipconfig_newaddr(index, label,
-                                       prefixlen, inet_ntoa(address));
+       __connman_ipconfig_newaddr(index, family, label,
+                                       prefixlen, ip_string);
 }
 
 static void process_deladdr(unsigned char family, unsigned char prefixlen,
                                int index, struct ifaddrmsg *msg, int bytes)
 {
-       struct in_addr address = { INADDR_ANY };
        const char *label = NULL;
+       void *src;
+       char ip_string[INET6_ADDRSTRLEN];
 
-       if (family != AF_INET)
+       if (family != AF_INET && family != AF_INET6)
                return;
 
-       extract_addr(msg, bytes, &label, &address, NULL, NULL);
+       if (family == AF_INET) {
+               struct in_addr ipv4_addr = { INADDR_ANY };
+
+               extract_ipv4_addr(msg, bytes, &label, &ipv4_addr, NULL, NULL);
+               src = &ipv4_addr;
+       } else if (family == AF_INET6) {
+               struct in6_addr ipv6_address, ipv6_local;
+
+               extract_ipv6_addr(msg, bytes, &ipv6_address, &ipv6_local);
+               src = &ipv6_address;
+       }
+
+       if (inet_ntop(family, src, ip_string, INET6_ADDRSTRLEN) == NULL)
+               return;
 
-       __connman_ipconfig_deladdr(index, label,
-                                       prefixlen, inet_ntoa(address));
+       __connman_ipconfig_deladdr(index, family, label,
+                                       prefixlen, ip_string);
 }
 
 static void extract_route(struct rtmsg *msg, int bytes, int *index,
@@ -1277,7 +1326,8 @@ int __connman_rtnl_init(void)
 
        memset(&addr, 0, sizeof(addr));
        addr.nl_family = AF_NETLINK;
-       addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
+       addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
+                               RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
 
        if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
                close(sk);