Support for MAX_INITIAL_RTR_ADVERTISEMENTS, MAX_FINAL_RTR_ADVERTISEMENTS,
MinRtrAdvInterval and MaxRtrAdvInterval
Change-Id: Ic853d621dbb5bad8eaafb0dfaf8da090db643740
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 8ed36a3..cf804b7 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -604,6 +604,7 @@
union mysockaddr addr;
int used;
bool is_ra_adv_dis;
+ unsigned int final_ra_sent_count;
struct iname *next;
};
@@ -930,7 +931,7 @@
char *name;
char *mtu_name;
int interval, lifetime, prio, mtu;
- unsigned int reachable_time, retrans_time;
+ unsigned int reachable_time, retrans_time, min_ra_adv_interval, max_ra_adv_interval, ra_sent_count;
unsigned char hop_limit;
struct ra_interface *next;
};
@@ -1663,9 +1664,20 @@
/* radv.c */
#ifdef HAVE_DHCP6
+// All RTR_ADV_INTERVALs in seconds
+#define DEFAULT_RTR_ADV_INTERVAL 600
+#define MAX_RTR_ADV_INTERVAL_UPPER_BOUND 1800
+#define MAX_RTR_ADV_INTERVAL_LOWER_BOUND 4
+#define MIN_RTR_ADV_INTERVAL 3
// MAX_RA_DELAY_TIME in milliseconds
#define MAX_RA_DELAY_TIME 500
#define random_num_in_range(range) (rand() % (range))
+// MAX_INITIAL_RTR_ADVERT_INTERVAL in seconds
+#define MAX_INITIAL_RTR_ADVERT_INTERVAL 16
+// MAX_INITIAL_RTR_ADVERTISEMENTS in number of transmissions
+#define MAX_INITIAL_RTR_ADVERTISEMENTS 3
+// MAX_FINAL_RTR_ADVERTISEMENTS in number of transmissions
+#define MAX_FINAL_RTR_ADVERTISEMENTS 3
void ra_init(time_t now);
void icmp6_packet(time_t now);
time_t periodic_ra(time_t now);
diff --git a/src/option.c b/src/option.c
index da94de8..63a40f3 100644
--- a/src/option.c
+++ b/src/option.c
@@ -528,7 +528,7 @@
{ LOPT_DNSSEC_CHECK, ARG_DUP, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL },
{ LOPT_DNSSEC_TIME, OPT_DNSSEC_TIME, NULL, gettext_noop("Don't check DNSSEC signature timestamps until first cache-reload"), NULL },
{ LOPT_DNSSEC_STAMP, ARG_ONE, "<path>", gettext_noop("Timestamp file to verify system clock for DNSSEC"), NULL },
- { LOPT_RA_PARAM, ARG_DUP, "<iface>,[mtu:<value>|<interface>|off,][<prio>,]<intval>[,<lifetime>][,<reachable_time>][,<hop_limit>][,<retrans_time>]", gettext_noop("Set MTU, priority, resend-interval, router-lifetime, reachable_time, hop_limit and retrans_time"), NULL },
+ { LOPT_RA_PARAM, ARG_DUP, "<iface>,[mtu:<value>|<interface>|off,][<prio>,]<intval>[,<lifetime>][,<reachable_time>][,<hop_limit>][,<retrans_time>][,<min_ra_adv_interval>][,<max_ra_adv_interval>]", gettext_noop("Set MTU, priority, resend-interval, router-lifetime, reachable_time, hop_limit, retrans_time, min_ra_adv_interval and max_ra_adv_interval"), NULL },
{ LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
{ LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL },
{ LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL },
@@ -2466,6 +2466,7 @@
new->name = opt_string_alloc(arg);
new->used = 0;
new->is_ra_adv_dis = false;
+ new->final_ra_sent_count = 0;
arg = comma;
} while (arg);
break;
@@ -2478,6 +2479,7 @@
{
if (strcmp(tmp->name, arg) == 0) {
tmp->is_ra_adv_dis = true;
+ tmp->final_ra_sent_count = 0;
}
}
arg = comma;
@@ -4103,6 +4105,9 @@
new->reachable_time = 0;
new->hop_limit = 0;
new->retrans_time = 0;
+ new->ra_sent_count = 0;
+ new->max_ra_adv_interval = DEFAULT_RTR_ADV_INTERVAL;
+ new->min_ra_adv_interval = new->max_ra_adv_interval/3;
if (strcasestr(comma, "mtu:") == comma)
{
arg = comma + 4;
@@ -4133,8 +4138,14 @@
if (comma && !atoi_check(comma, (int *)&new->reachable_time))
goto err;
comma = split(arg);
- if ((arg && !atoi_check(arg, (int *)&new->hop_limit)) ||
- (comma && (!atoi_check(comma, (int *)&new->retrans_time))))
+ if (arg && (!atoi_check(arg, (int *)&new->hop_limit)))
+ goto err;
+ arg = split(comma);
+ if (comma && !atoi_check(comma, (int *)&new->retrans_time))
+ goto err;
+ comma = split(arg);
+ if ((arg && !atoi_check(arg, (int *)&new->min_ra_adv_interval)) ||
+ (comma && (!atoi_check(comma, (int *)&new->max_ra_adv_interval))))
{
err:
free(new->name);
diff --git a/src/radv.c b/src/radv.c
index c65aca1..fdc674b 100644
--- a/src/radv.c
+++ b/src/radv.c
@@ -265,13 +265,6 @@
#endif
struct iname *if_tmp;
- for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
- {
- if ((strcmp(if_tmp->name, iface_name) == 0) && (if_tmp->is_ra_adv_dis == true)) {
- return;
- }
- }
-
parm.ind = iface;
parm.managed = 0;
parm.other = 0;
@@ -302,6 +295,20 @@
iface_id.next = NULL;
parm.tags = &iface_id;
+ for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
+ {
+ if ((strcmp(if_tmp->name, iface_name) == 0) && (if_tmp->is_ra_adv_dis == true)) {
+ if (if_tmp->final_ra_sent_count < MAX_FINAL_RTR_ADVERTISEMENTS) {
+ ra->lifetime = htons(0);
+ if_tmp->final_ra_sent_count++;
+ break;
+ }
+ else {
+ return;
+ }
+ }
+ }
+
for (context = daemon->dhcp6; context; context = context->next)
{
context->flags &= ~CONTEXT_RA_DONE;
@@ -565,7 +572,7 @@
while (retry_send(sendto(daemon->icmp6fd, daemon->outpacket.iov_base,
save_counter(-1), 0, (struct sockaddr *)&addr,
sizeof(addr))));
-
+ ra_param->ra_sent_count++;
}
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest)
@@ -587,7 +594,12 @@
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
{
if ((strcmp(if_tmp->name, param->if_name) == 0) && (if_tmp->is_ra_adv_dis == true)) {
- return 1;
+ if (if_tmp->final_ra_sent_count < MAX_FINAL_RTR_ADVERTISEMENTS) {
+ break;
+ }
+ else {
+ return 1;
+ }
}
}
@@ -848,7 +860,9 @@
struct iname *if_tmp;
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
{
- if ((strcmp(if_tmp->name, param.name) == 0) && (if_tmp->is_ra_adv_dis == false)) {
+ if ((strcmp(if_tmp->name, param.name) == 0) &&
+ ((if_tmp->is_ra_adv_dis == false) ||
+ (if_tmp->final_ra_sent_count < MAX_FINAL_RTR_ADVERTISEMENTS))) {
send_ra(now, param.iface, param.name, NULL);
/* Also send on all interfaces that are aliases of this
@@ -1005,17 +1019,23 @@
static unsigned int calc_interval(struct ra_interface *ra)
{
- int interval = 600;
+ int interval = DEFAULT_RTR_ADV_INTERVAL;
+ unsigned int min_rtr_interval = ra->min_ra_adv_interval;
+ unsigned int max_rtr_interval = ra->max_ra_adv_interval;
+
+ if (max_rtr_interval > MAX_RTR_ADV_INTERVAL_UPPER_BOUND)
+ max_rtr_interval = MAX_RTR_ADV_INTERVAL_UPPER_BOUND;
+ else if (max_rtr_interval < MAX_RTR_ADV_INTERVAL_LOWER_BOUND)
+ max_rtr_interval = MAX_RTR_ADV_INTERVAL_LOWER_BOUND;
+
+ if (min_rtr_interval < MIN_RTR_ADV_INTERVAL)
+ min_rtr_interval = MIN_RTR_ADV_INTERVAL;
+
+ interval = (rand() % (max_rtr_interval - min_rtr_interval + 1)) + min_rtr_interval;
- if (ra && ra->interval != 0)
- {
- interval = ra->interval;
- if (interval > 1800)
- interval = 1800;
- else if (interval < 4)
- interval = 4;
- }
-
+ if (((ra->ra_sent_count + 1) < MAX_INITIAL_RTR_ADVERTISEMENTS) &&
+ interval > MAX_INITIAL_RTR_ADVERT_INTERVAL)
+ interval = random_num_in_range(MAX_INITIAL_RTR_ADVERT_INTERVAL);
return (unsigned int)interval;
}