2005-03-25 Jean-Mickael Guerin <jean-mickael.guerin@6wind.com>
	* interface.c, interface.h, rtadv.c, rtadv.h: extensions to Neighbor
	  discovery for Mobile IPv6.
diff --git a/zebra/ChangeLog b/zebra/ChangeLog
index ac99ff9..bc3c738 100644
--- a/zebra/ChangeLog
+++ b/zebra/ChangeLog
@@ -1,3 +1,13 @@
+2005-03-25 Jean-Mickael Guerin <jean-mickael.guerin@6wind.com>
+	* interface.c, interface.h, rtadv.c, rtadv.h: modifications to 
+	  IPv6 Neighbor Discovery according to RFC3775, section 7:
+	  o 1-bit Home Agent flag management in Router Advertisement (7.1).
+	  o 1-bit Router Address flag management in Prefix Information 
+	    Option (7.2).
+	  o Advertisement Interval Option (7.3)
+	  o Home Agent Information Option (7.4)
+	  o Changes to Sending Router Advertisements more frequently (7.5)
+
 2005-03-13 Hasso Tepper <hasso at quagga.net>
 
 	* zebra/interaface.c: "show interface description" command
diff --git a/zebra/interface.c b/zebra/interface.c
index 6c3e33a..5571754 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -87,11 +87,15 @@
     rtadv->AdvIntervalTimer = 0;
     rtadv->AdvManagedFlag = 0;
     rtadv->AdvOtherConfigFlag = 0;
+    rtadv->AdvHomeAgentFlag = 0;
     rtadv->AdvLinkMTU = 0;
     rtadv->AdvReachableTime = 0;
     rtadv->AdvRetransTimer = 0;
     rtadv->AdvCurHopLimit = 0;
     rtadv->AdvDefaultLifetime = RTADV_ADV_DEFAULT_LIFETIME;
+    rtadv->HomeAgentPreference = 0;
+    rtadv->HomeAgentLifetime = RTADV_ADV_DEFAULT_LIFETIME;
+    rtadv->AdvIntervalOption = 0;
 
     rtadv->AdvPrefixList = list_new ();
   }    
@@ -604,6 +608,7 @@
 {
   struct zebra_if *zif;
   struct rtadvconf *rtadv;
+  int interval;
 
   zif = (struct zebra_if *) ifp->info;
   rtadv = &zif->rtadv;
@@ -614,8 +619,15 @@
 	       rtadv->AdvReachableTime, VTY_NEWLINE);
       vty_out (vty, "  ND advertised retransmit interval is %d milliseconds%s",
 	       rtadv->AdvRetransTimer, VTY_NEWLINE);
-      vty_out (vty, "  ND router advertisements are sent every %d seconds%s",
-	       rtadv->MaxRtrAdvInterval, VTY_NEWLINE);
+      interval = rtadv->MaxRtrAdvInterval;
+      if (interval % 1000)
+        vty_out (vty, "  ND router advertisements are sent every "
+			"%d milliseconds%s", interval,
+		 VTY_NEWLINE);
+      else
+        vty_out (vty, "  ND router advertisements are sent every "
+			"%d seconds%s", interval / 1000,
+		 VTY_NEWLINE);
       vty_out (vty, "  ND router advertisements live for %d seconds%s",
 	       rtadv->AdvDefaultLifetime, VTY_NEWLINE);
       if (rtadv->AdvManagedFlag)
@@ -624,6 +636,13 @@
       else
 	vty_out (vty, "  Hosts use stateless autoconfig for addresses.%s",
 		 VTY_NEWLINE);
+      if (rtadv->AdvHomeAgentFlag)
+      	vty_out (vty, "  ND router advertisements with "
+				"Home Agent flag bit set.%s",
+		 VTY_NEWLINE);
+      if (rtadv->AdvIntervalOption)
+      	vty_out (vty, "  ND router advertisements with Adv. Interval option.%s",
+		 VTY_NEWLINE);
     }
 }
 #endif /* RTADV */
