summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Ortiz <sameo@linux.intel.com>2010-07-28 19:55:36 +0200
committerSamuel Ortiz <sameo@linux.intel.com>2010-07-29 02:12:54 +0200
commit7f54267c96a58191004e30ac2c01acf369f1df33 (patch)
tree366f5d8d18d2e95a48f470c1aecba3277660ba40
parentea2c14980b153c28990f8aa15da4192d04e42173 (diff)
downloadconnman-7f54267c96a58191004e30ac2c01acf369f1df33.tar.gz
connman-7f54267c96a58191004e30ac2c01acf369f1df33.tar.bz2
connman-7f54267c96a58191004e30ac2c01acf369f1df33.zip
Track IPv6 address changes through rtnl
-rw-r--r--src/connman.h4
-rw-r--r--src/ipconfig.c14
-rw-r--r--src/rtnl.c74
3 files changed, 74 insertions, 18 deletions
diff --git a/src/connman.h b/src/connman.h
index b014c2ed..0dd87d27 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -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);
diff --git a/src/ipconfig.c b/src/ipconfig.c
index f486c99b..e3bff4c6 100644
--- a/src/ipconfig.c
+++ b/src/ipconfig.c
@@ -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;
diff --git a/src/rtnl.c b/src/rtnl.c
index 7e8d3b6c..c67a0ed6 100644
--- a/src/rtnl.c
+++ b/src/rtnl.c
@@ -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);