]>
git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/radv.c
1 /* dnsmasq is Copyright (c) 2000-2014 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 */
27 #include <netinet/icmp6.h>
31 int ind
, managed
, other
, found_context
, first
, adv_router
;
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
;
39 time_t now
; int iface
;
40 char name
[IF_NAMESIZE
+1];
43 static void send_ra(time_t now
, int iface
, char *iface_name
, struct in6_addr
*dest
);
44 static int add_prefixes(struct in6_addr
*local
, int prefix
,
45 int scope
, int if_index
, int flags
,
46 unsigned int preferred
, unsigned int valid
, void *vparam
);
47 static int iface_search(struct in6_addr
*local
, int prefix
,
48 int scope
, int if_index
, int flags
,
49 int prefered
, int valid
, void *vparam
);
50 static int add_lla(int index
, unsigned int type
, char *mac
, size_t maclen
, void *parm
);
51 static void new_timeout(struct dhcp_context
*context
, char *iface_name
, time_t now
);
52 static unsigned int calc_lifetime(struct ra_interface
*ra
);
53 static unsigned int calc_interval(struct ra_interface
*ra
);
54 static unsigned int calc_prio(struct ra_interface
*ra
);
55 static struct ra_interface
*find_iface_param(char *iface
);
59 void ra_init(time_t now
)
61 struct icmp6_filter filter
;
63 #if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
64 int class = IPTOS_CLASS_CS6
;
66 int val
= 255; /* radvd uses this value */
67 socklen_t len
= sizeof(int);
68 struct dhcp_context
*context
;
70 /* ensure this is around even if we're not doing DHCPv6 */
71 expand_buf(&daemon
->outpacket
, sizeof(struct dhcp_packet
));
73 /* See if we're guessing SLAAC addresses, if so we need to recieve ping replies */
74 for (context
= daemon
->dhcp6
; context
; context
= context
->next
)
75 if ((context
->flags
& CONTEXT_RA_NAME
))
78 /* Need ICMP6 socket for transmission for DHCPv6 even when not doing RA. */
80 ICMP6_FILTER_SETBLOCKALL(&filter
);
83 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT
, &filter
);
85 ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY
, &filter
);
88 if ((fd
= socket(PF_INET6
, SOCK_RAW
, IPPROTO_ICMPV6
)) == -1 ||
89 getsockopt(fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &hop_limit
, &len
) ||
90 #if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
91 setsockopt(fd
, IPPROTO_IPV6
, IPV6_TCLASS
, &class, sizeof(class)) == -1 ||
94 !set_ipv6pktinfo(fd
) ||
95 setsockopt(fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &val
, sizeof(val
)) ||
96 setsockopt(fd
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &val
, sizeof(val
)) ||
97 setsockopt(fd
, IPPROTO_ICMPV6
, ICMP6_FILTER
, &filter
, sizeof(filter
)) == -1)
98 die (_("cannot create ICMPv6 socket: %s"), NULL
, EC_BADNET
);
100 daemon
->icmp6fd
= fd
;
102 if (daemon
->doing_ra
)
103 ra_start_unsolicted(now
, NULL
);
106 void ra_start_unsolicted(time_t now
, struct dhcp_context
*context
)
108 /* init timers so that we do ra's for some/all soon. some ra_times will end up zeroed
109 if it's not appropriate to advertise those contexts.
110 This gets re-called on a netlink route-change to re-do the advertisement
111 and pick up new interfaces */
114 context
->ra_short_period_start
= context
->ra_time
= now
;
116 for (context
= daemon
->dhcp6
; context
; context
= context
->next
)
117 if (!(context
->flags
& CONTEXT_TEMPLATE
))
119 context
->ra_time
= now
+ (rand16()/13000); /* range 0 - 5 */
120 /* re-do frequently for a minute or so, in case the first gets lost. */
121 context
->ra_short_period_start
= now
;
125 void icmp6_packet(time_t now
)
127 char interface
[IF_NAMESIZE
+1];
130 struct cmsghdr
*cmptr
;
133 struct cmsghdr align
; /* this ensures alignment */
134 char control6
[CMSG_SPACE(sizeof(struct in6_pktinfo
))];
136 struct sockaddr_in6 from
;
137 unsigned char *packet
;
140 /* Note: use outpacket for input buffer */
141 msg
.msg_control
= control_u
.control6
;
142 msg
.msg_controllen
= sizeof(control_u
);
144 msg
.msg_name
= &from
;
145 msg
.msg_namelen
= sizeof(from
);
146 msg
.msg_iov
= &daemon
->outpacket
;
149 if ((sz
= recv_dhcp_packet(daemon
->icmp6fd
, &msg
)) == -1 || sz
< 8)
152 packet
= (unsigned char *)daemon
->outpacket
.iov_base
;
154 for (cmptr
= CMSG_FIRSTHDR(&msg
); cmptr
; cmptr
= CMSG_NXTHDR(&msg
, cmptr
))
155 if (cmptr
->cmsg_level
== IPPROTO_IPV6
&& cmptr
->cmsg_type
== daemon
->v6pktinfo
)
159 struct in6_pktinfo
*p
;
161 p
.c
= CMSG_DATA(cmptr
);
163 if_index
= p
.p
->ipi6_ifindex
;
166 if (!indextoname(daemon
->icmp6fd
, if_index
, interface
))
169 if (!iface_check(AF_LOCAL
, NULL
, interface
, NULL
))
172 for (tmp
= daemon
->dhcp_except
; tmp
; tmp
= tmp
->next
)
173 if (tmp
->name
&& wildcard_match(tmp
->name
, interface
))
179 if (packet
[0] == ICMP6_ECHO_REPLY
)
180 lease_ping_reply(&from
.sin6_addr
, packet
, interface
);
181 else if (packet
[0] == ND_ROUTER_SOLICIT
)
185 /* look for link-layer address option for logging */
186 if (sz
>= 16 && packet
[8] == ICMP6_OPT_SOURCE_MAC
&& (packet
[9] * 8) + 8 <= sz
)
188 print_mac(daemon
->namebuff
, &packet
[10], (packet
[9] * 8) - 2);
189 mac
= daemon
->namebuff
;
192 if (!option_bool(OPT_QUIET_RA
))
193 my_syslog(MS_DHCP
| LOG_INFO
, "RTR-SOLICIT(%s) %s", interface
, mac
);
194 /* source address may not be valid in solicit request. */
195 send_ra(now
, if_index
, interface
, !IN6_IS_ADDR_UNSPECIFIED(&from
.sin6_addr
) ? &from
.sin6_addr
: NULL
);
199 static void send_ra(time_t now
, int iface
, char *iface_name
, struct in6_addr
*dest
)
201 struct ra_packet
*ra
;
202 struct ra_param parm
;
203 struct sockaddr_in6 addr
;
204 struct dhcp_context
*context
, *tmp
, **up
;
205 struct dhcp_netid iface_id
;
206 struct dhcp_opt
*opt_cfg
;
207 struct ra_interface
*ra_param
= find_iface_param(iface_name
);
208 int done_dns
= 0, old_prefix
= 0;
209 unsigned int min_pref_time
;
210 #ifdef HAVE_LINUX_NETWORK
217 parm
.found_context
= 0;
219 parm
.if_name
= iface_name
;
222 parm
.glob_pref_time
= parm
.link_pref_time
= parm
.ula_pref_time
= 0;
223 parm
.adv_interval
= calc_interval(ra_param
);
224 parm
.prio
= calc_prio(ra_param
);
227 ra
= expand(sizeof(struct ra_packet
));
229 ra
->type
= ND_ROUTER_ADVERT
;
231 ra
->hop_limit
= hop_limit
;
232 ra
->flags
= parm
.prio
;
233 ra
->lifetime
= htons(calc_lifetime(ra_param
));
234 ra
->reachable_time
= 0;
235 ra
->retrans_time
= 0;
237 /* set tag with name == interface */
238 iface_id
.net
= iface_name
;
239 iface_id
.next
= NULL
;
240 parm
.tags
= &iface_id
;
242 for (context
= daemon
->dhcp6
; context
; context
= context
->next
)
244 context
->flags
&= ~CONTEXT_RA_DONE
;
245 context
->netid
.next
= &context
->netid
;
248 if (!iface_enumerate(AF_INET6
, &parm
, add_prefixes
))
251 /* Find smallest preferred time within address classes,
252 to use as lifetime for options. This is a rather arbitrary choice. */
253 min_pref_time
= 0xffffffff;
254 if (parm
.glob_pref_time
!= 0 && parm
.glob_pref_time
< min_pref_time
)
255 min_pref_time
= parm
.glob_pref_time
;
257 if (parm
.ula_pref_time
!= 0 && parm
.ula_pref_time
< min_pref_time
)
258 min_pref_time
= parm
.ula_pref_time
;
260 if (parm
.link_pref_time
!= 0 && parm
.link_pref_time
< min_pref_time
)
261 min_pref_time
= parm
.link_pref_time
;
263 /* Look for constructed contexts associated with addresses which have gone,
264 and advertise them with preferred_time == 0 RFC 6204 4.3 L-13 */
265 for (up
= &daemon
->dhcp6
, context
= daemon
->dhcp6
; context
; context
= tmp
)
269 if (context
->if_index
== iface
&& (context
->flags
& CONTEXT_OLD
))
271 unsigned int old
= difftime(now
, context
->address_lost_time
);
273 if (old
> context
->saved_valid
)
275 /* We've advertised this enough, time to go */
281 struct prefix_opt
*opt
;
282 struct in6_addr local
= context
->start6
;
287 /* zero net part of address */
288 setaddr6part(&local
, addr6part(&local
) & ~((context
->prefix
== 64) ? (u64
)-1LL : (1LLU << (128 - context
->prefix
)) - 1LLU));
291 if (context
->flags
& CONTEXT_RA
)
294 if (context
->flags
& CONTEXT_DHCP
)
297 if (!(context
->flags
& CONTEXT_RA_STATELESS
))
303 /* don't do RA for non-ra-only unless --enable-ra is set */
304 if (option_bool(OPT_RA
))
311 if ((opt
= expand(sizeof(struct prefix_opt
))))
313 opt
->type
= ICMP6_OPT_PREFIX
;
315 opt
->prefix_len
= context
->prefix
;
316 /* autonomous only if we're not doing dhcp, always set "on-link" */
317 opt
->flags
= do_slaac
? 0xC0 : 0x80;
318 opt
->valid_lifetime
= htonl(context
->saved_valid
- old
);
319 opt
->preferred_lifetime
= htonl(0);
323 inet_ntop(AF_INET6
, &local
, daemon
->addrbuff
, ADDRSTRLEN
);
324 if (!option_bool(OPT_QUIET_RA
))
325 my_syslog(MS_DHCP
| LOG_INFO
, "RTR-ADVERT(%s) %s old prefix", iface_name
, daemon
->addrbuff
);
335 /* If we're advertising only old prefixes, set router lifetime to zero. */
336 if (old_prefix
&& !parm
.found_context
)
337 ra
->lifetime
= htons(0);
339 /* No prefixes to advertise. */
340 if (!old_prefix
&& !parm
.found_context
)
343 /* If we're sending router address instead of prefix in at least on prefix,
344 include the advertisement interval option. */
347 put_opt6_char(ICMP6_OPT_ADV_INTERVAL
);
350 /* interval value is in milliseconds */
351 put_opt6_long(1000 * calc_interval(find_iface_param(iface_name
)));
354 #ifdef HAVE_LINUX_NETWORK
355 /* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU
356 available from SIOCGIFMTU */
357 sprintf(daemon
->namebuff
, "/proc/sys/net/ipv6/conf/%s/mtu", iface_name
);
358 if ((f
= fopen(daemon
->namebuff
, "r")))
360 if (fgets(daemon
->namebuff
, MAXDNAME
, f
))
362 put_opt6_char(ICMP6_OPT_MTU
);
365 put_opt6_long(atoi(daemon
->namebuff
));
371 iface_enumerate(AF_LOCAL
, &iface
, add_lla
);
373 /* RDNSS, RFC 6106, use relevant DHCP6 options */
374 (void)option_filter(parm
.tags
, NULL
, daemon
->dhcp_opts6
);
376 for (opt_cfg
= daemon
->dhcp_opts6
; opt_cfg
; opt_cfg
= opt_cfg
->next
)
380 /* netids match and not encapsulated? */
381 if (!(opt_cfg
->flags
& DHOPT_TAGOK
))
384 if (opt_cfg
->opt
== OPTION6_DNS_SERVER
)
391 if (opt_cfg
->len
== 0)
394 /* reduce len for any addresses we can't substitute */
395 for (a
= (struct in6_addr
*)opt_cfg
->val
, len
= opt_cfg
->len
, i
= 0;
396 i
< opt_cfg
->len
; i
+= IN6ADDRSZ
, a
++)
397 if ((IN6_IS_ADDR_UNSPECIFIED(a
) && parm
.glob_pref_time
== 0) ||
398 (IN6_IS_ADDR_ULA_ZERO(a
) && parm
.ula_pref_time
== 0) ||
399 (IN6_IS_ADDR_LINK_LOCAL_ZERO(a
) && parm
.link_pref_time
== 0))
404 put_opt6_char(ICMP6_OPT_RDNSS
);
405 put_opt6_char((len
/8) + 1);
407 put_opt6_long(min_pref_time
);
409 for (a
= (struct in6_addr
*)opt_cfg
->val
, i
= 0; i
< opt_cfg
->len
; i
+= IN6ADDRSZ
, a
++)
410 if (IN6_IS_ADDR_UNSPECIFIED(a
))
412 if (parm
.glob_pref_time
!= 0)
413 put_opt6(&parm
.link_global
, IN6ADDRSZ
);
415 else if (IN6_IS_ADDR_ULA_ZERO(a
))
417 if (parm
.ula_pref_time
!= 0)
418 put_opt6(&parm
.ula
, IN6ADDRSZ
);
420 else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a
))
422 if (parm
.link_pref_time
!= 0)
423 put_opt6(&parm
.link_local
, IN6ADDRSZ
);
426 put_opt6(a
, IN6ADDRSZ
);
430 if (opt_cfg
->opt
== OPTION6_DOMAIN_SEARCH
&& opt_cfg
->len
!= 0)
432 int len
= ((opt_cfg
->len
+7)/8);
434 put_opt6_char(ICMP6_OPT_DNSSL
);
435 put_opt6_char(len
+ 1);
437 put_opt6_long(min_pref_time
);
438 put_opt6(opt_cfg
->val
, opt_cfg
->len
);
441 for (i
= opt_cfg
->len
; i
< len
* 8; i
++)
446 if (daemon
->port
== NAMESERVER_PORT
&& !done_dns
&& parm
.link_pref_time
!= 0)
448 /* default == us, as long as we are supplying DNS service. */
449 put_opt6_char(ICMP6_OPT_RDNSS
);
452 put_opt6_long(min_pref_time
);
453 put_opt6(&parm
.link_local
, IN6ADDRSZ
);
456 /* set managed bits unless we're providing only RA on this link */
458 ra
->flags
|= 0x80; /* M flag, managed, */
460 ra
->flags
|= 0x40; /* O flag, other */
462 /* decide where we're sending */
463 memset(&addr
, 0, sizeof(addr
));
464 #ifdef HAVE_SOCKADDR_SA_LEN
465 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
467 addr
.sin6_family
= AF_INET6
;
468 addr
.sin6_port
= htons(IPPROTO_ICMPV6
);
471 addr
.sin6_addr
= *dest
;
472 if (IN6_IS_ADDR_LINKLOCAL(dest
) ||
473 IN6_IS_ADDR_MC_LINKLOCAL(dest
))
474 addr
.sin6_scope_id
= iface
;
478 inet_pton(AF_INET6
, ALL_NODES
, &addr
.sin6_addr
);
479 setsockopt(daemon
->icmp6fd
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &iface
, sizeof(iface
));
482 while (sendto(daemon
->icmp6fd
, daemon
->outpacket
.iov_base
, save_counter(0), 0,
483 (struct sockaddr
*)&addr
, sizeof(addr
)) == -1 && retry_send());
487 static int add_prefixes(struct in6_addr
*local
, int prefix
,
488 int scope
, int if_index
, int flags
,
489 unsigned int preferred
, unsigned int valid
, void *vparam
)
491 struct ra_param
*param
= vparam
;
493 (void)scope
; /* warning */
495 if (if_index
== param
->ind
)
497 if (IN6_IS_ADDR_LINKLOCAL(local
))
499 /* Can there be more than one LL address?
500 Select the one with the longest preferred time
502 if (preferred
> param
->link_pref_time
)
504 param
->link_pref_time
= preferred
;
505 param
->link_local
= *local
;
508 else if (!IN6_IS_ADDR_LOOPBACK(local
) &&
509 !IN6_IS_ADDR_MULTICAST(local
))
516 unsigned int time
= 0xffffffff;
517 struct dhcp_context
*context
;
519 for (context
= daemon
->dhcp6
; context
; context
= context
->next
)
520 if (!(context
->flags
& (CONTEXT_TEMPLATE
| CONTEXT_OLD
)) &&
521 prefix
<= context
->prefix
&&
522 is_same_net6(local
, &context
->start6
, context
->prefix
) &&
523 is_same_net6(local
, &context
->end6
, context
->prefix
))
525 context
->saved_valid
= valid
;
527 if (context
->flags
& CONTEXT_RA
)
530 if (context
->flags
& CONTEXT_DHCP
)
533 if (!(context
->flags
& CONTEXT_RA_STATELESS
))
539 /* don't do RA for non-ra-only unless --enable-ra is set */
540 if (!option_bool(OPT_RA
))
546 /* Configured to advertise router address, not prefix. See RFC 3775 7.2
547 In this case we do all addresses associated with a context,
548 hence the real_prefix setting here. */
549 if (context
->flags
& CONTEXT_RA_ROUTER
)
552 param
->adv_router
= 1;
553 real_prefix
= context
->prefix
;
556 /* find floor time, don't reduce below 3 * RA interval. */
557 if (time
> context
->lease_time
)
559 time
= context
->lease_time
;
560 if (time
< ((unsigned int)(3 * param
->adv_interval
)))
561 time
= 3 * param
->adv_interval
;
564 if (context
->flags
& CONTEXT_DEPRECATE
)
567 if (context
->flags
& CONTEXT_CONSTRUCTED
)
571 /* collect dhcp-range tags */
572 if (context
->netid
.next
== &context
->netid
&& context
->netid
.net
)
574 context
->netid
.next
= param
->tags
;
575 param
->tags
= &context
->netid
;
578 /* subsequent prefixes on the same interface
579 and subsequent instances of this prefix don't need timers.
580 Be careful not to find the same prefix twice with different
581 addresses unless we're advertising the actual addresses. */
582 if (!(context
->flags
& CONTEXT_RA_DONE
))
585 context
->ra_time
= 0;
586 context
->flags
|= CONTEXT_RA_DONE
;
587 real_prefix
= context
->prefix
;
591 param
->found_context
= 1;
594 /* configured time is ceiling */
595 if (!constructed
|| valid
> time
)
598 if (flags
& IFACE_DEPRECATED
)
604 /* configured time is ceiling */
605 if (!constructed
|| preferred
> time
)
608 if (IN6_IS_ADDR_ULA(local
))
610 if (preferred
> param
->ula_pref_time
)
612 param
->ula_pref_time
= preferred
;
618 if (preferred
> param
->glob_pref_time
)
620 param
->glob_pref_time
= preferred
;
621 param
->link_global
= *local
;
625 if (real_prefix
!= 0)
627 struct prefix_opt
*opt
;
629 if ((opt
= expand(sizeof(struct prefix_opt
))))
631 /* zero net part of address */
633 setaddr6part(local
, addr6part(local
) & ~((real_prefix
== 64) ? (u64
)-1LL : (1LLU << (128 - real_prefix
)) - 1LLU));
635 opt
->type
= ICMP6_OPT_PREFIX
;
637 opt
->prefix_len
= real_prefix
;
638 /* autonomous only if we're not doing dhcp, always set "on-link" */
644 opt
->valid_lifetime
= htonl(valid
);
645 opt
->preferred_lifetime
= htonl(preferred
);
647 opt
->prefix
= *local
;
649 inet_ntop(AF_INET6
, local
, daemon
->addrbuff
, ADDRSTRLEN
);
650 if (!option_bool(OPT_QUIET_RA
))
651 my_syslog(MS_DHCP
| LOG_INFO
, "RTR-ADVERT(%s) %s", param
->if_name
, daemon
->addrbuff
);
659 static int add_lla(int index
, unsigned int type
, char *mac
, size_t maclen
, void *parm
)
663 if (index
== *((int *)parm
))
665 /* size is in units of 8 octets and includes type and length (2 bytes)
667 int len
= (maclen
+ 9) >> 3;
668 unsigned char *p
= expand(len
<< 3);
669 memset(p
, 0, len
<< 3);
670 *p
++ = ICMP6_OPT_SOURCE_MAC
;
672 memcpy(p
, mac
, maclen
);
680 time_t periodic_ra(time_t now
)
682 struct search_param param
;
683 struct dhcp_context
*context
;
691 /* find overdue events, and time of first future event */
692 for (next_event
= 0, context
= daemon
->dhcp6
; context
; context
= context
->next
)
693 if (context
->ra_time
!= 0)
695 if (difftime(context
->ra_time
, now
) <= 0.0)
698 if (next_event
== 0 || difftime(next_event
, context
->ra_time
) > 0.0)
699 next_event
= context
->ra_time
;
706 if ((context
->flags
& CONTEXT_OLD
) &&
707 context
->if_index
!= 0 &&
708 indextoname(daemon
->icmp6fd
, context
->if_index
, param
.name
))
710 /* A context for an old address. We'll not find the interface by
711 looking for addresses, but we know it anyway, since the context is
713 param
.iface
= context
->if_index
;
714 new_timeout(context
, param
.name
, now
);
716 else if (iface_enumerate(AF_INET6
, ¶m
, iface_search
))
717 /* There's a context overdue, but we can't find an interface
718 associated with it, because it's for a subnet we dont
719 have an interface on. Probably we're doing DHCP on
720 a remote subnet via a relay. Zero the timer, since we won't
721 ever be able to send ra's and satistfy it. */
722 context
->ra_time
= 0;
724 if (param
.iface
!= 0 &&
725 iface_check(AF_LOCAL
, NULL
, param
.name
, NULL
))
728 for (tmp
= daemon
->dhcp_except
; tmp
; tmp
= tmp
->next
)
729 if (tmp
->name
&& wildcard_match(tmp
->name
, param
.name
))
732 send_ra(now
, param
.iface
, param
.name
, NULL
);
738 static int iface_search(struct in6_addr
*local
, int prefix
,
739 int scope
, int if_index
, int flags
,
740 int preferred
, int valid
, void *vparam
)
742 struct search_param
*param
= vparam
;
743 struct dhcp_context
*context
;
749 for (context
= daemon
->dhcp6
; context
; context
= context
->next
)
750 if (!(context
->flags
& (CONTEXT_TEMPLATE
| CONTEXT_OLD
)) &&
751 prefix
<= context
->prefix
&&
752 is_same_net6(local
, &context
->start6
, context
->prefix
) &&
753 is_same_net6(local
, &context
->end6
, context
->prefix
) &&
754 context
->ra_time
!= 0 &&
755 difftime(context
->ra_time
, param
->now
) <= 0.0)
757 /* found an interface that's overdue for RA determine new
758 timeout value and arrange for RA to be sent unless interface is
761 if (!(flags
& IFACE_TENTATIVE
))
762 param
->iface
= if_index
;
764 /* should never fail */
765 if (!indextoname(daemon
->icmp6fd
, if_index
, param
->name
))
771 new_timeout(context
, param
->name
, param
->now
);
773 /* zero timers for other contexts on the same subnet, so they don't timeout
775 for (context
= context
->next
; context
; context
= context
->next
)
776 if (prefix
<= context
->prefix
&&
777 is_same_net6(local
, &context
->start6
, context
->prefix
) &&
778 is_same_net6(local
, &context
->end6
, context
->prefix
))
779 context
->ra_time
= 0;
781 return 0; /* found, abort */
784 return 1; /* keep searching */
787 static void new_timeout(struct dhcp_context
*context
, char *iface_name
, time_t now
)
789 if (difftime(now
, context
->ra_short_period_start
) < 60.0)
791 context
->ra_time
= now
+ 5 + (rand16()/4400);
794 /* range 3/4 - 1 times MaxRtrAdvInterval */
795 unsigned int adv_interval
= calc_interval(find_iface_param(iface_name
));
796 context
->ra_time
= now
+ (3 * adv_interval
)/4 + ((adv_interval
* (unsigned int)rand16()) >> 18);
800 static struct ra_interface
*find_iface_param(char *iface
)
802 struct ra_interface
*ra
;
804 for (ra
= daemon
->ra_interfaces
; ra
; ra
= ra
->next
)
805 if (wildcard_match(ra
->name
, iface
))
811 static unsigned int calc_interval(struct ra_interface
*ra
)
815 if (ra
&& ra
->interval
!= 0)
817 interval
= ra
->interval
;
820 else if (interval
< 4)
824 return (unsigned int)interval
;
827 static unsigned int calc_lifetime(struct ra_interface
*ra
)
829 int lifetime
, interval
= (int)calc_interval(ra
);
831 if (!ra
|| ra
->lifetime
== -1) /* not specified */
832 lifetime
= 3 * interval
;
835 lifetime
= ra
->lifetime
;
836 if (lifetime
< interval
&& lifetime
!= 0)
838 else if (lifetime
> 9000)
842 return (unsigned int)lifetime
;
845 static unsigned int calc_prio(struct ra_interface
*ra
)