diff --git a/zebra/interface.h b/zebra/interface.h
index 91578ff..0033f7d 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -46,7 +46,7 @@
 #endif
 
 #ifdef RTADV
-/* Router advertisement parameter.  From RFC2461. */
+/* Router advertisement parameter.  From RFC2461 and RFC3775. */
 struct rtadvconf
 {
   /* A flag indicating whether or not the router sends periodic Router
@@ -55,16 +55,18 @@
   int AdvSendAdvertisements;
 
   /* The maximum time allowed between sending unsolicited multicast
-     Router Advertisements from the interface, in seconds.  MUST be no
-     less than 4 seconds and no greater than 1800 seconds. 
+     Router Advertisements from the interface, in milliseconds.
+     MUST be no less than 70 ms (RFC3775, section 7.4) and no greater 
+     than 1800000 ms (See RFC2461).
 
-     Default: 600 seconds */
+     Default: 600000 milliseconds */
   int MaxRtrAdvInterval;
-#define RTADV_MAX_RTR_ADV_INTERVAL 600
+#define RTADV_MAX_RTR_ADV_INTERVAL 600000
 
   /* The minimum time allowed between sending unsolicited multicast
-     Router Advertisements from the interface, in seconds.  MUST be no
-     less than 3 seconds and no greater than .75 * MaxRtrAdvInterval.
+     Router Advertisements from the interface, in milliseconds.
+     MUST be no less than 30 ms (See RFC3775, section 7.4). 
+     MUST be no greater than .75 * MaxRtrAdvInterval.
 
      Default: 0.33 * MaxRtrAdvInterval */
   int MinRtrAdvInterval;
@@ -140,6 +142,35 @@
      advertisement is sent. The link-local prefix SHOULD NOT be
      included in the list of advertised prefixes. */
   struct list *AdvPrefixList;
+
+  /* The TRUE/FALSE value to be placed in the "Home agent"
+     flag field in the Router Advertisement.  See [RFC3775 7.1].
+
+     Default: FALSE */
+  int AdvHomeAgentFlag;
+#ifndef ND_RA_FLAG_HOME_AGENT
+#define ND_RA_FLAG_HOME_AGENT 	0x20
+#endif
+
+  /* The value to be placed in Home Agent Information option if Home 
+     Flag is set.
+     Default: 0 */
+  int HomeAgentPreference;
+
+  /* The value to be placed in Home Agent Information option if Home 
+     Flag is set. Lifetime (seconds) MUST not be greater than 18.2 
+     hours. 
+     The value 0 has special meaning: use of AdvDefaultLifetime value.
+     
+     Default: 0 */
+  int HomeAgentLifetime;
+#define RTADV_MAX_HALIFETIME 65520 /* 18.2 hours */
+
+  /* The TRUE/FALSE value to insert or not an Advertisement Interval
+     option. See [RFC 3775 7.3]
+
+     Default: FALSE */
+  int AdvIntervalOption;
 };
 
 #endif /* RTADV */
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index 1238396..7259656 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -1,4 +1,5 @@
 /* Router advertisement
+ * Copyright (C) 2005 6WIND <jean-mickael.guerin@6wind.com>
  * Copyright (C) 1999 Kunihiro Ishiguro
  *
  * This file is part of GNU Zebra.
@@ -58,7 +59,8 @@
 
 extern struct zebra_t zebrad;
 
-enum rtadv_event {RTADV_START, RTADV_STOP, RTADV_TIMER, RTADV_READ};
+enum rtadv_event {RTADV_START, RTADV_STOP, RTADV_TIMER, 
+		  RTADV_TIMER_MSEC, RTADV_READ};
 
 void rtadv_event (enum rtadv_event, int);
 
@@ -71,6 +73,7 @@
   int sock;
 
   int adv_if_count;
+  int adv_msec_if_count;
 
   struct thread *ra_read;
   struct thread *ra_timer;
@@ -210,12 +213,37 @@
     rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
   if (zif->rtadv.AdvOtherConfigFlag)
     rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
+  if (zif->rtadv.AdvHomeAgentFlag)
+    rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_HOME_AGENT;
   rtadv->nd_ra_router_lifetime = htons (zif->rtadv.AdvDefaultLifetime);
   rtadv->nd_ra_reachable = htonl (zif->rtadv.AdvReachableTime);
   rtadv->nd_ra_retransmit = htonl (0);
 
   len = sizeof (struct nd_router_advert);
 
+  if (zif->rtadv.AdvHomeAgentFlag)
+    {
+      struct nd_opt_homeagent_info *ndopt_hai = 
+	(struct nd_opt_homeagent_info *)(buf + len);
+      ndopt_hai->nd_opt_hai_type = ND_OPT_HA_INFORMATION;
+      ndopt_hai->nd_opt_hai_len = 1;
+      ndopt_hai->nd_opt_hai_reserved = 0;
+      ndopt_hai->nd_opt_hai_preference = htons(zif->rtadv.HomeAgentPreference);
+      ndopt_hai->nd_opt_hai_lifetime = htons(zif->rtadv.HomeAgentLifetime);
+      len += sizeof(struct nd_opt_homeagent_info);
+    }
+
+  if (zif->rtadv.AdvIntervalOption)
+    {
+      struct nd_opt_adv_interval *ndopt_adv = 
+	(struct nd_opt_adv_interval *)(buf + len);
+      ndopt_adv->nd_opt_ai_type = ND_OPT_ADV_INTERVAL;
+      ndopt_adv->nd_opt_ai_len = 1;
+      ndopt_adv->nd_opt_ai_reserved = 0;
+      ndopt_adv->nd_opt_ai_interval = htonl(zif->rtadv.MaxRtrAdvInterval);
+      len += sizeof(struct nd_opt_adv_interval);
+    }
+
   /* Fill in prefix. */
   for (node = listhead (zif->rtadv.AdvPrefixList); node; node = nextnode (node))
     {
@@ -235,6 +263,8 @@
 	pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK;
       if (rprefix->AdvAutonomousFlag)
 	pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
+      if (rprefix->AdvRouterAddressFlag)
+	pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_RADDR;
 
       pinfo->nd_opt_pi_valid_time = htonl (rprefix->AdvValidLifetime);
       pinfo->nd_opt_pi_preferred_time = htonl (rprefix->AdvPreferredLifetime);
@@ -311,9 +341,19 @@
   struct listnode *node;
   struct interface *ifp;
   struct zebra_if *zif;
+  int period;
 
   rtadv->ra_timer = NULL;
-  rtadv_event (RTADV_TIMER, 1);
+  if (rtadv->adv_msec_if_count == 0)
+    {
+      period = 1000; /* 1 s */
+      rtadv_event (RTADV_TIMER, 1 /* 1 s */);
+    } 
+  else
+    {
+      period = 10; /* 10 ms */
+      rtadv_event (RTADV_TIMER_MSEC, 10 /* 10 ms */);
+    }
 
   for (node = listhead (iflist); node; nextnode (node))
     {
@@ -325,11 +365,14 @@
       zif = ifp->info;
 
       if (zif->rtadv.AdvSendAdvertisements)
-	if (--zif->rtadv.AdvIntervalTimer <= 0)
-	  {
-	    zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
-	    rtadv_send_packet (rtadv->sock, ifp);
-	  }
+	{ 
+	  zif->rtadv.AdvIntervalTimer -= period;
+	  if (zif->rtadv.AdvIntervalTimer <= 0)
+	    {
+	      zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
+	      rtadv_send_packet (rtadv->sock, ifp);
+	    }
+	}
     }
   return 0;
 }
