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