summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2010-12-17 22:31:30 +0000
committerSamuel Ortiz <sameo@linux.intel.com>2010-12-21 16:55:05 +0100
commit5254c601b9a89660f901bb1927e3b80e8adc7bc0 (patch)
tree1cddd770d846bc2548747a43be6317664ac7ae10
parent1339c2b9108c95d65b1eb2ada00c64be76008e5d (diff)
downloadconnman-5254c601b9a89660f901bb1927e3b80e8adc7bc0.tar.gz
connman-5254c601b9a89660f901bb1927e3b80e8adc7bc0.tar.bz2
connman-5254c601b9a89660f901bb1927e3b80e8adc7bc0.zip
rtnl: Refactor RDNSS support so we can support DNSSL
Rather than registering the new nameserver as we hit the RDNSS option, gather all the information first and then register the nameservers after the loop. That way, we can gather the search domains while we're looping, and provide them when we register the nameservers.
-rw-r--r--src/rtnl.c43
1 files changed, 28 insertions, 15 deletions
diff --git a/src/rtnl.c b/src/rtnl.c
index b10d8354..b56a80d3 100644
--- a/src/rtnl.c
+++ b/src/rtnl.c
@@ -1024,32 +1024,33 @@ static void rtnl_delroute(struct nlmsghdr *hdr)
msg, RTM_PAYLOAD(hdr));
}
-static void rtnl_nd_opt_rdnss(char *interface, struct nd_opt_hdr *opt)
+static void *rtnl_nd_opt_rdnss(struct nd_opt_hdr *opt, guint32 *lifetime,
+ int *nr_servers)
{
guint32 *optint = (void *)opt;
- guint32 lifetime;
- char buf[80];
- int i;
if (opt->nd_opt_len < 3)
- return;
+ return NULL;
- lifetime = ntohl(optint[1]);
- if (!lifetime)
- return;
+ if (*lifetime > ntohl(optint[1]))
+ *lifetime = ntohl(optint[1]);
- 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);
- }
+ /* nd_opt_len is in units of 8 bytes. The header is 1 unit (8 bytes)
+ and each address is another 2 units (16 bytes).
+ So the number of addresses (given rounding) is nd_opt_len/2 */
+ *nr_servers = opt->nd_opt_len / 2;
+
+ /* And they start 8 bytes into the packet, or two guint32s in. */
+ return optint + 2;
}
static void rtnl_newnduseropt(struct nlmsghdr *hdr)
{
struct nduseroptmsg *msg = (struct nduseroptmsg *) NLMSG_DATA(hdr);
struct nd_opt_hdr *opt = (void *)&msg[1];
+ guint32 lifetime = -1;
+ struct in6_addr *servers;
+ int nr_servers = 0;
int msglen = msg->nduseropt_opts_len;
char *interface;
@@ -1076,7 +1077,19 @@ static void rtnl_newnduseropt(struct nlmsghdr *hdr)
opt->nd_opt_type, opt->nd_opt_len);
if (opt->nd_opt_type == 25)
- rtnl_nd_opt_rdnss(interface, opt);
+ servers = rtnl_nd_opt_rdnss(opt, &lifetime,
+ &nr_servers);
+ }
+
+ if (nr_servers) {
+ int i;
+ char buf[40];
+
+ for (i = 0; i < nr_servers; i++) {
+ if (inet_ntop(AF_INET6, servers + i, buf, sizeof(buf)))
+ connman_resolver_append_lifetime(interface,
+ NULL, buf, lifetime);
+ }
}
g_free(interface);
}