@@ -547,6 +590,7 @@
   rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime;
   rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag;
   rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag;
+  rprefix->AdvRouterAddressFlag = rp->AdvRouterAddressFlag;
 }
 
 int
@@ -634,6 +678,42 @@
   return CMD_SUCCESS;
 }
 
+DEFUN (ipv6_nd_ra_interval_msec,
+       ipv6_nd_ra_interval_msec_cmd,
+       "ipv6 nd ra-interval msec MILLISECONDS",
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Router Advertisement interval\n"
+       "Router Advertisement interval in milliseconds\n")
+{
+  int interval;
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  interval = atoi (argv[0]);
+
+  if (interval <= 0)
+    {
+      vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (zif->rtadv.MaxRtrAdvInterval % 1000)
+    rtadv->adv_msec_if_count--;
+
+  if (interval % 1000)
+    rtadv->adv_msec_if_count++;
+  
+  zif->rtadv.MaxRtrAdvInterval = interval;
+  zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
+  zif->rtadv.AdvIntervalTimer = 0;
+
+  return CMD_SUCCESS;
+}
+
 DEFUN (ipv6_nd_ra_interval,
        ipv6_nd_ra_interval_cmd,
        "ipv6 nd ra-interval SECONDS",
@@ -651,12 +731,18 @@
 
   interval = atoi (argv[0]);
 
-  if (interval < 0)
+  if (interval <= 0)
     {
       vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE);
       return CMD_WARNING;
     }
 
+  if (zif->rtadv.MaxRtrAdvInterval % 1000)
+    rtadv->adv_msec_if_count--;
+	
+  /* convert to milliseconds */
+  interval = interval * 1000; 
+	
   zif->rtadv.MaxRtrAdvInterval = interval;
   zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
   zif->rtadv.AdvIntervalTimer = 0;
@@ -678,6 +764,9 @@
   ifp = (struct interface *) vty->index;
   zif = ifp->info;
 
+  if (zif->rtadv.MaxRtrAdvInterval % 1000)
+    rtadv->adv_msec_if_count--;
+  
   zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
   zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
   zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
@@ -779,6 +868,100 @@
   return CMD_SUCCESS;
 }
 
