Add --ra-param and remove --force-fast-ra
diff --git a/src/radv.c b/src/radv.c
index b1f2bc1..d1147ba 100644
--- a/src/radv.c
+++ b/src/radv.c
@@ -32,11 +32,12 @@
   char *if_name;
   struct dhcp_netid *tags;
   struct in6_addr link_local, link_global;
-  unsigned int pref_time;
+  unsigned int pref_time, adv_interval;
 };
 
 struct search_param {
   time_t now; int iface;
+  char name[IF_NAMESIZE+1];
 };
 
 static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest);
@@ -47,7 +48,11 @@
 			int scope, int if_index, int flags, 
 			int prefered, int valid, void *vparam);
 static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
-static void new_timeout(struct dhcp_context *context, time_t now);
+static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now);
+static unsigned int calc_lifetime(struct ra_interface *ra);
+static unsigned int calc_interval(struct ra_interface *ra);
+static unsigned int calc_prio(struct ra_interface *ra);
+static struct ra_interface *find_iface_param(char *iface);
 
 static int hop_limit;
 
@@ -198,19 +203,20 @@
   struct dhcp_context *context, *tmp,  **up;
   struct dhcp_netid iface_id;
   struct dhcp_opt *opt_cfg;
+  struct ra_interface *ra_param = find_iface_param(iface_name);
   int done_dns = 0;
 #ifdef HAVE_LINUX_NETWORK
   FILE *f;
 #endif
-
+ 
   save_counter(0);
   ra = expand(sizeof(struct ra_packet));
   
   ra->type = ND_ROUTER_ADVERT;
   ra->code = 0;
   ra->hop_limit = hop_limit;
-  ra->flags = 0x00;
-  ra->lifetime = htons(RA_INTERVAL * 3); /* AdvDefaultLifetime * 3 */
+  ra->flags = calc_prio(ra_param);
+  ra->lifetime = htons(calc_lifetime(ra_param));
   ra->reachable_time = 0;
   ra->retrans_time = 0;
 
@@ -222,6 +228,7 @@
   parm.first = 1;
   parm.now = now;
   parm.pref_time = 0;
+  parm.adv_interval = calc_interval(ra_param);
   
   /* set tag with name == interface */
   iface_id.net = iface_name;
@@ -335,7 +342,7 @@
 	  put_opt6_char(ICMP6_OPT_RDNSS);
 	  put_opt6_char((opt_cfg->len/8) + 1);
 	  put_opt6_short(0);
-	  put_opt6_long(RA_INTERVAL * 2); /* lifetime - twice RA retransmit */
+	  put_opt6_long(parm.adv_interval * 2); /* lifetime - twice RA retransmit */
 	  /* zero means "self" */
 	  for (i = 0; i < opt_cfg->len; i += IN6ADDRSZ, a++)
 	    if (IN6_IS_ADDR_UNSPECIFIED(a))
@@ -351,7 +358,7 @@
 	  put_opt6_char(ICMP6_OPT_DNSSL);
 	  put_opt6_char(len + 1);
 	  put_opt6_short(0);
-	  put_opt6_long(RA_INTERVAL * 2); /* lifetime - twice RA retransmit */
+	  put_opt6_long(parm.adv_interval * 2); /* lifetime - twice RA retransmit */
 	  put_opt6(opt_cfg->val, opt_cfg->len);
 	  
 	  /* pad */
@@ -366,7 +373,7 @@
       put_opt6_char(ICMP6_OPT_RDNSS);
       put_opt6_char(3);
       put_opt6_short(0);
-      put_opt6_long(RA_INTERVAL * 2); /* lifetime - twice RA retransmit */
+      put_opt6_long(parm.adv_interval * 2); /* lifetime - twice RA retransmit */
       put_opt6(&parm.link_global, IN6ADDRSZ);
     }
 
@@ -455,8 +462,8 @@
 		if (time > context->lease_time)
 		  {
 		    time = context->lease_time;
-		    if (time < ((unsigned int)(3 * RA_INTERVAL)))
-		      time = 3 * RA_INTERVAL;
+		    if (time < ((unsigned int)(3 * param->adv_interval)))
+		      time = 3 * param->adv_interval;
 		  }
 
 		if (context->flags & CONTEXT_DEPRECATE)
@@ -564,8 +571,7 @@
   struct search_param param;
   struct dhcp_context *context;
   time_t next_event;
-  char interface[IF_NAMESIZE+1];
-  
+    
   param.now = now;
   param.iface = 0;
 
