]>
git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/radv.c
1 /* dnsmasq is Copyright (c) 2000-2015 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];
45 struct dhcp_bridge
*bridge
;
51 static void send_ra(time_t now
, int iface
, char *iface_name
, struct in6_addr
*dest
);
52 static void send_ra_alias(time_t now
, int iface
, char *iface_name
, struct in6_addr
*dest
,
54 static int send_ra_to_aliases(int index
, unsigned int type
, char *mac
, size_t maclen
, void *parm
);
55 static int add_prefixes(struct in6_addr
*local
, int prefix
,
56 int scope
, int if_index
, int flags
,
57 unsigned int preferred
, unsigned int valid
, void *vparam
);
58 static int iface_search(struct in6_addr
*local
, int prefix
,
59 int scope
, int if_index
, int flags
,
60 int prefered
, int valid
, void *vparam
);
61 static int add_lla(int index
, unsigned int type
, char *mac
, size_t maclen
, void *parm
);
62 static void new_timeout(struct dhcp_context
*context
, char *iface_name
, time_t now
);
63 static unsigned int calc_lifetime(struct ra_interface
*ra
);
64 static unsigned int calc_interval(struct ra_interface
*ra
);
65 static unsigned int calc_prio(struct ra_interface
*ra
);
66 static struct ra_interface
*find_iface_param(char *iface
);
70 void ra_init(time_t now
)
72 struct icmp6_filter filter
;
74 #if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
75 int class = IPTOS_CLASS_CS6
;
77 int val
= 255; /* radvd uses this value */
78 socklen_t len
= sizeof(int);
79 struct dhcp_context
*context
;
81 /* ensure this is around even if we're not doing DHCPv6 */
82 expand_buf(&daemon
->outpacket
, sizeof(struct dhcp_packet
));
84 /* See if we're guessing SLAAC addresses, if so we need to recieve ping replies */
85 for (context
= daemon
->dhcp6
; context
; context
= context
->next
)
86 if ((context
->flags
& CONTEXT_RA_NAME
))
89 /* Need ICMP6 socket for transmission for DHCPv6 even when not doing RA. */
91 ICMP6_FILTER_SETBLOCKALL(&filter
);
94 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT
, &filter
);
96 ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY
, &filter
);
99 if ((fd
= socket(PF_INET6
, SOCK_RAW
, IPPROTO_ICMPV6
)) == -1 ||
100 getsockopt(fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &hop_limit
, &len
) ||
101 #if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
102 setsockopt(fd
, IPPROTO_IPV6
, IPV6_TCLASS
, &class, sizeof(class)) == -1 ||
105 !set_ipv6pktinfo(fd
) ||
106 setsockopt(fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &val
, sizeof(val
)) ||
107 setsockopt(fd
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &val
, sizeof(val
)) ||
108 setsockopt(fd
, IPPROTO_ICMPV6
, ICMP6_FILTER
, &filter
, sizeof(filter
)) == -1)
109 die (_("cannot create ICMPv6 socket: %s"), NULL
, EC_BADNET
);
111 daemon
->icmp6fd
= fd
;
113 if (daemon
->doing_ra
)
114 ra_start_unsolicted(now
, NULL
);
117 void ra_start_unsolicted(time_t now
, struct dhcp_context
*context
)
119 /* init timers so that we do ra's for some/all soon. some ra_times will end up zeroed
120 if it's not appropriate to advertise those contexts.
121 This gets re-called on a netlink route-change to re-do the advertisement
122 and pick up new interfaces */
125 context
->ra_short_period_start
= context
->ra_time
= now
;
127 for (context
= daemon
->dhcp6
; context
; context
= context
->next
)
128 if (!(context
->flags
& CONTEXT_TEMPLATE
))
130 context
->ra_time
= now
+ (rand16()/13000); /* range 0 - 5 */
131 /* re-do frequently for a minute or so, in case the first gets lost. */
132 context
->ra_short_period_start
= now
;
136 void icmp6_packet(time_t now
)
138 char interface
[IF_NAMESIZE
+1];
141 struct cmsghdr
*cmptr
;
144 struct cmsghdr align
; /* this ensures alignment */
145 char control6
[CMSG_SPACE(sizeof(struct in6_pktinfo
))];
147 struct sockaddr_in6 from
;
148 unsigned char *packet
;
151 /* Note: use outpacket for input buffer */
152 msg
.msg_control
= control_u
.control6
;
153 msg
.msg_controllen
= sizeof(control_u
);
155 msg
.msg_name
= &from
;
156 msg
.msg_namelen
= sizeof(from
);
157 msg
.msg_iov
= &daemon
->outpacket
;
160 if ((sz
= recv_dhcp_packet(daemon
->icmp6fd
, &msg
)) == -1 || sz
< 8)
163 packet
= (unsigned char *)daemon
->outpacket
.iov_base
;
165 for (cmptr
= CMSG_FIRSTHDR(&msg
); cmptr
; cmptr
= CMSG_NXTHDR(&msg
, cmptr
))
166 if (cmptr
->cmsg_level
== IPPROTO_IPV6
&& cmptr
->cmsg_type
== daemon
->v6pktinfo
)
170 struct in6_pktinfo
*p
;
172 p
.c
= CMSG_DATA(cmptr
);
174 if_index
= p
.p
->ipi6_ifindex
;
177 if (!indextoname(daemon
->icmp6fd
, if_index
, interface
))
180 if (!iface_check(AF_LOCAL
, NULL
, interface
, NULL
))
183 for (tmp
= daemon
->dhcp_except
; tmp
; tmp
= tmp
->next
)
184 if (tmp
->name
&& wildcard_match(tmp
->name
, interface
))
190 if (packet
[0] == ICMP6_ECHO_REPLY
)
191 lease_ping_reply(&from
.sin6_addr
, packet
, interface
);
192 else if (packet
[0] == ND_ROUTER_SOLICIT
)
195 struct dhcp_bridge
*bridge
, *alias
;
197 /* look for link-layer address option for logging */
198 if (sz
>= 16 && packet
[8] == ICMP6_OPT_SOURCE_MAC
&& (packet
[9] * 8) + 8 <= sz
)
200 print_mac(daemon
->namebuff
, &packet
[10], (packet
[9] * 8) - 2);
201 mac
= daemon
->namebuff
;
204 if (!option_bool(OPT_QUIET_RA
))
205 my_syslog(MS_DHCP
| LOG_INFO
, "RTR-SOLICIT(%s) %s", interface
, mac
);
207 /* If the incoming interface is an alias of some other one (as
208 specified by the --bridge-interface option), send an RA using
209 the context of the aliased interface. */
210 for (bridge
= daemon
->bridges
; bridge
; bridge
= bridge
->next
)
212 int bridge_index
= if_nametoindex(bridge
->iface
);
215 for (alias
= bridge
->alias
; alias
; alias
= alias
->next
)
216 if (wildcard_matchn(alias
->iface
, interface
, IF_NAMESIZE
))
218 /* Send an RA on if_index with information from
220 send_ra_alias(now
, bridge_index
, bridge
->iface
, NULL
, if_index
);
228 /* If the incoming interface wasn't an alias, send an RA using
229 the context of the incoming interface. */
231 /* source address may not be valid in solicit request. */
232 send_ra(now
, if_index
, interface
, !IN6_IS_ADDR_UNSPECIFIED(&from
.sin6_addr
) ? &from
.sin6_addr
: NULL
);
236 static void send_ra_alias(time_t now
, int iface
, char *iface_name
, struct in6_addr
*dest
, int send_iface
)
238 struct ra_packet
*ra
;
239 struct ra_param parm
;
240 struct sockaddr_in6 addr
;
241 struct dhcp_context
*context
, *tmp
, **up
;
242 struct dhcp_netid iface_id
;
243 struct dhcp_opt
*opt_cfg
;
244 struct ra_interface
*ra_param
= find_iface_param(iface_name
);
245 int done_dns
= 0, old_prefix
= 0;
246 unsigned int min_pref_time
;
247 #ifdef HAVE_LINUX_NETWORK
254 parm
.found_context
= 0;
256 parm
.if_name
= iface_name
;
259 parm
.glob_pref_time
= parm
.link_pref_time
= parm
.ula_pref_time
= 0;
260 parm
.adv_interval
= calc_interval(ra_param
);
261 parm
.prio
= calc_prio(ra_param
);
264 ra
= expand(sizeof(struct ra_packet
));
266 ra
->type
= ND_ROUTER_ADVERT
;
268 ra
->hop_limit
= hop_limit
;
269 ra
->flags
= parm
.prio
;
270 ra
->lifetime
= htons(calc_lifetime(ra_param
));
271 ra
->reachable_time
= 0;
272 ra
->retrans_time
= 0;
274 /* set tag with name == interface */
275 iface_id
.net
= iface_name
;
276 iface_id
.next
= NULL
;
277 parm
.tags
= &iface_id
;
279 for (context
= daemon
->dhcp6
; context
; context
= context
->next
)
281 context
->flags
&= ~CONTEXT_RA_DONE
;
282 context
->netid
.next
= &context
->netid
;
285 if (!iface_enumerate(AF_INET6
, &parm
, add_prefixes
))
288 /* Find smallest preferred time within address classes,
289 to use as lifetime for options. This is a rather arbitrary choice. */
290 min_pref_time
= 0xffffffff;
291 if (parm
.glob_pref_time
!= 0 && parm
.glob_pref_time
< min_pref_time
)
292 min_pref_time
= parm
.glob_pref_time
;
294 if (parm
.ula_pref_time
!= 0 && parm
.ula_pref_time
< min_pref_time
)
295 min_pref_time
= parm
.ula_pref_time
;
297 if (parm
.link_pref_time
!= 0 && parm
.link_pref_time
< min_pref_time
)
298 min_pref_time
= parm
.link_pref_time
;
300 /* Look for constructed contexts associated with addresses which have gone,
301 and advertise them with preferred_time == 0 RFC 6204 4.3 L-13 */
302 for (up
= &daemon
->dhcp6
, context
= daemon
->dhcp6
; context
; context
= tmp
)
306 if (context
->if_index
== iface
&& (context
->flags
& CONTEXT_OLD
))
308 unsigned int old
= difftime(now
, context
->address_lost_time
);
310 if (old
> context
->saved_valid
)
312 /* We've advertised this enough, time to go */
318 struct prefix_opt
*opt
;
319 struct in6_addr local
= context
->start6
;
324 /* zero net part of address */
325 setaddr6part(&local
, addr6part(&local
) & ~((context
->prefix
== 64) ? (u64
)-1LL : (1LLU << (128 - context
->prefix
)) - 1LLU));
328 if (context
->flags
& CONTEXT_RA
)
331 if (context
->flags
& CONTEXT_DHCP
)
334 if (!(context
->flags
& CONTEXT_RA_STATELESS
))
340 /* don't do RA for non-ra-only unless --enable-ra is set */
341 if (option_bool(OPT_RA
))
348 if ((opt
= expand(sizeof(struct prefix_opt
))))
350 opt
->type
= ICMP6_OPT_PREFIX
;
352 opt
->prefix_len
= context
->prefix
;
353 /* autonomous only if we're not doing dhcp, set
354 "on-link" unless "off-link" was specified */
355 opt
->flags
= (do_slaac
? 0x40 : 0) |
356 ((context
->flags
& CONTEXT_RA_OFF_LINK
) ? 0 : 0x80);
357 opt
->valid_lifetime
= htonl(context
->saved_valid
- old
);
358 opt
->preferred_lifetime
= htonl(0);
362 inet_ntop(AF_INET6
, &local
, daemon
->addrbuff
, ADDRSTRLEN
);
363 if (!option_bool(OPT_QUIET_RA
))
364 my_syslog(MS_DHCP
| LOG_INFO
, "RTR-ADVERT(%s) %s old prefix", iface_name
, daemon
->addrbuff
);
374 /* If we're advertising only old prefixes, set router lifetime to zero. */
375 if (old_prefix
&& !parm
.found_context
)
376 ra
->lifetime
= htons(0);
378 /* No prefixes to advertise. */
379 if (!old_prefix
&& !parm
.found_context
)
382 /* If we're sending router address instead of prefix in at least on prefix,
383 include the advertisement interval option. */
386 put_opt6_char(ICMP6_OPT_ADV_INTERVAL
);
389 /* interval value is in milliseconds */
390 put_opt6_long(1000 * calc_interval(find_iface_param(iface_name
)));
393 #ifdef HAVE_LINUX_NETWORK
394 /* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU
395 available from SIOCGIFMTU */
396 sprintf(daemon
->namebuff
, "/proc/sys/net/ipv6/conf/%s/mtu", iface_name
);
397 if ((f
= fopen(daemon
->namebuff
, "r")))
399 if (fgets(daemon
->namebuff
, MAXDNAME
, f
))
401 put_opt6_char(ICMP6_OPT_MTU
);
404 put_opt6_long(atoi(daemon
->namebuff
));
410 iface_enumerate(AF_LOCAL
, &send_iface
, add_lla
);
412 /* RDNSS, RFC 6106, use relevant DHCP6 options */
413 (void)option_filter(parm
.tags
, NULL
, daemon
->dhcp_opts6
);
415 for (opt_cfg
= daemon
->dhcp_opts6
; opt_cfg
; opt_cfg
= opt_cfg
->next
)
419 /* netids match and not encapsulated? */
420 if (!(opt_cfg
->flags
& DHOPT_TAGOK
))
423 if (opt_cfg
->opt
== OPTION6_DNS_SERVER
)
430 if (opt_cfg
->len
== 0)
433 /* reduce len for any addresses we can't substitute */
434 for (a
= (struct in6_addr
*)opt_cfg
->val
, len
= opt_cfg
->len
, i
= 0;
435 i
< opt_cfg
->len
; i
+= IN6ADDRSZ
, a
++)
436 if ((IN6_IS_ADDR_UNSPECIFIED(a
) && parm
.glob_pref_time
== 0) ||
437 (IN6_IS_ADDR_ULA_ZERO(a
) && parm
.ula_pref_time
== 0) ||
438 (IN6_IS_ADDR_LINK_LOCAL_ZERO(a
) && parm
.link_pref_time
== 0))
443 put_opt6_char(ICMP6_OPT_RDNSS
);
444 put_opt6_char((len
/8) + 1);
446 put_opt6_long(min_pref_time
);
448 for (a
= (struct in6_addr
*)opt_cfg
->val
, i
= 0; i
< opt_cfg
->len
; i
+= IN6ADDRSZ
, a
++)
449 if (IN6_IS_ADDR_UNSPECIFIED(a
))
451 if (parm
.glob_pref_time
!= 0)
452 put_opt6(&parm
.link_global
, IN6ADDRSZ
);
454 else if (IN6_IS_ADDR_ULA_ZERO(a
))
456 if (parm
.ula_pref_time
!= 0)
457 put_opt6(&parm
.ula
, IN6ADDRSZ
);
459 else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a
))
461 if (parm
.link_pref_time
!= 0)
462 put_opt6(&parm
.link_local
, IN6ADDRSZ
);
465 put_opt6(a
, IN6ADDRSZ
);
469 if (opt_cfg
->opt
== OPTION6_DOMAIN_SEARCH
&& opt_cfg
->len
!= 0)
471 int len
= ((opt_cfg
->len
+7)/8);
473 put_opt6_char(ICMP6_OPT_DNSSL
);
474 put_opt6_char(len
+ 1);
476 put_opt6_long(min_pref_time
);
477 put_opt6(opt_cfg
->val
, opt_cfg
->len
);
480 for (i
= opt_cfg
->len
; i
< len
* 8; i
++)
485 if (daemon
->port
== NAMESERVER_PORT
&& !done_dns
&& parm
.link_pref_time
!= 0)
487 /* default == us, as long as we are supplying DNS service. */
488 put_opt6_char(ICMP6_OPT_RDNSS
);
491 put_opt6_long(min_pref_time
);
492 put_opt6(&parm
.link_local
, IN6ADDRSZ
);
495 /* set managed bits unless we're providing only RA on this link */
497 ra
->flags
|= 0x80; /* M flag, managed, */
499 ra
->flags
|= 0x40; /* O flag, other */
501 /* decide where we're sending */
502 memset(&addr
, 0, sizeof(addr
));
503 #ifdef HAVE_SOCKADDR_SA_LEN
504 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
506 addr
.sin6_family
= AF_INET6
;
507 addr
.sin6_port
= htons(IPPROTO_ICMPV6
);
510 addr
.sin6_addr
= *dest
;
511 if (IN6_IS_ADDR_LINKLOCAL(dest
) ||
512 IN6_IS_ADDR_MC_LINKLOCAL(dest
))
513 addr
.sin6_scope_id
= iface
;
517 inet_pton(AF_INET6
, ALL_NODES
, &addr
.sin6_addr
);
518 setsockopt(daemon
->icmp6fd
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &send_iface
, sizeof(send_iface
));
521 while (retry_send(sendto(daemon
->icmp6fd
, daemon
->outpacket
.iov_base
,
522 save_counter(0), 0, (struct sockaddr
*)&addr
,
527 static void send_ra(time_t now
, int iface
, char *iface_name
, struct in6_addr
*dest
)
529 /* Send an RA on the same interface that the RA content is based
531 send_ra_alias(now
, iface
, iface_name
, dest
, iface
);
534 static int add_prefixes(struct in6_addr
*local
, int prefix
,
535 int scope
, int if_index
, int flags
,
536 unsigned int preferred
, unsigned int valid
, void *vparam
)
538 struct ra_param
*param
= vparam
;
540 (void)scope
; /* warning */
542 if (if_index
== param
->ind
)
544 if (IN6_IS_ADDR_LINKLOCAL(local
))
546 /* Can there be more than one LL address?
547 Select the one with the longest preferred time
549 if (preferred
> param
->link_pref_time
)
551 param
->link_pref_time
= preferred
;
552 param
->link_local
= *local
;
555 else if (!IN6_IS_ADDR_LOOPBACK(local
) &&
556 !IN6_IS_ADDR_MULTICAST(local
))
564 unsigned int time
= 0xffffffff;
565 struct dhcp_context
*context
;
567 for (context
= daemon
->dhcp6
; context
; context
= context
->next
)
568 if (!(context
->flags
& (CONTEXT_TEMPLATE
| CONTEXT_OLD
)) &&
569 prefix
<= context
->prefix
&&
570 is_same_net6(local
, &context
->start6
, context
->prefix
) &&
571 is_same_net6(local
, &context
->end6
, context
->prefix
))
573 context
->saved_valid
= valid
;
575 if (context
->flags
& CONTEXT_RA
)
578 if (context
->flags
& CONTEXT_DHCP
)
581 if (!(context
->flags
& CONTEXT_RA_STATELESS
))
587 /* don't do RA for non-ra-only unless --enable-ra is set */
588 if (!option_bool(OPT_RA
))
594 /* Configured to advertise router address, not prefix. See RFC 3775 7.2
595 In this case we do all addresses associated with a context,
596 hence the real_prefix setting here. */
597 if (context
->flags
& CONTEXT_RA_ROUTER
)
600 param
->adv_router
= 1;
601 real_prefix
= context
->prefix
;
604 /* find floor time, don't reduce below 3 * RA interval. */
605 if (time
> context
->lease_time
)
607 time
= context
->lease_time
;
608 if (time
< ((unsigned int)(3 * param
->adv_interval
)))
609 time
= 3 * param
->adv_interval
;
612 if (context
->flags
& CONTEXT_DEPRECATE
)
615 if (context
->flags
& CONTEXT_CONSTRUCTED
)
619 /* collect dhcp-range tags */
620 if (context
->netid
.next
== &context
->netid
&& context
->netid
.net
)
622 context
->netid
.next
= param
->tags
;
623 param
->tags
= &context
->netid
;
626 /* subsequent prefixes on the same interface
627 and subsequent instances of this prefix don't need timers.
628 Be careful not to find the same prefix twice with different
629 addresses unless we're advertising the actual addresses. */
630 if (!(context
->flags
& CONTEXT_RA_DONE
))
633 context
->ra_time
= 0;
634 context
->flags
|= CONTEXT_RA_DONE
;
635 real_prefix
= context
->prefix
;
636 off_link
= (context
->flags
& CONTEXT_RA_OFF_LINK
);
640 param
->found_context
= 1;
643 /* configured time is ceiling */
644 if (!constructed
|| valid
> time
)
647 if (flags
& IFACE_DEPRECATED
)
653 /* configured time is ceiling */
654 if (!constructed
|| preferred
> time
)
657 if (IN6_IS_ADDR_ULA(local
))
659 if (preferred
> param
->ula_pref_time
)
661 param
->ula_pref_time
= preferred
;
667 if (preferred
> param
->glob_pref_time
)
669 param
->glob_pref_time
= preferred
;
670 param
->link_global
= *local
;
674 if (real_prefix
!= 0)
676 struct prefix_opt
*opt
;
678 if ((opt
= expand(sizeof(struct prefix_opt
))))
680 /* zero net part of address */
682 setaddr6part(local
, addr6part(local
) & ~((real_prefix
== 64) ? (u64
)-1LL : (1LLU << (128 - real_prefix
)) - 1LLU));
684 opt
->type
= ICMP6_OPT_PREFIX
;
686 opt
->prefix_len
= real_prefix
;
687 /* autonomous only if we're not doing dhcp, set
688 "on-link" unless "off-link" was specified */
689 opt
->flags
= (off_link
? 0 : 0x80);
694 opt
->valid_lifetime
= htonl(valid
);
695 opt
->preferred_lifetime
= htonl(preferred
);
697 opt
->prefix
= *local
;
699 inet_ntop(AF_INET6
, local
, daemon
->addrbuff
, ADDRSTRLEN
);
700 if (!option_bool(OPT_QUIET_RA
))
701 my_syslog(MS_DHCP
| LOG_INFO
, "RTR-ADVERT(%s) %s", param
->if_name
, daemon
->addrbuff
);
709 static int add_lla(int index
, unsigned int type
, char *mac
, size_t maclen
, void *parm
)
713 if (index
== *((int *)parm
))
715 /* size is in units of 8 octets and includes type and length (2 bytes)
717 int len
= (maclen
+ 9) >> 3;
718 unsigned char *p
= expand(len
<< 3);
719 memset(p
, 0, len
<< 3);
720 *p
++ = ICMP6_OPT_SOURCE_MAC
;
722 memcpy(p
, mac
, maclen
);
730 time_t periodic_ra(time_t now
)
732 struct search_param param
;
733 struct dhcp_context
*context
;
735 struct alias_param aparam
;
742 /* find overdue events, and time of first future event */
743 for (next_event
= 0, context
= daemon
->dhcp6
; context
; context
= context
->next
)
744 if (context
->ra_time
!= 0)
746 if (difftime(context
->ra_time
, now
) <= 0.0)
749 if (next_event
== 0 || difftime(next_event
, context
->ra_time
) > 0.0)
750 next_event
= context
->ra_time
;
757 if ((context
->flags
& CONTEXT_OLD
) &&
758 context
->if_index
!= 0 &&
759 indextoname(daemon
->icmp6fd
, context
->if_index
, param
.name
))
761 /* A context for an old address. We'll not find the interface by
762 looking for addresses, but we know it anyway, since the context is
764 param
.iface
= context
->if_index
;
765 new_timeout(context
, param
.name
, now
);
767 else if (iface_enumerate(AF_INET6
, ¶m
, iface_search
))
768 /* There's a context overdue, but we can't find an interface
769 associated with it, because it's for a subnet we dont
770 have an interface on. Probably we're doing DHCP on
771 a remote subnet via a relay. Zero the timer, since we won't
772 ever be able to send ra's and satistfy it. */
773 context
->ra_time
= 0;
775 if (param
.iface
!= 0 &&
776 iface_check(AF_LOCAL
, NULL
, param
.name
, NULL
))
779 for (tmp
= daemon
->dhcp_except
; tmp
; tmp
= tmp
->next
)
780 if (tmp
->name
&& wildcard_match(tmp
->name
, param
.name
))
784 send_ra(now
, param
.iface
, param
.name
, NULL
);
786 /* Also send on all interfaces that are aliases of this
788 for (aparam
.bridge
= daemon
->bridges
;
790 aparam
.bridge
= aparam
.bridge
->next
)
791 if ((int)if_nametoindex(aparam
.bridge
->iface
) == param
.iface
)
793 /* Count the number of alias interfaces for this
794 'bridge', by calling iface_enumerate with
795 send_ra_to_aliases and NULL alias_ifs. */
796 aparam
.iface
= param
.iface
;
797 aparam
.alias_ifs
= NULL
;
798 aparam
.num_alias_ifs
= 0;
799 iface_enumerate(AF_LOCAL
, &aparam
, send_ra_to_aliases
);
800 my_syslog(MS_DHCP
| LOG_INFO
, "RTR-ADVERT(%s) %s => %d alias(es)",
801 param
.name
, daemon
->addrbuff
, aparam
.num_alias_ifs
);
803 /* Allocate memory to store the alias interface
805 aparam
.alias_ifs
= (int *)whine_malloc(aparam
.num_alias_ifs
*
807 if (aparam
.alias_ifs
)
809 /* Use iface_enumerate again to get the alias
810 interface indices, then send on each of
812 aparam
.max_alias_ifs
= aparam
.num_alias_ifs
;
813 aparam
.num_alias_ifs
= 0;
814 iface_enumerate(AF_LOCAL
, &aparam
, send_ra_to_aliases
);
815 for (; aparam
.num_alias_ifs
; aparam
.num_alias_ifs
--)
817 my_syslog(MS_DHCP
| LOG_INFO
, "RTR-ADVERT(%s) %s => i/f %d",
818 param
.name
, daemon
->addrbuff
,
819 aparam
.alias_ifs
[aparam
.num_alias_ifs
- 1]);
824 aparam
.alias_ifs
[aparam
.num_alias_ifs
- 1]);
826 free(aparam
.alias_ifs
);
829 /* The source interface can only appear in at most
830 one --bridge-interface. */
839 static int send_ra_to_aliases(int index
, unsigned int type
, char *mac
, size_t maclen
, void *parm
)
841 struct alias_param
*aparam
= (struct alias_param
*)parm
;
842 char ifrn_name
[IFNAMSIZ
];
843 struct dhcp_bridge
*alias
;
849 if (if_indextoname(index
, ifrn_name
))
850 for (alias
= aparam
->bridge
->alias
; alias
; alias
= alias
->next
)
851 if (wildcard_matchn(alias
->iface
, ifrn_name
, IFNAMSIZ
))
853 if (aparam
->alias_ifs
&& (aparam
->num_alias_ifs
< aparam
->max_alias_ifs
))
854 aparam
->alias_ifs
[aparam
->num_alias_ifs
] = index
;
855 aparam
->num_alias_ifs
++;
861 static int iface_search(struct in6_addr
*local
, int prefix
,
862 int scope
, int if_index
, int flags
,
863 int preferred
, int valid
, void *vparam
)
865 struct search_param
*param
= vparam
;
866 struct dhcp_context
*context
;
872 for (context
= daemon
->dhcp6
; context
; context
= context
->next
)
873 if (!(context
->flags
& (CONTEXT_TEMPLATE
| CONTEXT_OLD
)) &&
874 prefix
<= context
->prefix
&&
875 is_same_net6(local
, &context
->start6
, context
->prefix
) &&
876 is_same_net6(local
, &context
->end6
, context
->prefix
) &&
877 context
->ra_time
!= 0 &&
878 difftime(context
->ra_time
, param
->now
) <= 0.0)
880 /* found an interface that's overdue for RA determine new
881 timeout value and arrange for RA to be sent unless interface is
884 if (!(flags
& IFACE_TENTATIVE
))
885 param
->iface
= if_index
;
887 /* should never fail */
888 if (!indextoname(daemon
->icmp6fd
, if_index
, param
->name
))
894 new_timeout(context
, param
->name
, param
->now
);
896 /* zero timers for other contexts on the same subnet, so they don't timeout
898 for (context
= context
->next
; context
; context
= context
->next
)
899 if (prefix
<= context
->prefix
&&
900 is_same_net6(local
, &context
->start6
, context
->prefix
) &&
901 is_same_net6(local
, &context
->end6
, context
->prefix
))
902 context
->ra_time
= 0;
904 return 0; /* found, abort */
907 return 1; /* keep searching */
910 static void new_timeout(struct dhcp_context
*context
, char *iface_name
, time_t now
)
912 if (difftime(now
, context
->ra_short_period_start
) < 60.0)
914 context
->ra_time
= now
+ 5 + (rand16()/4400);
917 /* range 3/4 - 1 times MaxRtrAdvInterval */
918 unsigned int adv_interval
= calc_interval(find_iface_param(iface_name
));
919 context
->ra_time
= now
+ (3 * adv_interval
)/4 + ((adv_interval
* (unsigned int)rand16()) >> 18);
923 static struct ra_interface
*find_iface_param(char *iface
)
925 struct ra_interface
*ra
;
927 for (ra
= daemon
->ra_interfaces
; ra
; ra
= ra
->next
)
928 if (wildcard_match(ra
->name
, iface
))
934 static unsigned int calc_interval(struct ra_interface
*ra
)
938 if (ra
&& ra
->interval
!= 0)
940 interval
= ra
->interval
;
943 else if (interval
< 4)
947 return (unsigned int)interval
;
950 static unsigned int calc_lifetime(struct ra_interface
*ra
)
952 int lifetime
, interval
= (int)calc_interval(ra
);
954 if (!ra
|| ra
->lifetime
== -1) /* not specified */
955 lifetime
= 3 * interval
;
958 lifetime
= ra
->lifetime
;
959 if (lifetime
< interval
&& lifetime
!= 0)
961 else if (lifetime
> 9000)
965 return (unsigned int)lifetime
;
968 static unsigned int calc_prio(struct ra_interface
*ra
)