+DEFUN (ipv6_nd_homeagent_preference,
+       ipv6_nd_homeagent_preference_cmd,
+       "ipv6 nd home-agent-preference PREFERENCE",
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Home Agent preference\n"
+       "Home Agent preference value 0..65535\n")
+{
+  u_int32_t hapref;
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  hapref = (u_int32_t) atol (argv[0]);
+
+  if (hapref > 65535)
+    {
+      vty_out (vty, "Invalid Home Agent preference%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  zif->rtadv.HomeAgentPreference = hapref;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_nd_homeagent_preference,
+       no_ipv6_nd_homeagent_preference_cmd,
+       "no ipv6 nd home-agent-preference",
+       NO_STR
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Home Agent preference\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.HomeAgentPreference = 0;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_nd_homeagent_lifetime,
+       ipv6_nd_homeagent_lifetime_cmd,
+       "ipv6 nd home-agent-lifetime SECONDS",
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Home Agent lifetime\n"
+       "Home Agent lifetime in seconds\n")
+{
+  u_int32_t ha_ltime;
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  ha_ltime = (u_int32_t) atol (argv[0]);
+
+  if (ha_ltime > RTADV_MAX_HALIFETIME)
+    {
+      vty_out (vty, "Invalid Home Agent Lifetime time%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  zif->rtadv.HomeAgentLifetime = ha_ltime;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_nd_homeagent_lifetime,
+       no_ipv6_nd_homeagent_lifetime_cmd,
+       "no ipv6 nd home-agent-lifetime",
+       NO_STR
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Home Agent lifetime\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.HomeAgentLifetime = 0;
+
+  return CMD_SUCCESS;
+}
+
 DEFUN (ipv6_nd_managed_config_flag,
        ipv6_nd_managed_config_flag_cmd,
        "ipv6 nd managed-config-flag",
@@ -816,6 +999,80 @@
   return CMD_SUCCESS;
 }
 
+DEFUN (ipv6_nd_homeagent_config_flag,
+       ipv6_nd_homeagent_config_flag_cmd,
+       "ipv6 nd home-agent-config-flag",
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Home Agent configuration flag\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.AdvHomeAgentFlag = 1;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_nd_homeagent_config_flag,
+       no_ipv6_nd_homeagent_config_flag_cmd,
+       "no ipv6 nd home-agent-config-flag",
+       NO_STR
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Home Agent configuration flag\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.AdvHomeAgentFlag = 0;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_nd_adv_interval_config_option,
+       ipv6_nd_adv_interval_config_option_cmd,
+       "ipv6 nd adv-interval-option",
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Advertisement Interval Option\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.AdvIntervalOption = 1;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_nd_adv_interval_config_option,
+       no_ipv6_nd_adv_interval_config_option_cmd,
+       "no ipv6 nd adv-interval-option",
+       NO_STR
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Advertisement Interval Option\n")
+{
+  struct interface *ifp;
+  struct zebra_if *zif;
+
+  ifp = (struct interface *) vty->index;
+  zif = ifp->info;
+
+  zif->rtadv.AdvIntervalOption = 0;
+
+  return CMD_SUCCESS;
+}
+
 DEFUN (ipv6_nd_other_config_flag,
        ipv6_nd_other_config_flag_cmd,
        "ipv6 nd other-config-flag",
@@ -856,7 +1113,7 @@
 DEFUN (ipv6_nd_prefix,
        ipv6_nd_prefix_cmd,
        "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
-       "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|)",
+       "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|) (router-address|)",
        "Interface IPv6 config commands\n"
        "Neighbor discovery\n"
        "Prefix information\n"
@@ -866,7 +1123,8 @@
        "Preferred lifetime in seconds\n"
        "Infinite preferred lifetime\n"
        "Do not use prefix for onlink determination\n"
-       "Do not use prefix for autoconfiguration\n")
+       "Do not use prefix for autoconfiguration\n"
+       "Set Router Address flag\n")
 {
   int i;
   int ret;
@@ -886,6 +1144,7 @@
     }
   rp.AdvOnLinkFlag = 1;
   rp.AdvAutonomousFlag = 1;
+  rp.AdvRouterAddressFlag = 0;
   rp.AdvValidLifetime = RTADV_VALID_LIFETIME;
   rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
 
@@ -920,6 +1179,8 @@
 		rp.AdvOnLinkFlag = 0;
 	      if (strncmp (argv[i], "no", 2) == 0)
 		rp.AdvAutonomousFlag = 0;
+	      if (strncmp (argv[i], "ro", 2) == 0)
+		rp.AdvRouterAddressFlag = 1;
 	    }
 	}
     }
@@ -930,6 +1191,21 @@
 }
 
 ALIAS (ipv6_nd_prefix,
+       ipv6_nd_prefix_val_nortaddr_cmd,
+       "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
+       "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|)",
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Prefix information\n"
+       "IPv6 prefix\n"
+       "Valid lifetime in seconds\n"
+       "Infinite valid lifetime\n"
+       "Preferred lifetime in seconds\n"
+       "Infinite preferred lifetime\n"
+       "Do not use prefix for onlink determination\n"
+       "Do not use prefix for autoconfiguration\n")
+
+ALIAS (ipv6_nd_prefix,
        ipv6_nd_prefix_val_rev_cmd,
        "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
        "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|)",
@@ -945,6 +1221,22 @@
        "Do not use prefix for onlink determination\n")
 
 ALIAS (ipv6_nd_prefix,
+       ipv6_nd_prefix_val_rev_rtaddr_cmd,
+       "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
+       "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|) (router-address|)",
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Prefix information\n"
+       "IPv6 prefix\n"
+       "Valid lifetime in seconds\n"
+       "Infinite valid lifetime\n"
+       "Preferred lifetime in seconds\n"
+       "Infinite preferred lifetime\n"
+       "Do not use prefix for autoconfiguration\n"
+       "Do not use prefix for onlink determination\n"
+       "Set Router Address flag\n")
+
+ALIAS (ipv6_nd_prefix,
        ipv6_nd_prefix_val_noauto_cmd,
        "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
        "(<0-4294967295>|infinite) (no-autoconfig|)",
@@ -956,7 +1248,7 @@
        "Infinite valid lifetime\n"
        "Preferred lifetime in seconds\n"
        "Infinite preferred lifetime\n"
-       "Do not use prefix for autoconfigurationn")
+       "Do not use prefix for autoconfiguration")
 
 ALIAS (ipv6_nd_prefix,
        ipv6_nd_prefix_val_offlink_cmd,
@@ -973,6 +1265,20 @@
        "Do not use prefix for onlink determination\n")
 
 ALIAS (ipv6_nd_prefix,
+       ipv6_nd_prefix_val_rtaddr_cmd,
+       "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
+       "(<0-4294967295>|infinite) (router-address|)",
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Prefix information\n"
+       "IPv6 prefix\n"
+       "Valid lifetime in seconds\n"
+       "Infinite valid lifetime\n"
+       "Preferred lifetime in seconds\n"
+       "Infinite preferred lifetime\n"
+       "Set Router Address flag\n")
+
+ALIAS (ipv6_nd_prefix,
        ipv6_nd_prefix_val_cmd,
        "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
        "(<0-4294967295>|infinite)",
@@ -1024,6 +1330,15 @@
        "Do not use prefix for onlink determination\n")
 
 ALIAS (ipv6_nd_prefix,
+       ipv6_nd_prefix_noval_rtaddr_cmd,
+       "ipv6 nd prefix X:X::X:X/M (router-address|)",
+       "Interface IPv6 config commands\n"
+       "Neighbor discovery\n"
+       "Prefix information\n"
+       "IPv6 prefix\n"
+       "Set Router Address flag\n")
+
+ALIAS (ipv6_nd_prefix,
        ipv6_nd_prefix_prefix_cmd,
        "ipv6 nd prefix X:X::X:X/M",
        "Interface IPv6 config commands\n"
@@ -1064,7 +1379,6 @@
 
   return CMD_SUCCESS;
 }
