Don't send RAs to the wrong place when DAD in progress.

This commit is contained in:
Simon Kelley
2012-12-03 14:05:59 +00:00
parent 421594f83d
commit 29d28dda95
3 changed files with 32 additions and 18 deletions

View File

@@ -58,6 +58,15 @@ version 2.64
Check interface for outgoing unsolicited router
advertisements, rather than relying on interface address
configuration. Thanks to Gene Czarinski for the patch.
Handle better attempts to transmit on interfaces which are
still doing DAD, and specifically do not just transmit
without setting source address and interface, since this
can cause very puzzling effects when a router
advertisement goes astray. Thanks again to Gene Czarinski.
Get RA timers right when there is more than one
dhcp-range on a subnet.
version 2.63

View File

@@ -95,26 +95,19 @@ int send_from(int fd, int nowild, char *packet, size_t len,
#endif
}
retry:
if (sendmsg(fd, &msg, 0) == -1)
while (sendmsg(fd, &msg, 0) == -1)
{
/* certain Linux kernels seem to object to setting the source address in the IPv6 stack
by returning EINVAL from sendmsg. In that case, try again without setting the
source address, since it will nearly alway be correct anyway. IPv6 stinks. */
if (errno == EINVAL && msg.msg_controllen)
{
msg.msg_controllen = 0;
goto retry;
}
if (retry_send())
goto retry;
continue;
/* If interface is still in DAD, EINVAL results - ignore that. */
if (errno == EINVAL)
break;
my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno));
return 0;
}
return 1;
}

View File

@@ -457,6 +457,7 @@ time_t periodic_ra(time_t now)
char interface[IF_NAMESIZE+1];
param.now = now;
param.iface = 0;
while (1)
{
@@ -482,7 +483,8 @@ time_t periodic_ra(time_t now)
ever be able to send ra's and satistfy it. */
if (iface_enumerate(AF_INET6, &param, iface_search))
context->ra_time = 0;
else if (indextoname(daemon->icmp6fd, param.iface, interface) &&
else if (param.iface != 0 &&
indextoname(daemon->icmp6fd, param.iface, interface) &&
iface_check(AF_LOCAL, NULL, interface))
{
struct iname *tmp;
@@ -512,9 +514,11 @@ static int iface_search(struct in6_addr *local, int prefix,
if (context->ra_time != 0 && difftime(context->ra_time, param->now) <= 0.0)
{
/* found an interface that's overdue for RA determine new
timeout value and zap other contexts on the same interface
so they don't timeout independently .*/
param->iface = if_index;
timeout value and arrange for RA to be sent unless interface is
still doing DAD.*/
if (!dad)
param->iface = if_index;
if (difftime(param->now, ra_short_period_start) < 60.0)
/* range 5 - 20 */
@@ -523,6 +527,14 @@ static int iface_search(struct in6_addr *local, int prefix,
/* range 450 - 600 */
context->ra_time = param->now + 450 + (rand16()/440);
/* zero timers for other contexts on the same subnet, so they don't timeout
independently */
for (context = context->next; context; context = context->next)
if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
context->ra_time = 0;
return 0; /* found, abort */
}