First checkin of interface-address constructor mode for DHCPv6 and RA.
diff --git a/src/radv.c b/src/radv.c
index 54884a2..b74c398 100644
--- a/src/radv.c
+++ b/src/radv.c
@@ -27,6 +27,7 @@
#include <netinet/icmp6.h>
struct ra_param {
+ time_t now;
int ind, managed, other, found_context, first;
char *if_name;
struct dhcp_netid *tags;
@@ -37,11 +38,13 @@
time_t now; int iface;
};
-static void send_ra(int iface, char *iface_name, struct in6_addr *dest);
+static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest);
static int add_prefixes(struct in6_addr *local, int prefix,
- int scope, int if_index, int dad, void *vparam);
+ int scope, int if_index, int dad,
+ int preferred, int valid, void *vparam);
static int iface_search(struct in6_addr *local, int prefix,
- int scope, int if_index, int dad, void *vparam);
+ int scope, int if_index, int dad,
+ int prefered, int valid, void *vparam);
static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
static int hop_limit;
@@ -62,7 +65,7 @@
expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
/* See if we're guessing SLAAC addresses, if so we need to recieve ping replies */
- for (context = daemon->ra_contexts; context; context = context->next)
+ for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME))
break;
@@ -98,14 +101,17 @@
if (context)
context->ra_time = now;
else
- for (context = daemon->ra_contexts; context; context = context->next)
- context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
-
+ for (context = daemon->dhcp6; context; context = context->next)
+ if (context->flags & CONTEXT_RA)
+ context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
+ else
+ context->ra_time = 0;
+
/* re-do frequently for a minute or so, in case the first gets lost. */
ra_short_period_start = now;
}
-void icmp6_packet(void)
+void icmp6_packet(time_t now)
{
char interface[IF_NAMESIZE+1];
ssize_t sz;
@@ -174,11 +180,11 @@
my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
/* source address may not be valid in solicit request. */
- send_ra(if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
+ send_ra(now, if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
}
}
-static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
+static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest)
{
struct ra_packet *ra;
struct ra_param parm;
@@ -206,13 +212,14 @@
parm.found_context = 0;
parm.if_name = iface_name;
parm.first = 1;
-
+ parm.now = now;
+
/* set tag with name == interface */
iface_id.net = iface_name;
iface_id.next = NULL;
parm.tags = &iface_id;
- for (context = daemon->ra_contexts; context; context = context->next)
+ for (context = daemon->dhcp6; context; context = context->next)
{
context->flags &= ~CONTEXT_RA_DONE;
context->netid.next = &context->netid;
@@ -320,28 +327,32 @@
}
static int add_prefixes(struct in6_addr *local, int prefix,
- int scope, int if_index, int dad, void *vparam)
+ int scope, int if_index, int dad,
+ int preferred, int valid, void *vparam)
{
struct ra_param *param = vparam;
(void)scope; /* warning */
(void)dad;
+ (void)preferred;
+ (void)valid;
if (if_index == param->ind)
{
if (IN6_IS_ADDR_LINKLOCAL(local))
param->link_local = *local;
else if (!IN6_IS_ADDR_LOOPBACK(local) &&
- !IN6_IS_ADDR_LINKLOCAL(local) &&
!IN6_IS_ADDR_MULTICAST(local))
{
int do_prefix = 0;
int do_slaac = 0;
int deprecate = 0;
+ int found_constructed = 0;
unsigned int time = 0xffffffff;
+ int calc_valid = 0, calc_preferred = 0;
struct dhcp_context *context;
- for (context = daemon->ra_contexts; context; context = context->next)
+ for (context = daemon->dhcp6; context; context = context->next)
if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
@@ -365,7 +376,18 @@
param->managed = 1;
param->other = 1;
}
-
+
+ if (context->flags & CONTEXT_CONSTRUCTED)
+ {
+ found_constructed = 1;
+ calc_valid = context->valid;
+ calc_preferred = context->preferred;
+ if (context->valid != -1)
+ calc_valid -= (int)param->now;
+ if (context->preferred != -1)
+ calc_preferred -= (int)param->now;
+ }
+
/* find floor time */
if (time > context->lease_time)
time = context->lease_time;
@@ -395,6 +417,12 @@
param->first = 0;
param->found_context = 1;
}
+
+ if (!found_constructed)
+ {
+ calc_valid = time;
+ calc_preferred = deprecate ? 0 : time;
+ }
if (do_prefix)
{
@@ -414,8 +442,8 @@
opt->prefix_len = prefix;
/* autonomous only if we're not doing dhcp, always set "on-link" */
opt->flags = do_slaac ? 0xC0 : 0x80;
- opt->valid_lifetime = htonl(time);
- opt->preferred_lifetime = htonl(deprecate ? 0 : time);
+ opt->valid_lifetime = htonl(calc_valid);
+ opt->preferred_lifetime = htonl(calc_preferred);
opt->reserved = 0;
opt->prefix = *local;
@@ -462,7 +490,7 @@
while (1)
{
/* find overdue events, and time of first future event */
- for (next_event = 0, context = daemon->ra_contexts; context; context = context->next)
+ for (next_event = 0, context = daemon->dhcp6; context; context = context->next)
if (context->ra_time != 0)
{
if (difftime(context->ra_time, now) <= 0.0)
@@ -492,22 +520,25 @@
if (tmp->name && (strcmp(tmp->name, interface) == 0))
break;
if (!tmp)
- send_ra(param.iface, interface, NULL);
+ send_ra(now, param.iface, interface, NULL);
}
}
return next_event;
}
static int iface_search(struct in6_addr *local, int prefix,
- int scope, int if_index, int dad, void *vparam)
+ int scope, int if_index, int dad,
+ int preferred, int valid, void *vparam)
{
struct search_param *param = vparam;
struct dhcp_context *context;
(void)scope;
(void)dad;
+ (void)preferred;
+ (void)valid;
- for (context = daemon->ra_contexts; context; context = context->next)
+ for (context = daemon->dhcp6; context; context = context->next)
if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))