-
 /* Write configuration about router advertisement. */
 void
 rtadv_config_write (struct vty *vty, struct interface *ifp)
@@ -1073,6 +1387,7 @@
   struct listnode *node;
   struct rtadv_prefix *rprefix;
   u_char buf[INET6_ADDRSTRLEN];
+  int interval;
 
   if (! rtadv)
     return;
@@ -1087,8 +1402,14 @@
 	vty_out (vty, " ipv6 nd suppress-ra%s", VTY_NEWLINE);
     }
 
-  if (zif->rtadv.MaxRtrAdvInterval != RTADV_MAX_RTR_ADV_INTERVAL)
-    vty_out (vty, " ipv6 nd ra-interval %d%s", zif->rtadv.MaxRtrAdvInterval,
+  
+  interval = zif->rtadv.MaxRtrAdvInterval;
+  if (interval % 1000)
+    vty_out (vty, " ipv6 nd ra-interval msec %d%s", interval,
+	     VTY_NEWLINE);
+  else
+    if (interval != RTADV_MAX_RTR_ADV_INTERVAL)
+      vty_out (vty, " ipv6 nd ra-interval %d%s", interval / 1000,
 	     VTY_NEWLINE);
 
   if (zif->rtadv.AdvDefaultLifetime != RTADV_ADV_DEFAULT_LIFETIME)
@@ -1128,6 +1449,8 @@
 	vty_out (vty, " off-link");
       if (!rprefix->AdvAutonomousFlag)
 	vty_out (vty, " no-autoconfig");
+      if (rprefix->AdvRouterAddressFlag)
+	vty_out (vty, " router-address");
       vty_out (vty, "%s", VTY_NEWLINE);
     }
 }
