]> git.ipfire.org Git - people/ms/dnsmasq.git/blame - src/radv.c
Upply --bridge-interface aliasing to solicited router advertisements.
[people/ms/dnsmasq.git] / src / radv.c
CommitLineData
aff33962 1/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
c5ad4e79
SK
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
15*/
16
17
843c96b4 18/* NB. This code may be called during a DHCPv4 or transaction which is in ping-wait
c5ad4e79 19 It therefore cannot use any DHCP buffer resources except outpacket, which is
843c96b4
SK
20 not used by DHCPv4 code. This code may also be called when DHCP 4 or 6 isn't
21 active, so we ensure that outpacket is allocated here too */
c5ad4e79
SK
22
23#include "dnsmasq.h"
c5ad4e79
SK
24
25#ifdef HAVE_DHCP6
26
22d904db
SK
27#include <netinet/icmp6.h>
28
c5ad4e79 29struct ra_param {
1f776932 30 time_t now;
7ea3d3fd 31 int ind, managed, other, found_context, first, adv_router;
c5ad4e79 32 char *if_name;
18f0fb05 33 struct dhcp_netid *tags;
c3a04081 34 struct in6_addr link_local, link_global, ula;
5bf50af2 35 unsigned int glob_pref_time, link_pref_time, ula_pref_time, adv_interval, prio;
c5ad4e79
SK
36};
37
38struct search_param {
39 time_t now; int iface;
c4cd95df 40 char name[IF_NAMESIZE+1];
c5ad4e79
SK
41};
42
1f776932 43static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest);
ba4fc0f9
NJ
44static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_addr *dest,
45 int send_iface);
c5ad4e79 46static int add_prefixes(struct in6_addr *local, int prefix,
bad7b875 47 int scope, int if_index, int flags,
55b42f6d 48 unsigned int preferred, unsigned int valid, void *vparam);
c5ad4e79 49static int iface_search(struct in6_addr *local, int prefix,
bad7b875 50 int scope, int if_index, int flags,
1f776932 51 int prefered, int valid, void *vparam);
c5ad4e79 52static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
c4cd95df
SK
53static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now);
54static unsigned int calc_lifetime(struct ra_interface *ra);
55static unsigned int calc_interval(struct ra_interface *ra);
56static unsigned int calc_prio(struct ra_interface *ra);
57static struct ra_interface *find_iface_param(char *iface);
c5ad4e79 58
c5379c1a 59static int hop_limit;
c5ad4e79
SK
60
61void ra_init(time_t now)
62{
c5ad4e79
SK
63 struct icmp6_filter filter;
64 int fd;
0e88d53f 65#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
c5ad4e79
SK
66 int class = IPTOS_CLASS_CS6;
67#endif
68 int val = 255; /* radvd uses this value */
7b6dd880 69 socklen_t len = sizeof(int);
353ae4d2
SK
70 struct dhcp_context *context;
71
843c96b4
SK
72 /* ensure this is around even if we're not doing DHCPv6 */
73 expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
353ae4d2
SK
74
75 /* See if we're guessing SLAAC addresses, if so we need to recieve ping replies */
1f776932 76 for (context = daemon->dhcp6; context; context = context->next)
353ae4d2
SK
77 if ((context->flags & CONTEXT_RA_NAME))
78 break;
79
89500e31
SK
80 /* Need ICMP6 socket for transmission for DHCPv6 even when not doing RA. */
81
c5ad4e79 82 ICMP6_FILTER_SETBLOCKALL(&filter);
89500e31
SK
83 if (daemon->doing_ra)
84 {
85 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
86 if (context)
87 ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
88 }
c5ad4e79
SK
89
90 if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 ||
c5379c1a 91 getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) ||
0e88d53f 92#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
c5ad4e79
SK
93 setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
94#endif
95 !fix_fd(fd) ||
96 !set_ipv6pktinfo(fd) ||
97 setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val)) ||
98 setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val)) ||
99 setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) == -1)
100 die (_("cannot create ICMPv6 socket: %s"), NULL, EC_BADNET);
101
102 daemon->icmp6fd = fd;
103
89500e31
SK
104 if (daemon->doing_ra)
105 ra_start_unsolicted(now, NULL);
c5ad4e79
SK
106}
107
353ae4d2 108void ra_start_unsolicted(time_t now, struct dhcp_context *context)
c5ad4e79 109{
353ae4d2 110 /* init timers so that we do ra's for some/all soon. some ra_times will end up zeroed
c5ad4e79
SK
111 if it's not appropriate to advertise those contexts.
112 This gets re-called on a netlink route-change to re-do the advertisement
113 and pick up new interfaces */
6e3dba3f 114
353ae4d2 115 if (context)
1b75c1e6 116 context->ra_short_period_start = context->ra_time = now;
353ae4d2 117 else
1f776932 118 for (context = daemon->dhcp6; context; context = context->next)
6e3dba3f 119 if (!(context->flags & CONTEXT_TEMPLATE))
1b75c1e6
SK
120 {
121 context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
122 /* re-do frequently for a minute or so, in case the first gets lost. */
123 context->ra_short_period_start = now;
124 }
c5ad4e79
SK
125}
126
1f776932 127void icmp6_packet(time_t now)
c5ad4e79
SK
128{
129 char interface[IF_NAMESIZE+1];
130 ssize_t sz;
131 int if_index = 0;
132 struct cmsghdr *cmptr;
133 struct msghdr msg;
134 union {
135 struct cmsghdr align; /* this ensures alignment */
136 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
137 } control_u;
138 struct sockaddr_in6 from;
5ef33279 139 unsigned char *packet;
c5ad4e79 140 struct iname *tmp;
c5ad4e79
SK
141
142 /* Note: use outpacket for input buffer */
143 msg.msg_control = control_u.control6;
144 msg.msg_controllen = sizeof(control_u);
145 msg.msg_flags = 0;
146 msg.msg_name = &from;
147 msg.msg_namelen = sizeof(from);
148 msg.msg_iov = &daemon->outpacket;
149 msg.msg_iovlen = 1;
150
151 if ((sz = recv_dhcp_packet(daemon->icmp6fd, &msg)) == -1 || sz < 8)
152 return;
5ef33279
SK
153
154 packet = (unsigned char *)daemon->outpacket.iov_base;
c5ad4e79
SK
155
156 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
157 if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
158 {
159 union {
160 unsigned char *c;
161 struct in6_pktinfo *p;
162 } p;
163 p.c = CMSG_DATA(cmptr);
164
165 if_index = p.p->ipi6_ifindex;
166 }
167
168 if (!indextoname(daemon->icmp6fd, if_index, interface))
169 return;
170
4f7b304f 171 if (!iface_check(AF_LOCAL, NULL, interface, NULL))
c5ad4e79
SK
172 return;
173
174 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
49333cbd 175 if (tmp->name && wildcard_match(tmp->name, interface))
c5ad4e79
SK
176 return;
177
8bc4cece 178 if (packet[1] != 0)
353ae4d2 179 return;
8bc4cece 180
5ef33279
SK
181 if (packet[0] == ICMP6_ECHO_REPLY)
182 lease_ping_reply(&from.sin6_addr, packet, interface);
183 else if (packet[0] == ND_ROUTER_SOLICIT)
c5ad4e79 184 {
5ef33279 185 char *mac = "";
ba4fc0f9 186 struct dhcp_bridge *bridge, *alias;
5ef33279
SK
187
188 /* look for link-layer address option for logging */
189 if (sz >= 16 && packet[8] == ICMP6_OPT_SOURCE_MAC && (packet[9] * 8) + 8 <= sz)
190 {
191 print_mac(daemon->namebuff, &packet[10], (packet[9] * 8) - 2);
192 mac = daemon->namebuff;
193 }
194
8c0b73d3
KDB
195 if (!option_bool(OPT_QUIET_RA))
196 my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
ba4fc0f9
NJ
197
198 /* If the incoming interface is an alias of some other one (as
199 specified by the --bridge-interfaces option), send an RA
200 using the context of the aliased interface. */
201 for (bridge = daemon->bridges; bridge; bridge = bridge->next)
202 {
203 int bridge_index = if_nametoindex(bridge->iface);
204 if (bridge_index)
205 {
206 for (alias = bridge->alias; alias; alias = alias->next)
207 if (wildcard_matchn(alias->iface, interface, IF_NAMESIZE))
208 {
209 /* Send an RA on if_index with information from
210 bridge_index. */
211 send_ra_alias(now, bridge_index, bridge->iface, NULL, if_index);
212 break;
213 }
214 if (alias)
215 break;
216 }
217 }
218
219 /* If the incoming interface wasn't an alias, send an RA using
220 the context of the incoming interface. */
221 if (!bridge)
222 /* source address may not be valid in solicit request. */
223 send_ra(now, if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
c5ad4e79 224 }
c5ad4e79
SK
225}
226
ba4fc0f9 227static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_addr *dest, int send_iface)
c5ad4e79
SK
228{
229 struct ra_packet *ra;
230 struct ra_param parm;
c5ad4e79 231 struct sockaddr_in6 addr;
ef1a94ab 232 struct dhcp_context *context, *tmp, **up;
18f0fb05
SK
233 struct dhcp_netid iface_id;
234 struct dhcp_opt *opt_cfg;
c4cd95df 235 struct ra_interface *ra_param = find_iface_param(iface_name);
44522920 236 int done_dns = 0, old_prefix = 0;
c3a04081 237 unsigned int min_pref_time;
3b43646a
SK
238#ifdef HAVE_LINUX_NETWORK
239 FILE *f;
240#endif
c5ad4e79 241
c5ad4e79
SK
242 parm.ind = iface;
243 parm.managed = 0;
30cd9666 244 parm.other = 0;
c5ad4e79 245 parm.found_context = 0;
7ea3d3fd 246 parm.adv_router = 0;
c5ad4e79
SK
247 parm.if_name = iface_name;
248 parm.first = 1;
1f776932 249 parm.now = now;
c3a04081 250 parm.glob_pref_time = parm.link_pref_time = parm.ula_pref_time = 0;
c4cd95df 251 parm.adv_interval = calc_interval(ra_param);
5bf50af2
IP
252 parm.prio = calc_prio(ra_param);
253
254 save_counter(0);
255 ra = expand(sizeof(struct ra_packet));
1f776932 256
5bf50af2
IP
257 ra->type = ND_ROUTER_ADVERT;
258 ra->code = 0;
259 ra->hop_limit = hop_limit;
260 ra->flags = parm.prio;
261 ra->lifetime = htons(calc_lifetime(ra_param));
262 ra->reachable_time = 0;
263 ra->retrans_time = 0;
264
18f0fb05
SK
265 /* set tag with name == interface */
266 iface_id.net = iface_name;
267 iface_id.next = NULL;
268 parm.tags = &iface_id;
c5ad4e79 269
1f776932 270 for (context = daemon->dhcp6; context; context = context->next)
18f0fb05
SK
271 {
272 context->flags &= ~CONTEXT_RA_DONE;
273 context->netid.next = &context->netid;
274 }
275
ef1a94ab 276 if (!iface_enumerate(AF_INET6, &parm, add_prefixes))
c5ad4e79
SK
277 return;
278
c3a04081
SK
279 /* Find smallest preferred time within address classes,
280 to use as lifetime for options. This is a rather arbitrary choice. */
281 min_pref_time = 0xffffffff;
282 if (parm.glob_pref_time != 0 && parm.glob_pref_time < min_pref_time)
283 min_pref_time = parm.glob_pref_time;
284
285 if (parm.ula_pref_time != 0 && parm.ula_pref_time < min_pref_time)
286 min_pref_time = parm.ula_pref_time;
287
288 if (parm.link_pref_time != 0 && parm.link_pref_time < min_pref_time)
289 min_pref_time = parm.link_pref_time;
290
ef1a94ab
SK
291 /* Look for constructed contexts associated with addresses which have gone,
292 and advertise them with preferred_time == 0 RFC 6204 4.3 L-13 */
293 for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
294 {
295 tmp = context->next;
3b43646a 296
ef1a94ab
SK
297 if (context->if_index == iface && (context->flags & CONTEXT_OLD))
298 {
299 unsigned int old = difftime(now, context->address_lost_time);
300
301 if (old > context->saved_valid)
302 {
303 /* We've advertised this enough, time to go */
304 *up = context->next;
305 free(context);
306 }
307 else
308 {
309 struct prefix_opt *opt;
310 struct in6_addr local = context->start6;
311 int do_slaac = 0;
312
44522920 313 old_prefix = 1;
ef1a94ab
SK
314
315 /* zero net part of address */
316 setaddr6part(&local, addr6part(&local) & ~((context->prefix == 64) ? (u64)-1LL : (1LLU << (128 - context->prefix)) - 1LLU));
317
6ea1f23b 318
7ea3d3fd 319 if (context->flags & CONTEXT_RA)
6ea1f23b
SK
320 {
321 do_slaac = 1;
322 if (context->flags & CONTEXT_DHCP)
323 {
324 parm.other = 1;
325 if (!(context->flags & CONTEXT_RA_STATELESS))
326 parm.managed = 1;
327 }
328 }
329 else
330 {
331 /* don't do RA for non-ra-only unless --enable-ra is set */
332 if (option_bool(OPT_RA))
333 {
334 parm.managed = 1;
335 parm.other = 1;
336 }
337 }
338
ef1a94ab
SK
339 if ((opt = expand(sizeof(struct prefix_opt))))
340 {
341 opt->type = ICMP6_OPT_PREFIX;
342 opt->len = 4;
343 opt->prefix_len = context->prefix;
2fd5bc95
NJ
344 /* autonomous only if we're not doing dhcp, set
345 "on-link" unless "off-link" was specified */
346 opt->flags = (do_slaac ? 0x40 : 0) |
347 ((context->flags & CONTEXT_RA_OFF_LINK) ? 0 : 0x80);
ef1a94ab
SK
348 opt->valid_lifetime = htonl(context->saved_valid - old);
349 opt->preferred_lifetime = htonl(0);
350 opt->reserved = 0;
351 opt->prefix = local;
352
353 inet_ntop(AF_INET6, &local, daemon->addrbuff, ADDRSTRLEN);
8c0b73d3
KDB
354 if (!option_bool(OPT_QUIET_RA))
355 my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s old prefix", iface_name, daemon->addrbuff);
ef1a94ab
SK
356 }
357
358 up = &context->next;
359 }
360 }
361 else
362 up = &context->next;
363 }
364
44522920
SK
365 /* If we're advertising only old prefixes, set router lifetime to zero. */
366 if (old_prefix && !parm.found_context)
367 ra->lifetime = htons(0);
368
369 /* No prefixes to advertise. */
370 if (!old_prefix && !parm.found_context)
371 return;
372
7ea3d3fd
SK
373 /* If we're sending router address instead of prefix in at least on prefix,
374 include the advertisement interval option. */
375 if (parm.adv_router)
376 {
377 put_opt6_char(ICMP6_OPT_ADV_INTERVAL);
378 put_opt6_char(1);
379 put_opt6_short(0);
380 /* interval value is in milliseconds */
381 put_opt6_long(1000 * calc_interval(find_iface_param(iface_name)));
382 }
383
3b43646a
SK
384#ifdef HAVE_LINUX_NETWORK
385 /* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU
386 available from SIOCGIFMTU */
387 sprintf(daemon->namebuff, "/proc/sys/net/ipv6/conf/%s/mtu", iface_name);
388 if ((f = fopen(daemon->namebuff, "r")))
c5ad4e79 389 {
3b43646a
SK
390 if (fgets(daemon->namebuff, MAXDNAME, f))
391 {
392 put_opt6_char(ICMP6_OPT_MTU);
393 put_opt6_char(1);
394 put_opt6_short(0);
395 put_opt6_long(atoi(daemon->namebuff));
396 }
397 fclose(f);
c5ad4e79 398 }
3b43646a 399#endif
c5ad4e79 400
ba4fc0f9 401 iface_enumerate(AF_LOCAL, &send_iface, add_lla);
18f0fb05
SK
402
403 /* RDNSS, RFC 6106, use relevant DHCP6 options */
404 (void)option_filter(parm.tags, NULL, daemon->dhcp_opts6);
c5ad4e79 405
18f0fb05
SK
406 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
407 {
408 int i;
409
410 /* netids match and not encapsulated? */
411 if (!(opt_cfg->flags & DHOPT_TAGOK))
412 continue;
413
414 if (opt_cfg->opt == OPTION6_DNS_SERVER)
415 {
c3a04081
SK
416 struct in6_addr *a;
417 int len;
418
18f0fb05 419 done_dns = 1;
c3a04081
SK
420
421 if (opt_cfg->len == 0)
806cf787 422 continue;
18f0fb05 423
c3a04081
SK
424 /* reduce len for any addresses we can't substitute */
425 for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, i = 0;
426 i < opt_cfg->len; i += IN6ADDRSZ, a++)
427 if ((IN6_IS_ADDR_UNSPECIFIED(a) && parm.glob_pref_time == 0) ||
428 (IN6_IS_ADDR_ULA_ZERO(a) && parm.ula_pref_time == 0) ||
429 (IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && parm.link_pref_time == 0))
430 len -= IN6ADDRSZ;
431
432 if (len != 0)
433 {
434 put_opt6_char(ICMP6_OPT_RDNSS);
435 put_opt6_char((len/8) + 1);
436 put_opt6_short(0);
437 put_opt6_long(min_pref_time);
438
439 for (a = (struct in6_addr *)opt_cfg->val, i = 0; i < opt_cfg->len; i += IN6ADDRSZ, a++)
440 if (IN6_IS_ADDR_UNSPECIFIED(a))
441 {
442 if (parm.glob_pref_time != 0)
443 put_opt6(&parm.link_global, IN6ADDRSZ);
444 }
445 else if (IN6_IS_ADDR_ULA_ZERO(a))
446 {
447 if (parm.ula_pref_time != 0)
448 put_opt6(&parm.ula, IN6ADDRSZ);
449 }
450 else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
451 {
452 if (parm.link_pref_time != 0)
453 put_opt6(&parm.link_local, IN6ADDRSZ);
454 }
455 else
456 put_opt6(a, IN6ADDRSZ);
457 }
18f0fb05
SK
458 }
459
460 if (opt_cfg->opt == OPTION6_DOMAIN_SEARCH && opt_cfg->len != 0)
461 {
462 int len = ((opt_cfg->len+7)/8);
463
464 put_opt6_char(ICMP6_OPT_DNSSL);
465 put_opt6_char(len + 1);
466 put_opt6_short(0);
c3a04081 467 put_opt6_long(min_pref_time);
18f0fb05
SK
468 put_opt6(opt_cfg->val, opt_cfg->len);
469
470 /* pad */
471 for (i = opt_cfg->len; i < len * 8; i++)
472 put_opt6_char(0);
473 }
474 }
475
c3a04081 476 if (daemon->port == NAMESERVER_PORT && !done_dns && parm.link_pref_time != 0)
18f0fb05 477 {
ab915f83 478 /* default == us, as long as we are supplying DNS service. */
18f0fb05
SK
479 put_opt6_char(ICMP6_OPT_RDNSS);
480 put_opt6_char(3);
481 put_opt6_short(0);
c3a04081 482 put_opt6_long(min_pref_time);
806cf787 483 put_opt6(&parm.link_local, IN6ADDRSZ);
18f0fb05 484 }
c5ad4e79
SK
485
486 /* set managed bits unless we're providing only RA on this link */
487 if (parm.managed)
30cd9666
SK
488 ra->flags |= 0x80; /* M flag, managed, */
489 if (parm.other)
490 ra->flags |= 0x40; /* O flag, other */
491
c5ad4e79
SK
492 /* decide where we're sending */
493 memset(&addr, 0, sizeof(addr));
22d904db
SK
494#ifdef HAVE_SOCKADDR_SA_LEN
495 addr.sin6_len = sizeof(struct sockaddr_in6);
496#endif
c5ad4e79
SK
497 addr.sin6_family = AF_INET6;
498 addr.sin6_port = htons(IPPROTO_ICMPV6);
499 if (dest)
500 {
353ae4d2 501 addr.sin6_addr = *dest;
c5ad4e79
SK
502 if (IN6_IS_ADDR_LINKLOCAL(dest) ||
503 IN6_IS_ADDR_MC_LINKLOCAL(dest))
504 addr.sin6_scope_id = iface;
505 }
506 else
8f3194f7
SK
507 {
508 inet_pton(AF_INET6, ALL_NODES, &addr.sin6_addr);
ba4fc0f9 509 setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &send_iface, sizeof(send_iface));
8f3194f7 510 }
22d904db 511
ff841ebf
SK
512 while (retry_send(sendto(daemon->icmp6fd, daemon->outpacket.iov_base,
513 save_counter(0), 0, (struct sockaddr *)&addr,
514 sizeof(addr))));
c5ad4e79
SK
515
516}
517
ba4fc0f9
NJ
518static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest)
519{
520 /* Send an RA on the same interface that the RA content is based
521 on. */
522 send_ra_alias(now, iface, iface_name, dest, iface);
523}
524
c5ad4e79 525static int add_prefixes(struct in6_addr *local, int prefix,
bad7b875 526 int scope, int if_index, int flags,
55b42f6d 527 unsigned int preferred, unsigned int valid, void *vparam)
c5ad4e79 528{
c5ad4e79 529 struct ra_param *param = vparam;
c5ad4e79
SK
530
531 (void)scope; /* warning */
ed8b68ad 532
c5ad4e79
SK
533 if (if_index == param->ind)
534 {
535 if (IN6_IS_ADDR_LINKLOCAL(local))
c3a04081
SK
536 {
537 /* Can there be more than one LL address?
538 Select the one with the longest preferred time
539 if there is. */
540 if (preferred > param->link_pref_time)
541 {
542 param->link_pref_time = preferred;
543 param->link_local = *local;
544 }
545 }
c5ad4e79 546 else if (!IN6_IS_ADDR_LOOPBACK(local) &&
c5ad4e79
SK
547 !IN6_IS_ADDR_MULTICAST(local))
548 {
4c82efc5 549 int real_prefix = 0;
c8257540
SK
550 int do_slaac = 0;
551 int deprecate = 0;
3bc0d932 552 int constructed = 0;
7ea3d3fd 553 int adv_router = 0;
2fd5bc95 554 int off_link = 0;
c8257540 555 unsigned int time = 0xffffffff;
1e02a859
SK
556 struct dhcp_context *context;
557
1f776932 558 for (context = daemon->dhcp6; context; context = context->next)
ef1a94ab 559 if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
4c82efc5
VG
560 prefix <= context->prefix &&
561 is_same_net6(local, &context->start6, context->prefix) &&
562 is_same_net6(local, &context->end6, context->prefix))
c5ad4e79 563 {
ef1a94ab
SK
564 context->saved_valid = valid;
565
7ea3d3fd 566 if (context->flags & CONTEXT_RA)
30cd9666
SK
567 {
568 do_slaac = 1;
4723d49d 569 if (context->flags & CONTEXT_DHCP)
05e92e5a
SK
570 {
571 param->other = 1;
572 if (!(context->flags & CONTEXT_RA_STATELESS))
573 param->managed = 1;
574 }
30cd9666 575 }
884a6dfe 576 else
0010b474
SK
577 {
578 /* don't do RA for non-ra-only unless --enable-ra is set */
579 if (!option_bool(OPT_RA))
580 continue;
581 param->managed = 1;
30cd9666 582 param->other = 1;
0010b474 583 }
7ea3d3fd
SK
584
585 /* Configured to advertise router address, not prefix. See RFC 3775 7.2
586 In this case we do all addresses associated with a context,
587 hence the real_prefix setting here. */
588 if (context->flags & CONTEXT_RA_ROUTER)
589 {
590 adv_router = 1;
591 param->adv_router = 1;
592 real_prefix = context->prefix;
593 }
594
1ecbaaa3 595 /* find floor time, don't reduce below 3 * RA interval. */
c8257540 596 if (time > context->lease_time)
7f035f58
SK
597 {
598 time = context->lease_time;
c4cd95df
SK
599 if (time < ((unsigned int)(3 * param->adv_interval)))
600 time = 3 * param->adv_interval;
7f035f58
SK
601 }
602
c8257540
SK
603 if (context->flags & CONTEXT_DEPRECATE)
604 deprecate = 1;
3bc0d932
SK
605
606 if (context->flags & CONTEXT_CONSTRUCTED)
607 constructed = 1;
608
c8257540 609
18f0fb05
SK
610 /* collect dhcp-range tags */
611 if (context->netid.next == &context->netid && context->netid.net)
612 {
613 context->netid.next = param->tags;
614 param->tags = &context->netid;
615 }
616
5ae34bf3
SK
617 /* subsequent prefixes on the same interface
618 and subsequent instances of this prefix don't need timers.
619 Be careful not to find the same prefix twice with different
7ea3d3fd 620 addresses unless we're advertising the actual addresses. */
1e02a859
SK
621 if (!(context->flags & CONTEXT_RA_DONE))
622 {
5ae34bf3
SK
623 if (!param->first)
624 context->ra_time = 0;
1e02a859 625 context->flags |= CONTEXT_RA_DONE;
4c82efc5 626 real_prefix = context->prefix;
2fd5bc95 627 off_link = (context->flags & CONTEXT_RA_OFF_LINK);
1e02a859 628 }
5ae34bf3
SK
629
630 param->first = 0;
631 param->found_context = 1;
c5ad4e79 632 }
1f776932 633
ed8b68ad 634 /* configured time is ceiling */
3bc0d932 635 if (!constructed || valid > time)
ed8b68ad
SK
636 valid = time;
637
3bc0d932 638 if (flags & IFACE_DEPRECATED)
ed8b68ad 639 preferred = 0;
1e02a859 640
3bc0d932
SK
641 if (deprecate)
642 time = 0;
643
644 /* configured time is ceiling */
645 if (!constructed || preferred > time)
646 preferred = time;
c3a04081
SK
647
648 if (IN6_IS_ADDR_ULA(local))
55b42f6d 649 {
c3a04081
SK
650 if (preferred > param->ula_pref_time)
651 {
652 param->ula_pref_time = preferred;
653 param->ula = *local;
654 }
655 }
656 else
657 {
658 if (preferred > param->glob_pref_time)
659 {
660 param->glob_pref_time = preferred;
661 param->link_global = *local;
662 }
55b42f6d
SK
663 }
664
4c82efc5 665 if (real_prefix != 0)
c8257540 666 {
1e02a859
SK
667 struct prefix_opt *opt;
668
669 if ((opt = expand(sizeof(struct prefix_opt))))
670 {
5ef33279 671 /* zero net part of address */
7ea3d3fd
SK
672 if (!adv_router)
673 setaddr6part(local, addr6part(local) & ~((real_prefix == 64) ? (u64)-1LL : (1LLU << (128 - real_prefix)) - 1LLU));
5ef33279 674
1e02a859
SK
675 opt->type = ICMP6_OPT_PREFIX;
676 opt->len = 4;
4c82efc5 677 opt->prefix_len = real_prefix;
2fd5bc95
NJ
678 /* autonomous only if we're not doing dhcp, set
679 "on-link" unless "off-link" was specified */
680 opt->flags = (off_link ? 0 : 0x80);
7ea3d3fd
SK
681 if (do_slaac)
682 opt->flags |= 0x40;
683 if (adv_router)
684 opt->flags |= 0x20;
ed8b68ad
SK
685 opt->valid_lifetime = htonl(valid);
686 opt->preferred_lifetime = htonl(preferred);
5ef33279 687 opt->reserved = 0;
1e02a859 688 opt->prefix = *local;
1e02a859 689
5ef33279 690 inet_ntop(AF_INET6, local, daemon->addrbuff, ADDRSTRLEN);
8c0b73d3
KDB
691 if (!option_bool(OPT_QUIET_RA))
692 my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
1e02a859 693 }
c8257540 694 }
c5ad4e79
SK
695 }
696 }
697 return 1;
698}
699
700static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm)
701{
702 (void)type;
703
704 if (index == *((int *)parm))
705 {
706 /* size is in units of 8 octets and includes type and length (2 bytes)
707 add 7 to round up */
708 int len = (maclen + 9) >> 3;
709 unsigned char *p = expand(len << 3);
710 memset(p, 0, len << 3);
711 *p++ = ICMP6_OPT_SOURCE_MAC;
712 *p++ = len;
713 memcpy(p, mac, maclen);
714
715 return 0;
716 }
717
718 return 1;
719}
720
721time_t periodic_ra(time_t now)
722{
723 struct search_param param;
724 struct dhcp_context *context;
725 time_t next_event;
c4cd95df 726
c5ad4e79 727 param.now = now;
29d28dda 728 param.iface = 0;
c5ad4e79
SK
729
730 while (1)
731 {
732 /* find overdue events, and time of first future event */
1f776932 733 for (next_event = 0, context = daemon->dhcp6; context; context = context->next)
c5ad4e79
SK
734 if (context->ra_time != 0)
735 {
7dbe9814 736 if (difftime(context->ra_time, now) <= 0.0)
c5ad4e79
SK
737 break; /* overdue */
738
7dbe9814
SK
739 if (next_event == 0 || difftime(next_event, context->ra_time) > 0.0)
740 next_event = context->ra_time;
c5ad4e79
SK
741 }
742
743 /* none overdue */
744 if (!context)
745 break;
746
c4cd95df
SK
747 if ((context->flags & CONTEXT_OLD) &&
748 context->if_index != 0 &&
dd9d9ce5 749 indextoname(daemon->icmp6fd, context->if_index, param.name))
ef1a94ab
SK
750 {
751 /* A context for an old address. We'll not find the interface by
c4cd95df
SK
752 looking for addresses, but we know it anyway, since the context is
753 constructed */
ef1a94ab 754 param.iface = context->if_index;
c4cd95df 755 new_timeout(context, param.name, now);
ef1a94ab
SK
756 }
757 else if (iface_enumerate(AF_INET6, &param, iface_search))
758 /* There's a context overdue, but we can't find an interface
759 associated with it, because it's for a subnet we dont
760 have an interface on. Probably we're doing DHCP on
761 a remote subnet via a relay. Zero the timer, since we won't
762 ever be able to send ra's and satistfy it. */
c5ad4e79 763 context->ra_time = 0;
ef1a94ab
SK
764
765 if (param.iface != 0 &&
c4cd95df 766 iface_check(AF_LOCAL, NULL, param.name, NULL))
421594f8
SK
767 {
768 struct iname *tmp;
769 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
c4cd95df 770 if (tmp->name && wildcard_match(tmp->name, param.name))
421594f8
SK
771 break;
772 if (!tmp)
c4cd95df 773 send_ra(now, param.iface, param.name, NULL);
421594f8
SK
774 }
775 }
c5ad4e79
SK
776 return next_event;
777}
421594f8 778
c5ad4e79 779static int iface_search(struct in6_addr *local, int prefix,
bad7b875 780 int scope, int if_index, int flags,
1f776932 781 int preferred, int valid, void *vparam)
c5ad4e79
SK
782{
783 struct search_param *param = vparam;
741c2952 784 struct dhcp_context *context;
c5ad4e79
SK
785
786 (void)scope;
1f776932
SK
787 (void)preferred;
788 (void)valid;
c5ad4e79 789
1f776932 790 for (context = daemon->dhcp6; context; context = context->next)
ef1a94ab 791 if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
4c82efc5
VG
792 prefix <= context->prefix &&
793 is_same_net6(local, &context->start6, context->prefix) &&
794 is_same_net6(local, &context->end6, context->prefix) &&
6e3dba3f
SK
795 context->ra_time != 0 &&
796 difftime(context->ra_time, param->now) <= 0.0)
797 {
798 /* found an interface that's overdue for RA determine new
799 timeout value and arrange for RA to be sent unless interface is
800 still doing DAD.*/
801
bad7b875 802 if (!(flags & IFACE_TENTATIVE))
6e3dba3f
SK
803 param->iface = if_index;
804
c4cd95df
SK
805 /* should never fail */
806 if (!indextoname(daemon->icmp6fd, if_index, param->name))
807 {
808 param->iface = 0;
809 return 0;
810 }
811
812 new_timeout(context, param->name, param->now);
6e3dba3f
SK
813
814 /* zero timers for other contexts on the same subnet, so they don't timeout
815 independently */
816 for (context = context->next; context; context = context->next)
4c82efc5
VG
817 if (prefix <= context->prefix &&
818 is_same_net6(local, &context->start6, context->prefix) &&
819 is_same_net6(local, &context->end6, context->prefix))
6e3dba3f
SK
820 context->ra_time = 0;
821
822 return 0; /* found, abort */
823 }
c5ad4e79
SK
824
825 return 1; /* keep searching */
826}
ef1a94ab 827
c4cd95df 828static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now)
ef1a94ab 829{
c4cd95df 830 if (difftime(now, context->ra_short_period_start) < 60.0)
ef1a94ab
SK
831 /* range 5 - 20 */
832 context->ra_time = now + 5 + (rand16()/4400);
833 else
c4cd95df
SK
834 {
835 /* range 3/4 - 1 times MaxRtrAdvInterval */
836 unsigned int adv_interval = calc_interval(find_iface_param(iface_name));
837 context->ra_time = now + (3 * adv_interval)/4 + ((adv_interval * (unsigned int)rand16()) >> 18);
838 }
839}
840
841static struct ra_interface *find_iface_param(char *iface)
842{
843 struct ra_interface *ra;
844
845 for (ra = daemon->ra_interfaces; ra; ra = ra->next)
846 if (wildcard_match(ra->name, iface))
847 return ra;
848
849 return NULL;
850}
851
852static unsigned int calc_interval(struct ra_interface *ra)
853{
854 int interval = 600;
855
856 if (ra && ra->interval != 0)
857 {
858 interval = ra->interval;
859 if (interval > 1800)
860 interval = 1800;
861 else if (interval < 4)
862 interval = 4;
863 }
864
865 return (unsigned int)interval;
866}
867
868static unsigned int calc_lifetime(struct ra_interface *ra)
869{
870 int lifetime, interval = (int)calc_interval(ra);
871
872 if (!ra || ra->lifetime == -1) /* not specified */
873 lifetime = 3 * interval;
874 else
875 {
876 lifetime = ra->lifetime;
877 if (lifetime < interval && lifetime != 0)
878 lifetime = interval;
879 else if (lifetime > 9000)
880 lifetime = 9000;
881 }
882
883 return (unsigned int)lifetime;
884}
885
886static unsigned int calc_prio(struct ra_interface *ra)
887{
888 if (ra)
889 return ra->prio;
890
891 return 0;
ef1a94ab 892}
801ca9a7 893
c5ad4e79 894#endif