@@ -586,13 +592,15 @@
       if (!context)
 	break;
       
-      if ((context->flags & CONTEXT_OLD) && context->if_index != 0)
+      if ((context->flags & CONTEXT_OLD) && 
+	  context->if_index != 0 && 
+	  indextoname(daemon->icmp6fd, param.iface, param.name))
 	{
 	  /* A context for an old address. We'll not find the interface by 
-	     looking for addresses, but we know it anyway, as long as we
-	     sent at least one RA whilst the address was current. */
+	     looking for addresses, but we know it anyway, since the context is
+	     constructed */
 	  param.iface = context->if_index;
-	  new_timeout(context, now);
+	  new_timeout(context, param.name, now);
 	}
       else if (iface_enumerate(AF_INET6, &param, iface_search))
 	/* There's a context overdue, but we can't find an interface
@@ -603,15 +611,14 @@
 	context->ra_time = 0;
       
       if (param.iface != 0 &&
-	  indextoname(daemon->icmp6fd, param.iface, interface) &&
-	  iface_check(AF_LOCAL, NULL, interface, NULL))
+	  iface_check(AF_LOCAL, NULL, param.name, NULL))
 	{
 	  struct iname *tmp;
 	  for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
-	    if (tmp->name && wildcard_match(tmp->name, interface))
+	    if (tmp->name && wildcard_match(tmp->name, param.name))
 	      break;
 	  if (!tmp)
-	    send_ra(now, param.iface, interface, NULL); 
+	    send_ra(now, param.iface, param.name, NULL); 
 	}
     }      
   return next_event;
@@ -643,7 +650,14 @@
 	if (!(flags & IFACE_TENTATIVE))
 	  param->iface = if_index;
 	
-	new_timeout(context, param->now);
+	/* should never fail */
+	if (!indextoname(daemon->icmp6fd, if_index, param->name))
+	  {
+	    param->iface = 0;
+	    return 0;
+	  }
+	
+	new_timeout(context, param->name, param->now);
 	
 	/* zero timers for other contexts on the same subnet, so they don't timeout 
 	   independently */
@@ -659,14 +673,70 @@
   return 1; /* keep searching */
 }
  
-static void new_timeout(struct dhcp_context *context, time_t now)
+static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now)
 {
-  if (difftime(now, context->ra_short_period_start) < 60.0 || option_bool(OPT_FAST_RA))
+  if (difftime(now, context->ra_short_period_start) < 60.0)
     /* range 5 - 20 */
     context->ra_time = now + 5 + (rand16()/4400);
   else
-    /* range 3/4 - 1 times RA_INTERVAL */
-    context->ra_time = now + (3 * RA_INTERVAL)/4 + ((RA_INTERVAL * (unsigned int)rand16()) >> 18);
+    {
+      /* range 3/4 - 1 times MaxRtrAdvInterval */
+      unsigned int adv_interval = calc_interval(find_iface_param(iface_name));
+      context->ra_time = now + (3 * adv_interval)/4 + ((adv_interval * (unsigned int)rand16()) >> 18);
+    }
+}
+
+static struct ra_interface *find_iface_param(char *iface)
+{
+  struct ra_interface *ra;
+  
+  for (ra = daemon->ra_interfaces; ra; ra = ra->next)
+    if (wildcard_match(ra->name, iface))
+      return ra;
+
+  return NULL;
+}
+
+static unsigned int calc_interval(struct ra_interface *ra)
+{
+  int interval = 600;
+  
+  if (ra && ra->interval != 0)
+    {
+      interval = ra->interval;
+      if (interval > 1800)
+	interval = 1800;
+      else if (interval < 4)
+	interval = 4;
+    }
+  
+  return (unsigned int)interval;
+}
+
+static unsigned int calc_lifetime(struct ra_interface *ra)
+{
+  int lifetime, interval = (int)calc_interval(ra);
+  
+  if (!ra || ra->lifetime == -1) /* not specified */
+    lifetime = 3 * interval;
+  else
+    {
+      lifetime = ra->lifetime;
+      if (lifetime < interval && lifetime != 0)
+	lifetime = interval;
+      else if (lifetime > 9000)
+	lifetime = 9000;
+    }
+  
+  return (unsigned int)lifetime;
+}
+
+static unsigned int calc_prio(struct ra_interface *ra)
+{
+  if (ra)
+    return ra->prio;
+  
+  return 0;
 }
 
 #endif