@@ -1162,6 +1485,11 @@
 	rtadv->ra_timer = thread_add_timer (zebrad.master, rtadv_timer, NULL,
 	                                    val);
       break;
+    case RTADV_TIMER_MSEC:
+      if (! rtadv->ra_timer)
+	rtadv->ra_timer = thread_add_timer_msec (zebrad.master, rtadv_timer, 
+					    NULL, val);
+      break;
     case RTADV_READ:
       if (! rtadv->ra_read)
 	rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val);
@@ -1187,6 +1515,7 @@
   install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
   install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd);
   install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd);
   install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd);
@@ -1196,15 +1525,27 @@
   install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd);
   install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_homeagent_config_flag_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_adv_interval_config_option_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_nd_adv_interval_config_option_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_prefix_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_rtaddr_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_nortaddr_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_noauto_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_offlink_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rtaddr_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rev_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_noauto_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_offlink_cmd);
+  install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rtaddr_cmd);
   install_element (INTERFACE_NODE, &ipv6_nd_prefix_prefix_cmd);
   install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_cmd);
 }
diff --git a/zebra/rtadv.h b/zebra/rtadv.h
index 859b2d7..d52c2c0 100644
--- a/zebra/rtadv.h
+++ b/zebra/rtadv.h
@@ -1,4 +1,5 @@
 /* Router advertisement
+ * Copyright (C) 2005 6WIND <jean-mickael.guerin@6wind.com>
  * Copyright (C) 1999 Kunihiro Ishiguro
  *
  * This file is part of GNU Zebra.
@@ -42,8 +43,51 @@
 
   /* The value to be placed in the Autonomous Flag. */
   int AdvAutonomousFlag;
