dnsmasq: stay close as possible to master branch
[tomato.git] / release / src / router / dnsmasq / src / radv.c
blob749b666488d1f6fea101b75da350521b8849b395
1 /* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
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.
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.
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/>.
18 /* NB. This code may be called during a DHCPv4 or transaction which is in ping-wait
19 It therefore cannot use any DHCP buffer resources except outpacket, which is
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 */
23 #include "dnsmasq.h"
25 #ifdef HAVE_DHCP6
27 #include <netinet/icmp6.h>
29 struct ra_param {
30 time_t now;
31 int ind, managed, other, first, adv_router;
32 char *if_name;
33 struct dhcp_netid *tags;
34 struct in6_addr link_local, link_global, ula;
35 unsigned int glob_pref_time, link_pref_time, ula_pref_time, adv_interval, prio;
36 struct dhcp_context *found_context;
39 struct search_param {
40 time_t now; int iface;
41 char name[IF_NAMESIZE+1];
44 struct alias_param {
45 int iface;
46 struct dhcp_bridge *bridge;
47 int num_alias_ifs;
48 int max_alias_ifs;
49 int *alias_ifs;
52 static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest);
53 static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_addr *dest,
54 int send_iface);
55 static int send_ra_to_aliases(int index, unsigned int type, char *mac, size_t maclen, void *parm);
56 static int add_prefixes(struct in6_addr *local, int prefix,
57 int scope, int if_index, int flags,
58 unsigned int preferred, unsigned int valid, void *vparam);
59 static int iface_search(struct in6_addr *local, int prefix,
60 int scope, int if_index, int flags,
61 int prefered, int valid, void *vparam);
62 static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
63 static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now);
64 static unsigned int calc_lifetime(struct ra_interface *ra);
65 static unsigned int calc_interval(struct ra_interface *ra);
66 static unsigned int calc_prio(struct ra_interface *ra);
67 static struct ra_interface *find_iface_param(char *iface);
69 static int hop_limit;
71 void ra_init(time_t now)
73 struct icmp6_filter filter;
74 int fd;
75 #if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
76 int class = IPTOS_CLASS_CS6;
77 #endif
78 int val = 255; /* radvd uses this value */
79 socklen_t len = sizeof(int);
80 struct dhcp_context *context;
82 /* ensure this is around even if we're not doing DHCPv6 */
83 expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
85 /* See if we're guessing SLAAC addresses, if so we need to recieve ping replies */
86 for (context = daemon->dhcp6; context; context = context->next)
87 if ((context->flags & CONTEXT_RA_NAME))
88 break;
90 /* Need ICMP6 socket for transmission for DHCPv6 even when not doing RA. */
92 ICMP6_FILTER_SETBLOCKALL(&filter);
93 if (daemon->doing_ra)
95 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
96 if (context)
97 ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
100 if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 ||
101 getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) ||
102 #if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
103 setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
104 #endif
105 !fix_fd(fd) ||
106 !set_ipv6pktinfo(fd) ||
107 setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val)) ||
108 setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val)) ||
109 setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) == -1)
110 die (_("cannot create ICMPv6 socket: %s"), NULL, EC_BADNET);
112 daemon->icmp6fd = fd;
114 if (daemon->doing_ra)
115 ra_start_unsolicted(now, NULL);
118 void ra_start_unsolicted(time_t now, struct dhcp_context *context)
120 /* init timers so that we do ra's for some/all soon. some ra_times will end up zeroed
121 if it's not appropriate to advertise those contexts.
122 This gets re-called on a netlink route-change to re-do the advertisement
123 and pick up new interfaces */
125 if (context)
126 context->ra_short_period_start = context->ra_time = now;
127 else
128 for (context = daemon->dhcp6; context; context = context->next)
129 if (!(context->flags & CONTEXT_TEMPLATE))
131 context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
132 /* re-do frequently for a minute or so, in case the first gets lost. */
133 context->ra_short_period_start = now;
137 void icmp6_packet(time_t now)
139 char interface[IF_NAMESIZE+1];
140 ssize_t sz;
141 int if_index = 0;
142 struct cmsghdr *cmptr;
143 struct msghdr msg;
144 union {
145 struct cmsghdr align; /* this ensures alignment */
146 char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
147 } control_u;
148 struct sockaddr_in6 from;
149 unsigned char *packet;
150 struct iname *tmp;
152 /* Note: use outpacket for input buffer */
153 msg.msg_control = control_u.control6;
154 msg.msg_controllen = sizeof(control_u);
155 msg.msg_flags = 0;
156 msg.msg_name = &from;
157 msg.msg_namelen = sizeof(from);
158 msg.msg_iov = &daemon->outpacket;
159 msg.msg_iovlen = 1;
161 if ((sz = recv_dhcp_packet(daemon->icmp6fd, &msg)) == -1 || sz < 8)
162 return;
164 packet = (unsigned char *)daemon->outpacket.iov_base;
166 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
167 if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
169 union {
170 unsigned char *c;
171 struct in6_pktinfo *p;
172 } p;
173 p.c = CMSG_DATA(cmptr);
175 if_index = p.p->ipi6_ifindex;
178 if (!indextoname(daemon->icmp6fd, if_index, interface))
179 return;
181 if (!iface_check(AF_LOCAL, NULL, interface, NULL))
182 return;
184 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
185 if (tmp->name && wildcard_match(tmp->name, interface))
186 return;
188 if (packet[1] != 0)
189 return;
191 if (packet[0] == ICMP6_ECHO_REPLY)
192 lease_ping_reply(&from.sin6_addr, packet, interface);
193 else if (packet[0] == ND_ROUTER_SOLICIT)
195 char *mac = "";
196 struct dhcp_bridge *bridge, *alias;
198 /* look for link-layer address option for logging */
199 if (sz >= 16 && packet[8] == ICMP6_OPT_SOURCE_MAC && (packet[9] * 8) + 8 <= sz)
201 print_mac(daemon->namebuff, &packet[10], (packet[9] * 8) - 2);
202 mac = daemon->namebuff;
205 if (!option_bool(OPT_QUIET_RA))
206 my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
208 /* If the incoming interface is an alias of some other one (as
209 specified by the --bridge-interface option), send an RA using
210 the context of the aliased interface. */
211 for (bridge = daemon->bridges; bridge; bridge = bridge->next)
213 int bridge_index = if_nametoindex(bridge->iface);
214 if (bridge_index)
216 for (alias = bridge->alias; alias; alias = alias->next)
217 if (wildcard_matchn(alias->iface, interface, IF_NAMESIZE))
219 /* Send an RA on if_index with information from
220 bridge_index. */
221 send_ra_alias(now, bridge_index, bridge->iface, NULL, if_index);
222 break;
224 if (alias)
225 break;
229 /* If the incoming interface wasn't an alias, send an RA using
230 the context of the incoming interface. */
231 if (!bridge)
232 /* source address may not be valid in solicit request. */
233 send_ra(now, if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
237 static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_addr *dest, int send_iface)
239 struct ra_packet *ra;
240 struct ra_param parm;
241 struct sockaddr_in6 addr;
242 struct dhcp_context *context, *tmp, **up;
243 struct dhcp_netid iface_id;
244 struct dhcp_opt *opt_cfg;
245 struct ra_interface *ra_param = find_iface_param(iface_name);
246 int done_dns = 0, old_prefix = 0;
247 unsigned int min_pref_time;
248 #ifdef HAVE_LINUX_NETWORK
249 FILE *f;
250 #endif
252 parm.ind = iface;
253 parm.managed = 0;
254 parm.other = 0;
255 parm.found_context = NULL;
256 parm.adv_router = 0;
257 parm.if_name = iface_name;
258 parm.first = 1;
259 parm.now = now;
260 parm.glob_pref_time = parm.link_pref_time = parm.ula_pref_time = 0;
261 parm.adv_interval = calc_interval(ra_param);
262 parm.prio = calc_prio(ra_param);
264 save_counter(0);
265 ra = expand(sizeof(struct ra_packet));
267 ra->type = ND_ROUTER_ADVERT;
268 ra->code = 0;
269 ra->hop_limit = hop_limit;
270 ra->flags = parm.prio;
271 ra->lifetime = htons(calc_lifetime(ra_param));
272 ra->reachable_time = 0;
273 ra->retrans_time = 0;
275 /* set tag with name == interface */
276 iface_id.net = iface_name;
277 iface_id.next = NULL;
278 parm.tags = &iface_id;
280 for (context = daemon->dhcp6; context; context = context->next)
282 context->flags &= ~CONTEXT_RA_DONE;
283 context->netid.next = &context->netid;
286 if (!iface_enumerate(AF_INET6, &parm, add_prefixes))
287 return;
289 /* Find smallest preferred time within address classes,
290 to use as lifetime for options. This is a rather arbitrary choice. */
291 min_pref_time = 0xffffffff;
292 if (parm.glob_pref_time != 0 && parm.glob_pref_time < min_pref_time)
293 min_pref_time = parm.glob_pref_time;
295 if (parm.ula_pref_time != 0 && parm.ula_pref_time < min_pref_time)
296 min_pref_time = parm.ula_pref_time;
298 if (parm.link_pref_time != 0 && parm.link_pref_time < min_pref_time)
299 min_pref_time = parm.link_pref_time;
301 /* Look for constructed contexts associated with addresses which have gone,
302 and advertise them with preferred_time == 0 RFC 6204 4.3 L-13 */
303 for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
305 tmp = context->next;
307 if (context->if_index == iface && (context->flags & CONTEXT_OLD))
309 unsigned int old = difftime(now, context->address_lost_time);
311 if (old > context->saved_valid)
313 /* We've advertised this enough, time to go */
315 /* If this context held the timeout, and there's another context in use
316 transfer the timeout there. */
317 if (context->ra_time != 0 && parm.found_context && parm.found_context->ra_time == 0)
318 new_timeout(parm.found_context, iface_name, now);
320 *up = context->next;
321 free(context);
323 else
325 struct prefix_opt *opt;
326 struct in6_addr local = context->start6;
327 int do_slaac = 0;
329 old_prefix = 1;
331 /* zero net part of address */
332 setaddr6part(&local, addr6part(&local) & ~((context->prefix == 64) ? (u64)-1LL : (1LLU << (128 - context->prefix)) - 1LLU));
335 if (context->flags & CONTEXT_RA)
337 do_slaac = 1;
338 if (context->flags & CONTEXT_DHCP)
340 parm.other = 1;
341 if (!(context->flags & CONTEXT_RA_STATELESS))
342 parm.managed = 1;
345 else
347 /* don't do RA for non-ra-only unless --enable-ra is set */
348 if (option_bool(OPT_RA))
350 parm.managed = 1;
351 parm.other = 1;
355 if ((opt = expand(sizeof(struct prefix_opt))))
357 opt->type = ICMP6_OPT_PREFIX;
358 opt->len = 4;
359 opt->prefix_len = context->prefix;
360 /* autonomous only if we're not doing dhcp, set
361 "on-link" unless "off-link" was specified */
362 opt->flags = (do_slaac ? 0x40 : 0) |
363 ((context->flags & CONTEXT_RA_OFF_LINK) ? 0 : 0x80);
364 opt->valid_lifetime = htonl(context->saved_valid - old);
365 opt->preferred_lifetime = htonl(0);
366 opt->reserved = 0;
367 opt->prefix = local;
369 inet_ntop(AF_INET6, &local, daemon->addrbuff, ADDRSTRLEN);
370 if (!option_bool(OPT_QUIET_RA))
371 my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s old prefix", iface_name, daemon->addrbuff);
374 up = &context->next;
377 else
378 up = &context->next;
381 /* If we're advertising only old prefixes, set router lifetime to zero. */
382 if (old_prefix && !parm.found_context)
383 ra->lifetime = htons(0);
385 /* No prefixes to advertise. */
386 if (!old_prefix && !parm.found_context)
387 return;
389 /* If we're sending router address instead of prefix in at least on prefix,
390 include the advertisement interval option. */
391 if (parm.adv_router)
393 put_opt6_char(ICMP6_OPT_ADV_INTERVAL);
394 put_opt6_char(1);
395 put_opt6_short(0);
396 /* interval value is in milliseconds */
397 put_opt6_long(1000 * calc_interval(find_iface_param(iface_name)));
400 #ifdef HAVE_LINUX_NETWORK
401 /* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU
402 available from SIOCGIFMTU */
403 sprintf(daemon->namebuff, "/proc/sys/net/ipv6/conf/%s/mtu", iface_name);
404 if ((f = fopen(daemon->namebuff, "r")))
406 if (fgets(daemon->namebuff, MAXDNAME, f))
408 put_opt6_char(ICMP6_OPT_MTU);
409 put_opt6_char(1);
410 put_opt6_short(0);
411 put_opt6_long(atoi(daemon->namebuff));
413 fclose(f);
415 #endif
417 iface_enumerate(AF_LOCAL, &send_iface, add_lla);
419 /* RDNSS, RFC 6106, use relevant DHCP6 options */
420 (void)option_filter(parm.tags, NULL, daemon->dhcp_opts6);
422 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
424 int i;
426 /* netids match and not encapsulated? */
427 if (!(opt_cfg->flags & DHOPT_TAGOK))
428 continue;
430 if (opt_cfg->opt == OPTION6_DNS_SERVER)
432 struct in6_addr *a;
433 int len;
435 done_dns = 1;
437 if (opt_cfg->len == 0)
438 continue;
440 /* reduce len for any addresses we can't substitute */
441 for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, i = 0;
442 i < opt_cfg->len; i += IN6ADDRSZ, a++)
443 if ((IN6_IS_ADDR_UNSPECIFIED(a) && parm.glob_pref_time == 0) ||
444 (IN6_IS_ADDR_ULA_ZERO(a) && parm.ula_pref_time == 0) ||
445 (IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && parm.link_pref_time == 0))
446 len -= IN6ADDRSZ;
448 if (len != 0)
450 put_opt6_char(ICMP6_OPT_RDNSS);
451 put_opt6_char((len/8) + 1);
452 put_opt6_short(0);
453 put_opt6_long(min_pref_time);
455 for (a = (struct in6_addr *)opt_cfg->val, i = 0; i < opt_cfg->len; i += IN6ADDRSZ, a++)
456 if (IN6_IS_ADDR_UNSPECIFIED(a))
458 if (parm.glob_pref_time != 0)
459 put_opt6(&parm.link_global, IN6ADDRSZ);
461 else if (IN6_IS_ADDR_ULA_ZERO(a))
463 if (parm.ula_pref_time != 0)
464 put_opt6(&parm.ula, IN6ADDRSZ);
466 else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
468 if (parm.link_pref_time != 0)
469 put_opt6(&parm.link_local, IN6ADDRSZ);
471 else
472 put_opt6(a, IN6ADDRSZ);
476 if (opt_cfg->opt == OPTION6_DOMAIN_SEARCH && opt_cfg->len != 0)
478 int len = ((opt_cfg->len+7)/8);
480 put_opt6_char(ICMP6_OPT_DNSSL);
481 put_opt6_char(len + 1);
482 put_opt6_short(0);
483 put_opt6_long(min_pref_time);
484 put_opt6(opt_cfg->val, opt_cfg->len);
486 /* pad */
487 for (i = opt_cfg->len; i < len * 8; i++)
488 put_opt6_char(0);
492 if (daemon->port == NAMESERVER_PORT && !done_dns && parm.link_pref_time != 0)
494 /* default == us, as long as we are supplying DNS service. */
495 put_opt6_char(ICMP6_OPT_RDNSS);
496 put_opt6_char(3);
497 put_opt6_short(0);
498 put_opt6_long(min_pref_time);
499 put_opt6(&parm.link_local, IN6ADDRSZ);
502 /* set managed bits unless we're providing only RA on this link */
503 if (parm.managed)
504 ra->flags |= 0x80; /* M flag, managed, */
505 if (parm.other)
506 ra->flags |= 0x40; /* O flag, other */
508 /* decide where we're sending */
509 memset(&addr, 0, sizeof(addr));
510 #ifdef HAVE_SOCKADDR_SA_LEN
511 addr.sin6_len = sizeof(struct sockaddr_in6);
512 #endif
513 addr.sin6_family = AF_INET6;
514 addr.sin6_port = htons(IPPROTO_ICMPV6);
515 if (dest)
517 addr.sin6_addr = *dest;
518 if (IN6_IS_ADDR_LINKLOCAL(dest) ||
519 IN6_IS_ADDR_MC_LINKLOCAL(dest))
520 addr.sin6_scope_id = iface;
522 else
524 inet_pton(AF_INET6, ALL_NODES, &addr.sin6_addr);
525 setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &send_iface, sizeof(send_iface));
528 while (retry_send(sendto(daemon->icmp6fd, daemon->outpacket.iov_base,
529 save_counter(0), 0, (struct sockaddr *)&addr,
530 sizeof(addr))));
534 static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest)
536 /* Send an RA on the same interface that the RA content is based
537 on. */
538 send_ra_alias(now, iface, iface_name, dest, iface);
541 static int add_prefixes(struct in6_addr *local, int prefix,
542 int scope, int if_index, int flags,
543 unsigned int preferred, unsigned int valid, void *vparam)
545 struct ra_param *param = vparam;
547 (void)scope; /* warning */
549 if (if_index == param->ind)
551 if (IN6_IS_ADDR_LINKLOCAL(local))
553 /* Can there be more than one LL address?
554 Select the one with the longest preferred time
555 if there is. */
556 if (preferred > param->link_pref_time)
558 param->link_pref_time = preferred;
559 param->link_local = *local;
562 else if (!IN6_IS_ADDR_LOOPBACK(local) &&
563 !IN6_IS_ADDR_MULTICAST(local))
565 int real_prefix = 0;
566 int do_slaac = 0;
567 int deprecate = 0;
568 int constructed = 0;
569 int adv_router = 0;
570 int off_link = 0;
571 unsigned int time = 0xffffffff;
572 struct dhcp_context *context;
574 for (context = daemon->dhcp6; context; context = context->next)
575 if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
576 prefix <= context->prefix &&
577 is_same_net6(local, &context->start6, context->prefix) &&
578 is_same_net6(local, &context->end6, context->prefix))
580 context->saved_valid = valid;
582 if (context->flags & CONTEXT_RA)
584 do_slaac = 1;
585 if (context->flags & CONTEXT_DHCP)
587 param->other = 1;
588 if (!(context->flags & CONTEXT_RA_STATELESS))
589 param->managed = 1;
592 else
594 /* don't do RA for non-ra-only unless --enable-ra is set */
595 if (!option_bool(OPT_RA))
596 continue;
597 param->managed = 1;
598 param->other = 1;
601 /* Configured to advertise router address, not prefix. See RFC 3775 7.2
602 In this case we do all addresses associated with a context,
603 hence the real_prefix setting here. */
604 if (context->flags & CONTEXT_RA_ROUTER)
606 adv_router = 1;
607 param->adv_router = 1;
608 real_prefix = context->prefix;
611 /* find floor time, don't reduce below 3 * RA interval. */
612 if (time > context->lease_time)
614 time = context->lease_time;
615 if (time < ((unsigned int)(3 * param->adv_interval)))
616 time = 3 * param->adv_interval;
619 if (context->flags & CONTEXT_DEPRECATE)
620 deprecate = 1;
622 if (context->flags & CONTEXT_CONSTRUCTED)
623 constructed = 1;
626 /* collect dhcp-range tags */
627 if (context->netid.next == &context->netid && context->netid.net)
629 context->netid.next = param->tags;
630 param->tags = &context->netid;
633 /* subsequent prefixes on the same interface
634 and subsequent instances of this prefix don't need timers.
635 Be careful not to find the same prefix twice with different
636 addresses unless we're advertising the actual addresses. */
637 if (!(context->flags & CONTEXT_RA_DONE))
639 if (!param->first)
640 context->ra_time = 0;
641 context->flags |= CONTEXT_RA_DONE;
642 real_prefix = context->prefix;
643 off_link = (context->flags & CONTEXT_RA_OFF_LINK);
646 param->first = 0;
647 /* found_context is the _last_ one we found, so if there's
648 more than one, it's not the first. */
649 param->found_context = context;
652 /* configured time is ceiling */
653 if (!constructed || valid > time)
654 valid = time;
656 if (flags & IFACE_DEPRECATED)
657 preferred = 0;
659 if (deprecate)
660 time = 0;
662 /* configured time is ceiling */
663 if (!constructed || preferred > time)
664 preferred = time;
666 if (IN6_IS_ADDR_ULA(local))
668 if (preferred > param->ula_pref_time)
670 param->ula_pref_time = preferred;
671 param->ula = *local;
674 else
676 if (preferred > param->glob_pref_time)
678 param->glob_pref_time = preferred;
679 param->link_global = *local;
683 if (real_prefix != 0)
685 struct prefix_opt *opt;
687 if ((opt = expand(sizeof(struct prefix_opt))))
689 /* zero net part of address */
690 if (!adv_router)
691 setaddr6part(local, addr6part(local) & ~((real_prefix == 64) ? (u64)-1LL : (1LLU << (128 - real_prefix)) - 1LLU));
693 opt->type = ICMP6_OPT_PREFIX;
694 opt->len = 4;
695 opt->prefix_len = real_prefix;
696 /* autonomous only if we're not doing dhcp, set
697 "on-link" unless "off-link" was specified */
698 opt->flags = (off_link ? 0 : 0x80);
699 if (do_slaac)
700 opt->flags |= 0x40;
701 if (adv_router)
702 opt->flags |= 0x20;
703 opt->valid_lifetime = htonl(valid);
704 opt->preferred_lifetime = htonl(preferred);
705 opt->reserved = 0;
706 opt->prefix = *local;
708 inet_ntop(AF_INET6, local, daemon->addrbuff, ADDRSTRLEN);
709 if (!option_bool(OPT_QUIET_RA))
710 my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
715 return 1;
718 static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm)
720 (void)type;
722 if (index == *((int *)parm))
724 /* size is in units of 8 octets and includes type and length (2 bytes)
725 add 7 to round up */
726 int len = (maclen + 9) >> 3;
727 unsigned char *p = expand(len << 3);
728 memset(p, 0, len << 3);
729 *p++ = ICMP6_OPT_SOURCE_MAC;
730 *p++ = len;
731 memcpy(p, mac, maclen);
733 return 0;
736 return 1;
739 time_t periodic_ra(time_t now)
741 struct search_param param;
742 struct dhcp_context *context;
743 time_t next_event;
744 struct alias_param aparam;
746 param.now = now;
747 param.iface = 0;
749 while (1)
751 /* find overdue events, and time of first future event */
752 for (next_event = 0, context = daemon->dhcp6; context; context = context->next)
753 if (context->ra_time != 0)
755 if (difftime(context->ra_time, now) <= 0.0)
756 break; /* overdue */
758 if (next_event == 0 || difftime(next_event, context->ra_time) > 0.0)
759 next_event = context->ra_time;
762 /* none overdue */
763 if (!context)
764 break;
766 if ((context->flags & CONTEXT_OLD) &&
767 context->if_index != 0 &&
768 indextoname(daemon->icmp6fd, context->if_index, param.name))
770 /* A context for an old address. We'll not find the interface by
771 looking for addresses, but we know it anyway, since the context is
772 constructed */
773 param.iface = context->if_index;
774 new_timeout(context, param.name, now);
776 else if (iface_enumerate(AF_INET6, &param, iface_search))
777 /* There's a context overdue, but we can't find an interface
778 associated with it, because it's for a subnet we dont
779 have an interface on. Probably we're doing DHCP on
780 a remote subnet via a relay. Zero the timer, since we won't
781 ever be able to send ra's and satistfy it. */
782 context->ra_time = 0;
784 if (param.iface != 0 &&
785 iface_check(AF_LOCAL, NULL, param.name, NULL))
787 struct iname *tmp;
788 for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
789 if (tmp->name && wildcard_match(tmp->name, param.name))
790 break;
791 if (!tmp)
793 send_ra(now, param.iface, param.name, NULL);
795 /* Also send on all interfaces that are aliases of this
796 one. */
797 for (aparam.bridge = daemon->bridges;
798 aparam.bridge;
799 aparam.bridge = aparam.bridge->next)
800 if ((int)if_nametoindex(aparam.bridge->iface) == param.iface)
802 /* Count the number of alias interfaces for this
803 'bridge', by calling iface_enumerate with
804 send_ra_to_aliases and NULL alias_ifs. */
805 aparam.iface = param.iface;
806 aparam.alias_ifs = NULL;
807 aparam.num_alias_ifs = 0;
808 iface_enumerate(AF_LOCAL, &aparam, send_ra_to_aliases);
809 my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s => %d alias(es)",
810 param.name, daemon->addrbuff, aparam.num_alias_ifs);
812 /* Allocate memory to store the alias interface
813 indices. */
814 aparam.alias_ifs = (int *)whine_malloc(aparam.num_alias_ifs *
815 sizeof(int));
816 if (aparam.alias_ifs)
818 /* Use iface_enumerate again to get the alias
819 interface indices, then send on each of
820 those. */
821 aparam.max_alias_ifs = aparam.num_alias_ifs;
822 aparam.num_alias_ifs = 0;
823 iface_enumerate(AF_LOCAL, &aparam, send_ra_to_aliases);
824 for (; aparam.num_alias_ifs; aparam.num_alias_ifs--)
826 my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s => i/f %d",
827 param.name, daemon->addrbuff,
828 aparam.alias_ifs[aparam.num_alias_ifs - 1]);
829 send_ra_alias(now,
830 param.iface,
831 param.name,
832 NULL,
833 aparam.alias_ifs[aparam.num_alias_ifs - 1]);
835 free(aparam.alias_ifs);
838 /* The source interface can only appear in at most
839 one --bridge-interface. */
840 break;
845 return next_event;
848 static int send_ra_to_aliases(int index, unsigned int type, char *mac, size_t maclen, void *parm)
850 struct alias_param *aparam = (struct alias_param *)parm;
851 char ifrn_name[IFNAMSIZ];
852 struct dhcp_bridge *alias;
854 (void)type;
855 (void)mac;
856 (void)maclen;
858 if (if_indextoname(index, ifrn_name))
859 for (alias = aparam->bridge->alias; alias; alias = alias->next)
860 if (wildcard_matchn(alias->iface, ifrn_name, IFNAMSIZ))
862 if (aparam->alias_ifs && (aparam->num_alias_ifs < aparam->max_alias_ifs))
863 aparam->alias_ifs[aparam->num_alias_ifs] = index;
864 aparam->num_alias_ifs++;
867 return 1;
870 static int iface_search(struct in6_addr *local, int prefix,
871 int scope, int if_index, int flags,
872 int preferred, int valid, void *vparam)
874 struct search_param *param = vparam;
875 struct dhcp_context *context;
877 (void)scope;
878 (void)preferred;
879 (void)valid;
881 for (context = daemon->dhcp6; context; context = context->next)
882 if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
883 prefix <= context->prefix &&
884 is_same_net6(local, &context->start6, context->prefix) &&
885 is_same_net6(local, &context->end6, context->prefix) &&
886 context->ra_time != 0 &&
887 difftime(context->ra_time, param->now) <= 0.0)
889 /* found an interface that's overdue for RA determine new
890 timeout value and arrange for RA to be sent unless interface is
891 still doing DAD.*/
893 if (!(flags & IFACE_TENTATIVE))
894 param->iface = if_index;
896 /* should never fail */
897 if (!indextoname(daemon->icmp6fd, if_index, param->name))
899 param->iface = 0;
900 return 0;
903 new_timeout(context, param->name, param->now);
905 /* zero timers for other contexts on the same subnet, so they don't timeout
906 independently */
907 for (context = context->next; context; context = context->next)
908 if (prefix <= context->prefix &&
909 is_same_net6(local, &context->start6, context->prefix) &&
910 is_same_net6(local, &context->end6, context->prefix))
911 context->ra_time = 0;
913 return 0; /* found, abort */
916 return 1; /* keep searching */
919 static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now)
921 if (difftime(now, context->ra_short_period_start) < 60.0)
922 /* range 5 - 20 */
923 context->ra_time = now + 5 + (rand16()/4400);
924 else
926 /* range 3/4 - 1 times MaxRtrAdvInterval */
927 unsigned int adv_interval = calc_interval(find_iface_param(iface_name));
928 context->ra_time = now + (3 * adv_interval)/4 + ((adv_interval * (unsigned int)rand16()) >> 18);
932 static struct ra_interface *find_iface_param(char *iface)
934 struct ra_interface *ra;
936 for (ra = daemon->ra_interfaces; ra; ra = ra->next)
937 if (wildcard_match(ra->name, iface))
938 return ra;
940 return NULL;
943 static unsigned int calc_interval(struct ra_interface *ra)
945 int interval = 600;
947 if (ra && ra->interval != 0)
949 interval = ra->interval;
950 if (interval > 1800)
951 interval = 1800;
952 else if (interval < 4)
953 interval = 4;
956 return (unsigned int)interval;
959 static unsigned int calc_lifetime(struct ra_interface *ra)
961 int lifetime, interval = (int)calc_interval(ra);
963 if (!ra || ra->lifetime == -1) /* not specified */
964 lifetime = 3 * interval;
965 else
967 lifetime = ra->lifetime;
968 if (lifetime < interval && lifetime != 0)
969 lifetime = interval;
970 else if (lifetime > 9000)
971 lifetime = 9000;
974 return (unsigned int)lifetime;
977 static unsigned int calc_prio(struct ra_interface *ra)
979 if (ra)
980 return ra->prio;
982 return 0;
985 #endif