1/*
2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
4 * All rights reserved
5
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/param.h>
29#include <sys/socket.h>
30#include <net/if.h>
31#include <netinet/in.h>
32#include <netinet/ip6.h>
33#include <netinet/icmp6.h>
34
35#include <errno.h>
36#include <stddef.h>
37#include <stdlib.h>
38#include <string.h>
39#include <syslog.h>
40
41#ifdef __linux__
42#  define _LINUX_IN6_H
43#  include <linux/ipv6.h>
44#endif
45
46#define ELOOP_QUEUE 1
47#include "bind.h"
48#include "common.h"
49#include "configure.h"
50#include "dhcpcd.h"
51#include "eloop.h"
52#include "ipv6rs.h"
53
54#define ALLROUTERS "ff02::2"
55#define HOPLIMIT 255
56
57#define ROUNDUP8(a) (1 + (((a) - 1) | 7))
58
59#define RTR_SOLICITATION_INTERVAL       4 /* seconds */
60#define MAX_RTR_SOLICITATIONS           3 /* times */
61
62#ifndef ND_OPT_RDNSS
63#define ND_OPT_RDNSS			25
64struct nd_opt_rdnss {           /* RDNSS option RFC 6106 */
65	uint8_t		nd_opt_rdnss_type;
66	uint8_t		nd_opt_rdnss_len;
67	uint16_t	nd_opt_rdnss_reserved;
68	uint32_t	nd_opt_rdnss_lifetime;
69        /* followed by list of IP prefixes */
70} _packed;
71#endif
72
73#ifndef ND_OPT_DNSSL
74#define ND_OPT_DNSSL			31
75struct nd_opt_dnssl {		/* DNSSL option RFC 6106 */
76	uint8_t		nd_opt_dnssl_type;
77	uint8_t		nd_opt_dnssl_len;
78	uint16_t	nd_opt_dnssl_reserved;
79	uint32_t	nd_opt_dnssl_lifetime;
80	/* followed by list of DNS servers */
81} _packed;
82#endif
83
84static int sock;
85static struct sockaddr_in6 allrouters, from;
86static struct msghdr sndhdr;
87static struct iovec sndiov[2];
88static unsigned char *sndbuf;
89static struct msghdr rcvhdr;
90static struct iovec rcviov[2];
91static unsigned char *rcvbuf;
92static unsigned char ansbuf[1500];
93static char ntopbuf[INET6_ADDRSTRLEN];
94
95#if DEBUG_MEMORY
96static void
97ipv6rs_cleanup(void)
98{
99
100	free(sndbuf);
101	free(rcvbuf);
102}
103#endif
104
105int
106ipv6rs_open(void)
107{
108	int on;
109	int len;
110	struct icmp6_filter filt;
111
112	memset(&allrouters, 0, sizeof(allrouters));
113	allrouters.sin6_family = AF_INET6;
114#ifdef SIN6_LEN
115	allrouters.sin6_len = sizeof(allrouters);
116#endif
117	if (inet_pton(AF_INET6, ALLROUTERS, &allrouters.sin6_addr.s6_addr) != 1)
118		return -1;
119	sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
120	if (sock == -1)
121		return -1;
122	on = 1;
123	if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
124		&on, sizeof(on)) == -1)
125		return -1;
126
127	on = 1;
128	if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
129		&on, sizeof(on)) == -1)
130		return -1;
131
132	ICMP6_FILTER_SETBLOCKALL(&filt);
133	ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
134	if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER,
135		&filt, sizeof(filt)) == -1)
136		return -1;
137
138#if DEBUG_MEMORY
139	atexit(ipv6rs_cleanup);
140#endif
141
142	len = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int));
143	sndbuf = xzalloc(len);
144	if (sndbuf == NULL)
145		return -1;
146	sndhdr.msg_namelen = sizeof(struct sockaddr_in6);
147	sndhdr.msg_iov = sndiov;
148	sndhdr.msg_iovlen = 1;
149	sndhdr.msg_control = sndbuf;
150	sndhdr.msg_controllen = len;
151	rcvbuf = xzalloc(len);
152	if (rcvbuf == NULL)
153		return -1;
154	rcvhdr.msg_name = &from;
155	rcvhdr.msg_namelen = sizeof(from);
156	rcvhdr.msg_iov = rcviov;
157	rcvhdr.msg_iovlen = 1;
158	rcvhdr.msg_control = rcvbuf;
159	rcvhdr.msg_controllen = len;
160	rcviov[0].iov_base = ansbuf;
161	rcviov[0].iov_len = sizeof(ansbuf);
162	return sock;
163}
164
165static int
166ipv6rs_makeprobe(struct interface *ifp)
167{
168	struct nd_router_solicit *rs;
169	struct nd_opt_hdr *nd;
170
171	free(ifp->rs);
172	ifp->rslen = sizeof(*rs) + ROUNDUP8(ifp->hwlen + 2);
173	ifp->rs = xzalloc(ifp->rslen);
174	if (ifp->rs == NULL)
175		return -1;
176	rs = (struct nd_router_solicit *)ifp->rs;
177	rs->nd_rs_type = ND_ROUTER_SOLICIT;
178	rs->nd_rs_code = 0;
179	rs->nd_rs_cksum = 0;
180	rs->nd_rs_reserved = 0;
181	nd = (struct nd_opt_hdr *)(ifp->rs + sizeof(*rs));
182	nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
183	nd->nd_opt_len = (ROUNDUP8(ifp->hwlen + 2)) >> 3;
184	memcpy(nd + 1, ifp->hwaddr, ifp->hwlen);
185	return 0;
186}
187
188static void
189ipv6rs_sendprobe(void *arg)
190{
191	struct interface *ifp = arg;
192	struct sockaddr_in6 dst;
193	struct cmsghdr *cm;
194	struct in6_pktinfo pi;
195	int hoplimit = HOPLIMIT;
196
197	dst = allrouters;
198	//dst.sin6_scope_id = ifp->linkid;
199
200	ipv6rs_makeprobe(ifp);
201	sndhdr.msg_name = (caddr_t)&dst;
202	sndhdr.msg_iov[0].iov_base = ifp->rs;
203	sndhdr.msg_iov[0].iov_len = ifp->rslen;
204
205	/* Set the outbound interface */
206	cm = CMSG_FIRSTHDR(&sndhdr);
207	cm->cmsg_level = IPPROTO_IPV6;
208	cm->cmsg_type = IPV6_PKTINFO;
209	cm->cmsg_len = CMSG_LEN(sizeof(pi));
210	memset(&pi, 0, sizeof(pi));
211	pi.ipi6_ifindex = if_nametoindex(ifp->name);
212	memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
213
214	/* Hop limit */
215	cm = CMSG_NXTHDR(&sndhdr, cm);
216	cm->cmsg_level = IPPROTO_IPV6;
217	cm->cmsg_type = IPV6_HOPLIMIT;
218	cm->cmsg_len = CMSG_LEN(sizeof(hoplimit));
219	memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit));
220
221	syslog(LOG_INFO, "%s: sending IPv6 Router Solicitation", ifp->name);
222	if (sendmsg(sock, &sndhdr, 0) == -1)
223		syslog(LOG_ERR, "%s: sendmsg: %m", ifp->name);
224
225	if (ifp->rsprobes++ < MAX_RTR_SOLICITATIONS)
226		add_timeout_sec(RTR_SOLICITATION_INTERVAL,
227		    ipv6rs_sendprobe, ifp);
228	else
229		syslog(LOG_INFO, "%s: no IPv6 Routers available", ifp->name);
230}
231
232static void
233ipv6rs_sort(struct interface *ifp)
234{
235	struct ra *rap, *sorted, *ran, *rat;
236
237	if (ifp->ras == NULL || ifp->ras->next == NULL)
238		return;
239
240	/* Sort our RA's - most recent first */
241	sorted = ifp->ras;
242	ifp->ras = ifp->ras->next;
243	sorted->next = NULL;
244	for (rap = ifp->ras; rap && (ran = rap->next, 1); rap = ran) {
245		/* Are we the new head? */
246		if (timercmp(&rap->received, &sorted->received, <)) {
247			rap->next = sorted;
248			sorted = rap;
249			continue;
250		}
251		/* Do we fit in the middle? */
252		for (rat = sorted; rat->next; rat = rat->next) {
253			if (timercmp(&rap->received, &rat->next->received, <)) {
254				rap->next = rat->next;
255				rat->next = rap;
256				break;
257			}
258		}
259		/* We must be at the end */
260		if (!rat->next) {
261			rat->next = rap;
262			rap->next = NULL;
263		}
264	}
265}
266
267void
268ipv6rs_handledata(_unused void *arg)
269{
270	ssize_t len, l, n, olen;
271	struct cmsghdr *cm;
272	int hoplimit;
273	struct in6_pktinfo pkt;
274	struct icmp6_hdr *icp;
275	struct interface *ifp;
276	const char *sfrom;
277	struct nd_router_advert *nd_ra;
278	struct nd_opt_prefix_info *pi;
279	struct nd_opt_mtu *mtu;
280	struct nd_opt_rdnss *rdnss;
281	struct nd_opt_dnssl *dnssl;
282	uint32_t lifetime;
283	uint8_t *p, *op;
284	struct in6_addr addr;
285	char buf[INET6_ADDRSTRLEN];
286	const char *cbp;
287	struct ra *rap;
288	struct nd_opt_hdr *ndo;
289	struct ra_opt *rao, *raol;
290	char *opt;
291	struct timeval expire;
292	int has_dns;
293
294	len = recvmsg(sock, &rcvhdr, 0);
295	if (len == -1) {
296		syslog(LOG_ERR, "recvmsg: %m");
297		return;
298	}
299	sfrom = inet_ntop(AF_INET6, &from.sin6_addr,
300	    ntopbuf, INET6_ADDRSTRLEN);
301	if ((size_t)len < sizeof(struct nd_router_advert)) {
302		syslog(LOG_ERR, "IPv6 RA packet too short from %s", sfrom);
303		return;
304	}
305
306	pkt.ipi6_ifindex = hoplimit = 0;
307	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvhdr);
308	     cm;
309	     cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvhdr, cm))
310	{
311		if (cm->cmsg_level != IPPROTO_IPV6)
312			continue;
313		switch(cm->cmsg_type) {
314		case IPV6_PKTINFO:
315			if (cm->cmsg_len == CMSG_LEN(sizeof(pkt)))
316				memcpy(&pkt, CMSG_DATA(cm), sizeof(pkt));
317			break;
318		case IPV6_HOPLIMIT:
319			if (cm->cmsg_len == CMSG_LEN(sizeof(int)))
320				memcpy(&hoplimit, CMSG_DATA(cm), sizeof(int));
321			break;
322		}
323	}
324
325	if (pkt.ipi6_ifindex == 0 || hoplimit == 0) {
326		syslog(LOG_ERR,
327		    "IPv6 RA did not contain index or hop limit from %s",
328		    sfrom);
329		return;
330	}
331
332	icp = (struct icmp6_hdr *)rcvhdr.msg_iov[0].iov_base;
333	if (icp->icmp6_type != ND_ROUTER_ADVERT ||
334	    icp->icmp6_code != 0)
335	{
336		syslog(LOG_ERR, "invalid IPv6 type or code from %s", sfrom);
337		return;
338	}
339
340	if (!IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) {
341		syslog(LOG_ERR, "RA recieved from non local IPv6 address %s",
342		    sfrom);
343		return;
344	}
345
346	for (ifp = ifaces; ifp; ifp = ifp->next)
347		if (if_nametoindex(ifp->name) == (unsigned int)pkt.ipi6_ifindex)
348			break;
349	if (ifp == NULL) {
350		syslog(LOG_ERR,"received RA for unexpected interface from %s",
351		    sfrom);
352		return;
353	}
354	for (rap = ifp->ras; rap; rap = rap->next) {
355		if (memcmp(rap->from.s6_addr, from.sin6_addr.s6_addr,
356		    sizeof(rap->from.s6_addr)) == 0)
357			break;
358	}
359
360	/* We don't want to spam the log with the fact we got an RA every
361	 * 30 seconds or so, so only spam the log if it's different. */
362	if (options & DHCPCD_DEBUG || rap == NULL ||
363	    (rap->expired || rap->data_len != len ||
364	     memcmp(rap->data, (unsigned char *)icp, rap->data_len) != 0))
365	{
366		if (rap) {
367			free(rap->data);
368			rap->data_len = 0;
369		}
370		syslog(LOG_INFO, "%s: Router Advertisement from %s",
371		    ifp->name, sfrom);
372	}
373
374	if (rap == NULL) {
375		rap = xmalloc(sizeof(*rap));
376		rap->next = ifp->ras;
377		rap->options = NULL;
378		ifp->ras = rap;
379		memcpy(rap->from.s6_addr, from.sin6_addr.s6_addr,
380		    sizeof(rap->from.s6_addr));
381		strlcpy(rap->sfrom, sfrom, sizeof(rap->sfrom));
382		rap->data_len = 0;
383	}
384	if (rap->data_len == 0) {
385		rap->data = xmalloc(len);
386		memcpy(rap->data, icp, len);
387		rap->data_len = len;
388	}
389
390	get_monotonic(&rap->received);
391	nd_ra = (struct nd_router_advert *)icp;
392	rap->lifetime = ntohs(nd_ra->nd_ra_router_lifetime);
393	rap->expired = 0;
394
395	len -= sizeof(struct nd_router_advert);
396	p = ((uint8_t *)icp) + sizeof(struct nd_router_advert);
397	olen = 0;
398	lifetime = ~0U;
399	has_dns = 0;
400	for (olen = 0; len > 0; p += olen, len -= olen) {
401		if ((size_t)len < sizeof(struct nd_opt_hdr)) {
402			syslog(LOG_ERR, "%s: Short option", ifp->name);
403			break;
404		}
405		ndo = (struct nd_opt_hdr *)p;
406		olen = ndo->nd_opt_len * 8 ;
407		if (olen == 0) {
408			syslog(LOG_ERR, "%s: zero length option", ifp->name);
409			break;
410		}
411		if (olen > len) {
412			syslog(LOG_ERR,
413			    "%s: Option length exceeds message", ifp->name);
414			break;
415		}
416
417		opt = NULL;
418		switch (ndo->nd_opt_type) {
419		case ND_OPT_PREFIX_INFORMATION:
420			pi = (struct nd_opt_prefix_info *)ndo;
421			if (pi->nd_opt_pi_len != 4) {
422				syslog(LOG_ERR,
423				    "%s: invalid option len for prefix",
424				    ifp->name);
425				break;
426			}
427			if (pi->nd_opt_pi_prefix_len > 128) {
428				syslog(LOG_ERR, "%s: invalid prefix len",
429				    ifp->name);
430				break;
431			}
432			if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) ||
433			    IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix))
434			{
435				syslog(LOG_ERR,
436				    "%s: invalid prefix in RA", ifp->name);
437				break;
438			}
439			opt = xstrdup(inet_ntop(AF_INET6,
440			    pi->nd_opt_pi_prefix.s6_addr,
441			    ntopbuf, INET6_ADDRSTRLEN));
442			if (opt) {
443				rap->prefix_len = pi->nd_opt_pi_prefix_len;
444				rap->prefix_vltime =
445					ntohl(pi->nd_opt_pi_valid_time);
446				rap->prefix_pltime =
447					ntohl(pi->nd_opt_pi_preferred_time);
448			}
449			break;
450
451		case ND_OPT_MTU:
452			mtu = (struct nd_opt_mtu *)p;
453			snprintf(buf, sizeof(buf), "%d",
454			    ntohl(mtu->nd_opt_mtu_mtu));
455			opt = xstrdup(buf);
456			break;
457
458		case ND_OPT_RDNSS:
459			rdnss = (struct nd_opt_rdnss *)p;
460			lifetime = ntohl(rdnss->nd_opt_rdnss_lifetime);
461			op = (uint8_t *)ndo;
462			op += offsetof(struct nd_opt_rdnss,
463			    nd_opt_rdnss_lifetime);
464			op += sizeof(rdnss->nd_opt_rdnss_lifetime);
465			l = 0;
466			for (n = ndo->nd_opt_len - 1; n > 1; n -= 2) {
467				memcpy(&addr.s6_addr, op, sizeof(addr.s6_addr));
468				cbp = inet_ntop(AF_INET6, &addr,
469				    ntopbuf, INET6_ADDRSTRLEN);
470				if (cbp == NULL) {
471					syslog(LOG_ERR,
472					    "%s: invalid RDNSS address",
473					    ifp->name);
474				} else {
475					if (opt) {
476						l = strlen(opt);
477						opt = xrealloc(opt,
478							l + strlen(cbp) + 2);
479						opt[l] = ' ';
480						strcpy(opt + l + 1, cbp);
481					} else
482						opt = xstrdup(cbp);
483					if (lifetime > 0)
484						has_dns = 1;
485				}
486		        	op += sizeof(addr.s6_addr);
487			}
488			break;
489
490		case ND_OPT_DNSSL:
491			dnssl = (struct nd_opt_dnssl *)p;
492			lifetime = ntohl(dnssl->nd_opt_dnssl_lifetime);
493			op = p + offsetof(struct nd_opt_dnssl,
494			    nd_opt_dnssl_lifetime);
495			op += sizeof(dnssl->nd_opt_dnssl_lifetime);
496			n = (dnssl->nd_opt_dnssl_len - 1) * 8;
497			l = decode_rfc3397(NULL, 0, n, op);
498			if (l < 1) {
499				syslog(LOG_ERR, "%s: invalid DNSSL option",
500				    ifp->name);
501			} else {
502				opt = xmalloc(l);
503				decode_rfc3397(opt, l, n, op);
504			}
505			break;
506		}
507
508		if (opt == NULL)
509			continue;
510		for (raol = NULL, rao = rap->options;
511		    rao;
512		    raol = rao, rao = rao->next)
513		{
514			if (rao->type == ndo->nd_opt_type &&
515			    strcmp(rao->option, opt) == 0)
516				break;
517		}
518		if (lifetime == 0) {
519			if (rao) {
520				if (raol)
521					raol->next = rao->next;
522				else
523					rap->options = rao->next;
524				free(rao->option);
525				free(rao);
526			}
527			continue;
528		}
529
530		if (rao == NULL) {
531			rao = xmalloc(sizeof(*rao));
532			rao->next = rap->options;
533			rap->options = rao;
534			rao->type = ndo->nd_opt_type;
535			rao->option = opt;
536		} else
537			free(opt);
538		if (lifetime == ~0U)
539			timerclear(&rao->expire);
540		else {
541			expire.tv_sec = lifetime;
542			expire.tv_usec = 0;
543			timeradd(&rap->received, &expire, &rao->expire);
544		}
545	}
546
547	ipv6rs_sort(ifp);
548	run_script_reason(ifp, options & DHCPCD_TEST ? "TEST" : "ROUTERADVERT");
549	if (options & DHCPCD_TEST)
550		exit(EXIT_SUCCESS);
551
552	/* If we don't require RDNSS then set has_dns = 1 so we fork */
553	if (!(ifp->state->options->options & DHCPCD_IPV6RA_REQRDNSS))
554		has_dns = 1;
555
556	if (has_dns)
557		delete_q_timeout(0, handle_exit_timeout, NULL);
558	delete_timeout(NULL, ifp);
559	ipv6rs_expire(ifp);
560	if (has_dns)
561		daemonise();
562	else if (options & DHCPCD_DAEMONISE && !(options & DHCPCD_DAEMONISED))
563		syslog(LOG_WARNING,
564		    "%s: did not fork due to an absent RDNSS option in the RA",
565		    ifp->name);
566}
567
568ssize_t
569ipv6rs_env(char **env, const char *prefix, const struct interface *ifp)
570{
571	ssize_t l;
572	struct timeval now;
573	const struct ra *rap;
574	const struct ra_opt *rao;
575	int i;
576	char buffer[32], buffer2[32];
577	const char *optn;
578
579	l = 0;
580	get_monotonic(&now);
581	for (rap = ifp->ras, i = 1; rap; rap = rap->next, i++) {
582		if (env) {
583			snprintf(buffer, sizeof(buffer),
584			    "ra%d_from", i);
585			setvar(&env, prefix, buffer, rap->sfrom);
586		}
587		l++;
588
589		for (rao = rap->options; rao; rao = rao->next) {
590			if (rao->option == NULL)
591				continue;
592			if (env == NULL) {
593				switch (rao->type) {
594				case ND_OPT_PREFIX_INFORMATION:
595					l += 4;
596					break;
597				default:
598					l++;
599				}
600				continue;
601			}
602			switch (rao->type) {
603			case ND_OPT_PREFIX_INFORMATION:
604				optn = "prefix";
605				break;
606			case ND_OPT_MTU:
607				optn = "mtu";
608				break;
609			case ND_OPT_RDNSS:
610				optn = "rdnss";
611				break;
612			case ND_OPT_DNSSL:
613				optn = "dnssl";
614				break;
615			default:
616				continue;
617			}
618			snprintf(buffer, sizeof(buffer), "ra%d_%s", i, optn);
619			setvar(&env, prefix, buffer, rao->option);
620			l++;
621			switch (rao->type) {
622			case ND_OPT_PREFIX_INFORMATION:
623				snprintf(buffer, sizeof(buffer),
624				    "ra%d_prefix_len", i);
625				snprintf(buffer2, sizeof(buffer2),
626				    "%d", rap->prefix_len);
627				setvar(&env, prefix, buffer, buffer2);
628
629				snprintf(buffer, sizeof(buffer),
630				    "ra%d_prefix_vltime", i);
631				snprintf(buffer2, sizeof(buffer2),
632				    "%d", rap->prefix_vltime);
633				setvar(&env, prefix, buffer, buffer2);
634
635				snprintf(buffer, sizeof(buffer),
636				    "ra%d_prefix_pltime", i);
637				snprintf(buffer2, sizeof(buffer2),
638				    "%d", rap->prefix_pltime);
639				setvar(&env, prefix, buffer, buffer2);
640				l += 3;
641				break;
642			}
643
644		}
645	}
646
647	if (env)
648		setvard(&env, prefix, "ra_count", i - 1);
649	l++;
650	return l;
651}
652
653static void
654ipv6rs_free_opts(struct ra *rap)
655{
656	struct ra_opt *rao, *raon;
657
658	for (rao = rap->options; rao && (raon = rao->next, 1); rao = raon) {
659		free(rao->option);
660		free(rao);
661	}
662}
663
664void
665ipv6rs_free(struct interface *ifp)
666{
667	struct ra *rap, *ran;
668
669	free(ifp->rs);
670	ifp->rs = NULL;
671	for (rap = ifp->ras; rap && (ran = rap->next, 1); rap = ran) {
672		ipv6rs_free_opts(rap);
673		free(rap->data);
674		free(rap);
675	}
676	ifp->ras = NULL;
677}
678
679void
680ipv6rs_expire(void *arg)
681{
682	struct interface *ifp;
683	struct ra *rap, *ran, *ral;
684	struct ra_opt *rao, *raol, *raon;
685	struct timeval now, lt, expire, next;
686	int expired;
687	uint32_t expire_secs;
688
689	ifp = arg;
690	get_monotonic(&now);
691	expired = 0;
692	expire_secs = ~0U;
693	timerclear(&next);
694
695	for (rap = ifp->ras, ral = NULL;
696	    rap && (ran = rap->next, 1);
697	    ral = rap, rap = ran)
698	{
699		lt.tv_sec = rap->lifetime;
700		lt.tv_usec = 0;
701		timeradd(&rap->received, &lt, &expire);
702		if (timercmp(&now, &expire, >)) {
703			syslog(LOG_INFO, "%s: %s: expired Router Advertisement",
704			    ifp->name, rap->sfrom);
705			rap->expired = expired = 1;
706			if (ral)
707				ral->next = ran;
708			else
709				ifp->ras = ran;
710			ipv6rs_free_opts(rap);
711			free(rap);
712			continue;
713		}
714		timersub(&expire, &now, &lt);
715		if (!timerisset(&next) || timercmp(&next, &lt, >))
716			next = lt;
717
718		for (rao = rap->options, raol = NULL;
719		    rao && (raon = rao->next);
720		    raol = rao, rao = raon)
721		{
722			if (!timerisset(&rao->expire))
723				continue;
724			if (timercmp(&now, &rao->expire, >)) {
725				syslog(LOG_INFO,
726				    "%s: %s: expired option %d",
727				    ifp->name, rap->sfrom, rao->type);
728				rap->expired = expired = 1;
729				if (raol)
730					raol = raon;
731				else
732					rap->options = raon;
733				continue;
734			}
735			timersub(&rao->expire, &now, &lt);
736			if (!timerisset(&next) || timercmp(&next, &lt, >))
737				next = lt;
738		}
739	}
740
741	if (timerisset(&next))
742		add_timeout_tv(&next, ipv6rs_expire, ifp);
743	if (expired)
744		run_script_reason(ifp, "ROUTERADVERT");
745}
746
747int
748ipv6rs_start(struct interface *ifp)
749{
750
751	delete_timeout(NULL, ifp);
752
753	/* Always make a new probe as the underlying hardware
754	 * address could have changed. */
755	ipv6rs_makeprobe(ifp);
756	if (ifp->rs == NULL)
757		return -1;
758
759	ifp->rsprobes = 0;
760	ipv6rs_sendprobe(ifp);
761	return 0;
762}
763