summaryrefslogtreecommitdiff
path: root/src/rtnl.c
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2010-12-03 01:20:31 +0000
committerSamuel Ortiz <sameo@linux.intel.com>2010-12-03 16:00:43 +0100
commit75026d7e1c1e95dcbcfaa7d05bc5787da084f4e9 (patch)
treeb51530a022a077cb238e01003e3c385e616a2f54 /src/rtnl.c
parentdf8d2792abe96688c7adb0ab9b10e1c9eb17de63 (diff)
downloadconnman-75026d7e1c1e95dcbcfaa7d05bc5787da084f4e9.tar.gz
connman-75026d7e1c1e95dcbcfaa7d05bc5787da084f4e9.tar.bz2
connman-75026d7e1c1e95dcbcfaa7d05bc5787da084f4e9.zip
rtnl: Receive notification of RDNSS from IPv6 router advertisements
Diffstat (limited to 'src/rtnl.c')
-rw-r--r--src/rtnl.c66
1 files changed, 65 insertions, 1 deletions
diff --git a/src/rtnl.c b/src/rtnl.c
index 1993493a..a6a871d0 100644
--- a/src/rtnl.c
+++ b/src/rtnl.c
@@ -30,6 +30,7 @@
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <netinet/ether.h>
+#include <netinet/icmp6.h>
#include <net/if_arp.h>
#include <linux/if.h>
#include <linux/netlink.h>
@@ -1020,6 +1021,63 @@ static void rtnl_delroute(struct nlmsghdr *hdr)
msg, RTM_PAYLOAD(hdr));
}
+static void rtnl_nd_opt_rdnss(char *interface, struct nd_opt_hdr *opt)
+{
+ guint32 *optint = (void *)opt;
+ guint32 lifetime;
+ char buf[80];
+ int i;
+
+ if (opt->nd_opt_len < 3)
+ return;
+
+ lifetime = ntohl(optint[1]);
+ if (!lifetime)
+ return;
+
+ optint += 2;
+ for (i = 0; i < opt->nd_opt_len / 2; i++, optint += 4) {
+ if (inet_ntop(AF_INET6, optint, buf, sizeof(buf)))
+ connman_resolver_append_lifetime(interface, NULL,
+ buf, lifetime);
+ }
+}
+
+static void rtnl_newnduseropt(struct nlmsghdr *hdr)
+{
+ struct nduseroptmsg *msg = (struct nduseroptmsg *) NLMSG_DATA(hdr);
+ struct nd_opt_hdr *opt = (void *)&msg[1];
+ int msglen = msg->nduseropt_opts_len;
+ char *interface;
+
+ DBG("family %02x index %x len %04x type %02x code %02x",
+ msg->nduseropt_family, msg->nduseropt_ifindex,
+ msg->nduseropt_opts_len, msg->nduseropt_icmp_type,
+ msg->nduseropt_icmp_code);
+
+ if (msg->nduseropt_family != AF_INET6 ||
+ msg->nduseropt_icmp_type != ND_ROUTER_ADVERT ||
+ msg->nduseropt_icmp_code != 0)
+ return;
+
+ interface = connman_inet_ifname(msg->nduseropt_ifindex);
+ if (!interface)
+ return;
+
+ for (opt = (void *)&msg[1];
+ msglen >= 2 && msglen >= opt->nd_opt_len && opt->nd_opt_len;
+ msglen -= opt->nd_opt_len,
+ opt = ((void *)opt) + opt->nd_opt_len*8) {
+
+ DBG("nd opt type %d len %d\n",
+ opt->nd_opt_type, opt->nd_opt_len);
+
+ if (opt->nd_opt_type == 25)
+ rtnl_nd_opt_rdnss(interface, opt);
+ }
+ g_free(interface);
+}
+
static const char *type2string(uint16_t type)
{
switch (type) {
@@ -1047,6 +1105,8 @@ static const char *type2string(uint16_t type)
return "NEWROUTE";
case RTM_DELROUTE:
return "DELROUTE";
+ case RTM_NEWNDUSEROPT:
+ return "NEWNDUSEROPT";
default:
return "UNKNOWN";
}
@@ -1171,6 +1231,9 @@ static void rtnl_message(void *buf, size_t len)
case RTM_DELROUTE:
rtnl_delroute(hdr);
break;
+ case RTM_NEWNDUSEROPT:
+ rtnl_newnduseropt(hdr);
+ break;
}
len -= hdr->nlmsg_len;
@@ -1351,7 +1414,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 |
- RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
+ RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE |
+ (1<<(RTNLGRP_ND_USEROPT-1));
if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
close(sk);