+
+  /* The value to be placed in the Router Address Flag (RFC3775 7.2). */
+  int AdvRouterAddressFlag;
+#ifndef ND_OPT_PI_FLAG_RADDR
+#define ND_OPT_PI_FLAG_RADDR         0x20
+#endif
+
 };
 
 void rtadv_config_write (struct vty *, struct interface *);
 
+/* draft-ietf-mip6-mipext-advapi-03 */
+
+#ifndef ND_OPT_ADV_INTERVAL
+#define ND_OPT_ADV_INTERVAL	7   /* Adv Interval Option */
+#endif
+#ifndef ND_OPT_HA_INFORMATION
+#define ND_OPT_HA_INFORMATION	8   /* HA Information Option */
+#endif
+
+#ifndef HAVE_ND_OPT_ADV_INTERVAL
+struct nd_opt_adv_interval {   /* Advertisement interval option */
+        uint8_t        nd_opt_ai_type;
+        uint8_t        nd_opt_ai_len;
+        uint16_t       nd_opt_ai_reserved;
+        uint32_t       nd_opt_ai_interval;
+} __attribute__((__packed__));
+#else
+#ifndef HAVE_ND_OPT_ADV_INTERVAL_AI_FIELDS
+/* fields may have to be renamed */
+#define nd_opt_ai_type		nd_opt_adv_interval_type
+#define nd_opt_ai_len		nd_opt_adv_interval_len
+#define nd_opt_ai_reserved	nd_opt_adv_interval_reserved
+#define nd_opt_ai_interval	nd_opt_adv_interval_ival
+#endif
+#endif
+
+#ifndef HAVE_ND_OPT_HOMEAGENT_INFO
+struct nd_opt_homeagent_info {  /* Home Agent info */
+        u_int8_t        nd_opt_hai_type;
+        u_int8_t        nd_opt_hai_len;
+        u_int16_t       nd_opt_hai_reserved;
+        u_int16_t       nd_opt_hai_preference;
+        u_int16_t       nd_opt_hai_lifetime;
+} __attribute__((__packed__));
+#endif
+
 #endif /* _ZEBRA_RTADV_H */