diff -x CVS -urN ospf6d.old/ChangeLog ospf6d/ChangeLog
--- ospf6d.old/ChangeLog	Sat Apr 26 23:17:47 2003
+++ ospf6d/ChangeLog	Fri Apr 25 11:40:31 2003
@@ -1,3 +1,36 @@
+2003-04-25  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_asbr.c: AS-External LSA refresh was based on the
+	prefix of the obsolete LSA. It was wrong so fixed.
+	* version: 0.9.6p
+
+2002-11-09  Vincent Jardin  <jardin@6wind.com>
+
+	* ospf6_interface.c: update link-local address on interface creation.
+
+2002-11-09  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_asbr.c: apply MinLSInterval to AS-External-LSA origination.
+	* ospf6_lsa.c: change not to issue flooding caused by expire event
+	when the received LSA is (already) MaxAge.
+	* ospf6_spf.c: fix a bug which is that ospf6d calculates
+	wrong nexthop when failed to find Link-LSA for the neighbor.
+	* ospf6_damp.c ospf6_dbex.c ospf6_neighbor.c ospf6_spf.c:
+	some clean up
+	* version: 0.9.6o
+
+2002-10-04  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_asbr.c: bug of failing ASE lsa refresh fixed.
+	* version: 0.9.6n
+
+2002-10-01  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_asbr.c: AS-External-LSA origination function
+	is re-written.
+	* ospf6_damp.[ch]: New feature that damps flaps is added.
+	* version: 0.9.6m
+
 2002-07-14  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
 
 	* ospf6_spf.c: unwanted assert() in ospf6_spf_nexthop_calculation()
diff -x CVS -urN ospf6d.old/Makefile.in ospf6d/Makefile.in
--- ospf6d.old/Makefile.in	Sat Apr 26 23:17:47 2003
+++ ospf6d/Makefile.in	Thu Feb 20 01:31:12 2003
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.6.2 from Makefile.am.
+# Makefile.in generated by automake 1.6.3 from Makefile.am.
 # @configure_input@
 
 # Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
@@ -111,9 +111,9 @@
 	ospf6_neighbor.c ospf6_message.c ospf6_lsa.c ospf6_spf.c \
 	ospf6_route.c ospf6_zebra.c ospf6_ism.c ospf6_dbex.c \
 	ospf6_lsdb.c ospf6_prefix.c ospf6_top.c ospf6_area.c ospf6_nsm.c \
-	ospf6_redistribute.c ospf6_routemap.c ospf6_proto.c \
+	ospf6_routemap.c ospf6_proto.c \
 	ospf6_hook.c ospf6_asbr.c ospf6_bintree.c ospf6_linklist.c \
-	ospf6_abr.c ospf6_intra.c
+	ospf6_abr.c ospf6_intra.c ospf6_damp.c
 
 
 noinst_HEADERS = \
@@ -121,9 +121,9 @@
 	ospf6_message.h ospf6_neighbor.h ospf6_network.h ospf6_proto.h \
 	ospf6_spf.h ospf6_route.h ospf6_types.h ospf6_zebra.h ospf6d.h \
 	ospf6_ism.h ospf6_dbex.h ospf6_lsdb.h ospf6_prefix.h \
-	ospf6_top.h ospf6_nsm.h ospf6_redistribute.h ospf6_routemap.h \
+	ospf6_top.h ospf6_nsm.h ospf6_routemap.h \
         ospf6_hook.h ospf6_asbr.h ospf6_bintree.h ospf6_linklist.h \
-	ospf6_abr.h ospf6_intra.h
+	ospf6_abr.h ospf6_intra.h ospf6_damp.h
 
 
 ospf6d_SOURCES = \
@@ -150,10 +150,10 @@
 	ospf6_zebra.$(OBJEXT) ospf6_ism.$(OBJEXT) ospf6_dbex.$(OBJEXT) \
 	ospf6_lsdb.$(OBJEXT) ospf6_prefix.$(OBJEXT) ospf6_top.$(OBJEXT) \
 	ospf6_area.$(OBJEXT) ospf6_nsm.$(OBJEXT) \
-	ospf6_redistribute.$(OBJEXT) ospf6_routemap.$(OBJEXT) \
-	ospf6_proto.$(OBJEXT) ospf6_hook.$(OBJEXT) ospf6_asbr.$(OBJEXT) \
+	ospf6_routemap.$(OBJEXT) ospf6_proto.$(OBJEXT) \
+	ospf6_hook.$(OBJEXT) ospf6_asbr.$(OBJEXT) \
 	ospf6_bintree.$(OBJEXT) ospf6_linklist.$(OBJEXT) \
-	ospf6_abr.$(OBJEXT) ospf6_intra.$(OBJEXT)
+	ospf6_abr.$(OBJEXT) ospf6_intra.$(OBJEXT) ospf6_damp.$(OBJEXT)
 libospf6_a_OBJECTS = $(am_libospf6_a_OBJECTS)
 sbin_PROGRAMS = ospf6d$(EXEEXT)
 PROGRAMS = $(sbin_PROGRAMS)
@@ -165,10 +165,10 @@
 	ospf6_zebra.$(OBJEXT) ospf6_ism.$(OBJEXT) ospf6_dbex.$(OBJEXT) \
 	ospf6_lsdb.$(OBJEXT) ospf6_prefix.$(OBJEXT) ospf6_top.$(OBJEXT) \
 	ospf6_area.$(OBJEXT) ospf6_nsm.$(OBJEXT) \
-	ospf6_redistribute.$(OBJEXT) ospf6_routemap.$(OBJEXT) \
-	ospf6_proto.$(OBJEXT) ospf6_hook.$(OBJEXT) ospf6_asbr.$(OBJEXT) \
+	ospf6_routemap.$(OBJEXT) ospf6_proto.$(OBJEXT) \
+	ospf6_hook.$(OBJEXT) ospf6_asbr.$(OBJEXT) \
 	ospf6_bintree.$(OBJEXT) ospf6_linklist.$(OBJEXT) \
-	ospf6_abr.$(OBJEXT) ospf6_intra.$(OBJEXT)
+	ospf6_abr.$(OBJEXT) ospf6_intra.$(OBJEXT) ospf6_damp.$(OBJEXT)
 am_ospf6d_OBJECTS = ospf6_main.$(OBJEXT) $(am__objects_1)
 ospf6d_OBJECTS = $(am_ospf6d_OBJECTS)
 ospf6d_DEPENDENCIES = ../lib/libzebra.a
@@ -182,8 +182,8 @@
 @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/ospf6_abr.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/ospf6_area.Po ./$(DEPDIR)/ospf6_asbr.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/ospf6_bintree.Po \
-@AMDEP_TRUE@	./$(DEPDIR)/ospf6_dbex.Po ./$(DEPDIR)/ospf6_dump.Po \
-@AMDEP_TRUE@	./$(DEPDIR)/ospf6_hook.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_damp.Po ./$(DEPDIR)/ospf6_dbex.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_dump.Po ./$(DEPDIR)/ospf6_hook.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/ospf6_interface.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/ospf6_intra.Po ./$(DEPDIR)/ospf6_ism.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/ospf6_linklist.Po \
@@ -195,7 +195,6 @@
 @AMDEP_TRUE@	./$(DEPDIR)/ospf6_nsm.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/ospf6_prefix.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/ospf6_proto.Po \
-@AMDEP_TRUE@	./$(DEPDIR)/ospf6_redistribute.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/ospf6_route.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/ospf6_routemap.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/ospf6_spf.Po ./$(DEPDIR)/ospf6_top.Po \
@@ -218,7 +217,7 @@
 
 .SUFFIXES:
 .SUFFIXES: .c .o .obj
-$(srcdir)/Makefile.in:  Makefile.am  $(top_srcdir)/configure.in $(ACLOCAL_M4)
+$(srcdir)/Makefile.in:  Makefile.am  $(top_srcdir)/configure.in $(ACLOCAL_M4)
 	cd $(top_srcdir) && \
 	  $(AUTOMAKE) --foreign  ospf6d/Makefile
 Makefile:  $(srcdir)/Makefile.in  $(top_builddir)/config.status
@@ -238,8 +237,7 @@
 	  p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
 	  if test -f $$p \
 	  ; then \
-	    p1=`echo "$$p1" | sed -e 's,^.*/,,'`; \
-	    f=`echo $$p1|sed '$(transform);s/$$/$(EXEEXT)/'`; \
+	    f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
 	   echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \
 	   $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f; \
 	  else :; fi; \
@@ -248,8 +246,7 @@
 uninstall-sbinPROGRAMS:
 	@$(NORMAL_UNINSTALL)
 	@list='$(sbin_PROGRAMS)'; for p in $$list; do \
-	  f=`echo $$p|sed 's/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
-	  f=`echo "$$f" | sed -e 's,^.*/,,'`; \
+	  f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
 	  echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \
 	  rm -f $(DESTDIR)$(sbindir)/$$f; \
 	done
@@ -270,6 +267,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_area.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_asbr.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_bintree.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_damp.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_dbex.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_dump.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_hook.Po@am__quote@
@@ -286,7 +284,6 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_nsm.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_prefix.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_proto.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_redistribute.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_route.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_routemap.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_spf.Po@am__quote@
diff -x CVS -urN ospf6d.old/ospf6_abr.c ospf6d/ospf6_abr.c
--- ospf6d.old/ospf6_abr.c	Sat Apr 26 23:17:47 2003
+++ ospf6d/ospf6_abr.c	Tue Oct  1 10:28:07 2002
@@ -42,7 +42,7 @@
 
   inet_ntop (AF_INET, &router_id, router_string, sizeof (router_string));
 
-  zlog_info ("ABR:   Finding router %s in area %s", router_string, area->str);
+  //zlog_info ("ABR:   Finding router %s in area %s", router_string, area->str);
 
   memset (&abr_id, 0, sizeof (abr_id));
   abr_id.family = AF_UNSPEC;
diff -x CVS -urN ospf6d.old/ospf6_area.h ospf6d/ospf6_area.h
--- ospf6d.old/ospf6_area.h	Sat Apr 26 23:17:47 2003
+++ ospf6d/ospf6_area.h	Sat Nov  9 11:25:30 2002
@@ -62,6 +62,8 @@
                        void (*func) (void *, int, void *));
 
   struct thread *maxage_remover;
+
+  struct thread *thread_router_lsa;
 };
 
 
diff -x CVS -urN ospf6d.old/ospf6_asbr.c ospf6d/ospf6_asbr.c
--- ospf6d.old/ospf6_asbr.c	Sat Apr 26 23:17:47 2003
+++ ospf6d/ospf6_asbr.c	Fri Apr 25 11:40:31 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001 Yasuhiro Ohara
+ * Copyright (C) 2001-2002 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -19,108 +19,641 @@
  * Boston, MA 02111-1307, USA.  
  */
 
-#include "ospf6d.h"
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "prefix.h"
+#include "command.h"
+#include "vty.h"
+#include "routemap.h"
+#include "table.h"
+#include "plist.h"
+#include "thread.h"
+
+#include "ospf6_prefix.h"  /* xxx for ospf6_asbr.h */
+#include "ospf6_lsa.h"     /* xxx for ospf6_asbr.h */
+#include "ospf6_route.h"   /* xxx for ospf6_asbr.h, ospf6_zebra.h */
+#include "ospf6_zebra.h"
+#include "ospf6_asbr.h"
+#include "ospf6_damp.h"
+#include "ospf6_top.h"
+#include "ospf6_lsdb.h"
+#include "ospf6_proto.h"
+
+extern struct thread_master *master;
+
+struct route_table *external_table;
+struct
+{
+  char *name;
+  struct route_map *map;
+} rmap [ZEBRA_ROUTE_MAX];
+
+static u_int32_t link_state_id = 0;
+
+char *
+zroute_name[] =
+{ 
+  "system", "kernel", "connected", "static",
+  "rip", "ripng", "ospf", "ospf6", "bgp", "unknown"
+};
+char *
+zroute_abname[] =
+{
+  "X", "K", "C", "S", "R", "R", "O", "O", "B", "?"
+};
+
+#define ZROUTE_NAME(x) \
+  (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \
+   zroute_name[(x)] : zroute_name[ZEBRA_ROUTE_MAX])
+
+#define ZROUTE_ABNAME(x) \
+  (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \
+   zroute_abname[(x)] : zroute_abname[ZEBRA_ROUTE_MAX])
+
+/* redistribute function */
+void
+ospf6_asbr_routemap_set (int type, char *mapname)
+{
+  if (rmap[type].name)
+    free (rmap[type].name);
+
+  rmap[type].name = strdup (mapname);
+  rmap[type].map = route_map_lookup_by_name (mapname);
+}
+
+void
+ospf6_asbr_routemap_unset (int type)
+{
+  if (rmap[type].name)
+    free (rmap[type].name);
+  rmap[type].name = NULL;
+  rmap[type].map = NULL;
+}
+
+void
+ospf6_asbr_routemap_update ()
+{
+  int i;
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    {
+      if (rmap[i].name)
+        rmap[i].map = route_map_lookup_by_name (rmap[i].name);
+      else
+        rmap[i].map = NULL;
+    }
+}
+
+DEFUN (ospf6_redistribute,
+       ospf6_redistribute_cmd,
+       "redistribute (static|kernel|connected|ripng|bgp)",
+       "Redistribute\n"
+       "Static route\n"
+       "Kernel route\n"
+       "Connected route\n"
+       "RIPng route\n"
+       "BGP route\n"
+      )
+{
+  int type = 0;
+
+  if (strncmp (argv[0], "sta", 3) == 0)
+    type = ZEBRA_ROUTE_STATIC;
+  else if (strncmp (argv[0], "ker", 3) == 0)
+    type = ZEBRA_ROUTE_KERNEL;
+  else if (strncmp (argv[0], "con", 3) == 0)
+    type = ZEBRA_ROUTE_CONNECT;
+  else if (strncmp (argv[0], "rip", 3) == 0)
+    type = ZEBRA_ROUTE_RIPNG;
+  else if (strncmp (argv[0], "bgp", 3) == 0)
+    type = ZEBRA_ROUTE_BGP;
+
+  ospf6_zebra_no_redistribute (type);
+  ospf6_asbr_routemap_unset (type);
+  ospf6_zebra_redistribute (type);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_redistribute_routemap,
+       ospf6_redistribute_routemap_cmd,
+       "redistribute (static|kernel|connected|ripng|bgp) route-map WORD",
+       "Redistribute\n"
+       "Static routes\n"
+       "Kernel route\n"
+       "Connected route\n"
+       "RIPng route\n"
+       "BGP route\n"
+       "Route map reference\n"
+       "Route map name\n"
+      )
+{
+  int type = 0;
+
+  if (strncmp (argv[0], "sta", 3) == 0)
+    type = ZEBRA_ROUTE_STATIC;
+  else if (strncmp (argv[0], "ker", 3) == 0)
+    type = ZEBRA_ROUTE_KERNEL;
+  else if (strncmp (argv[0], "con", 3) == 0)
+    type = ZEBRA_ROUTE_CONNECT;
+  else if (strncmp (argv[0], "rip", 3) == 0)
+    type = ZEBRA_ROUTE_RIPNG;
+  else if (strncmp (argv[0], "bgp", 3) == 0)
+    type = ZEBRA_ROUTE_BGP;
+
+  ospf6_zebra_no_redistribute (type);
+  ospf6_asbr_routemap_set (type, argv[1]);
+  ospf6_zebra_redistribute (type);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf6_redistribute,
+       no_ospf6_redistribute_cmd,
+       "no redistribute (static|kernel|connected|ripng|bgp)",
+       NO_STR
+       "Redistribute\n"
+       "Static route\n"
+       "Kernel route\n"
+       "Connected route\n"
+       "RIPng route\n"
+       "BGP route\n"
+      )
+{
+  int type = 0;
+  struct route_node *node;
+  struct ospf6_external_route *route;
+  struct ospf6_external_info *info, *info_next = NULL;
+
+  if (strncmp (argv[0], "sta", 3) == 0)
+    type = ZEBRA_ROUTE_STATIC;
+  else if (strncmp (argv[0], "ker", 3) == 0)
+    type = ZEBRA_ROUTE_KERNEL;
+  else if (strncmp (argv[0], "con", 3) == 0)
+    type = ZEBRA_ROUTE_CONNECT;
+  else if (strncmp (argv[0], "rip", 3) == 0)
+    type = ZEBRA_ROUTE_RIPNG;
+  else if (strncmp (argv[0], "bgp", 3) == 0)
+    type = ZEBRA_ROUTE_BGP;
+
+  ospf6_zebra_no_redistribute (type);
+  ospf6_asbr_routemap_unset (type);
+
+  /* remove redistributed route */
+  for (node = route_top (external_table); node; node = route_next (node))
+    {
+      route = node->info;
+      if (! route)
+        continue;
+      for (info = route->info_head; info; info = info_next)
+        {
+          info_next = info->next;
+          if (info->type != type)
+            continue;
+          ospf6_asbr_route_remove (info->type, info->ifindex,
+                                   &route->prefix);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+
+int
+ospf6_redistribute_config_write (struct vty *vty)
+{
+  int i;
+
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    {
+      if (i == ZEBRA_ROUTE_OSPF6)
+        continue;
+
+      if (! ospf6_zebra_is_redistribute (i))
+        continue;
+
+      if (rmap[i].map)
+        vty_out (vty, " redistribute %s route-map %s%s",
+                 ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE);
+      else
+        vty_out (vty, " redistribute %s%s",
+                 ZROUTE_NAME(i), VTY_NEWLINE);
+    }
+
+  return 0;
+}
 
 void
-ospf6_asbr_external_lsa_update (struct ospf6_route_req *request)
+ospf6_redistribute_show_config (struct vty *vty)
 {
+  int i;
+
+  if (! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_SYSTEM) &&
+      ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_KERNEL) &&
+      ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_STATIC) &&
+      ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_RIPNG) &&
+      ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_BGP))
+    return;
+
+  vty_out (vty, " Redistributing External Routes from,%s", VTY_NEWLINE);
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    {
+      if (i == ZEBRA_ROUTE_OSPF6)
+        continue;
+      if (! ospf6_zebra_is_redistribute (i))
+        continue;
+
+      if (rmap[i].map)
+        vty_out (vty, "    %s with route-map %s%s",
+                 ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE);
+      else
+        vty_out (vty, "    %s%s", ZROUTE_NAME(i), VTY_NEWLINE);
+    }
+}
+
+/* AS External LSA origination */
+int
+ospf6_asbr_external_lsa_originate (struct thread *thread)
+{
+  struct ospf6_external_info *info;
   char buffer [MAXLSASIZE];
-  u_int16_t size;
-  struct ospf6_lsa_as_external *external;
+  struct ospf6_lsa_as_external *e;
   char *p;
-  struct ospf6_route_req route;
-  char pbuf[BUFSIZ];
 
-  /* assert this is best path; if not, return */
-  ospf6_route_lookup (&route, &request->route.prefix, request->table);
-  if (memcmp (&route.path, &request->path, sizeof (route.path)))
-    return;
+  info = THREAD_ARG (thread);
 
-  if (IS_OSPF6_DUMP_LSA)
-    zlog_info ("Update AS-External: ID: %lu",
-               (u_long) ntohl (request->path.origin.id));
+  /* clear thread */
+  info->thread_originate = NULL;
+
+  if (info->is_removed)
+    {
+      if (IS_OSPF6_DUMP_ASBR)
+        {
+          char pbuf[64];
+          prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+          zlog_info ("ASBR: quit redistribution %s: state is down",
+                     pbuf);
+        }
+      return 0;
+    }
 
   /* prepare buffer */
   memset (buffer, 0, sizeof (buffer));
-  size = sizeof (struct ospf6_lsa_as_external);
-  external = (struct ospf6_lsa_as_external *) buffer;
-  p = (char *) (external + 1);
+  e = (struct ospf6_lsa_as_external *) buffer;
+  p = (char *) (e + 1);
 
-  if (route.path.metric_type == 2)
-    SET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E);   /* type2 */
+  if (info->metric_type == 2)
+    SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E);   /* type2 */
   else
-    UNSET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E); /* type1 */
+    UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E); /* type1, default */
 
   /* forwarding address */
-  if (! IN6_IS_ADDR_UNSPECIFIED (&route.nexthop.address))
-    SET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F);
+  if (! IN6_IS_ADDR_UNSPECIFIED (&info->forwarding))
+    SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F);
   else
-    UNSET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F);
+    UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F);
 
   /* external route tag */
-  UNSET_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T);
+  UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T);
 
   /* set metric. note: related to E bit */
-  OSPF6_ASBR_METRIC_SET (external, route.path.cost);
+  OSPF6_ASBR_METRIC_SET (e, info->metric);
 
   /* prefixlen */
-  external->prefix.prefix_length = route.route.prefix.prefixlen;
+  e->prefix.prefix_length = info->route->prefix.prefixlen;
 
   /* PrefixOptions */
-  external->prefix.prefix_options = route.path.prefix_options;
+  e->prefix.prefix_options = info->prefix_options;
 
   /* don't use refer LS-type */
-  external->prefix.prefix_refer_lstype = htons (0);
-
-  if (IS_OSPF6_DUMP_LSA)
-    {
-      prefix2str (&route.route.prefix, pbuf, sizeof (pbuf));
-      zlog_info ("  Prefix: %s", pbuf);
-    }
+  e->prefix.prefix_refer_lstype = htons (0);
 
   /* set Prefix */
-  memcpy (p, &route.route.prefix.u.prefix6,
-          OSPF6_PREFIX_SPACE (route.route.prefix.prefixlen));
-  ospf6_prefix_apply_mask (&external->prefix);
-  size += OSPF6_PREFIX_SPACE (route.route.prefix.prefixlen);
-  p += OSPF6_PREFIX_SPACE (route.route.prefix.prefixlen);
+  memcpy (p, &info->route->prefix.u.prefix6,
+          OSPF6_PREFIX_SPACE (info->route->prefix.prefixlen));
+  ospf6_prefix_apply_mask (&e->prefix);
+  p += OSPF6_PREFIX_SPACE (info->route->prefix.prefixlen);
 
   /* Forwarding address */
-  if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F))
+  if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F))
     {
-      memcpy (p, &route.nexthop.address, sizeof (struct in6_addr));
-      size += sizeof (struct in6_addr);
+      memcpy (p, &info->forwarding, sizeof (struct in6_addr));
       p += sizeof (struct in6_addr);
     }
 
   /* External Route Tag */
-  if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T))
+  if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T))
     {
       /* xxx */
     }
 
   ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
-                       route.path.origin.id, ospf6->router_id,
-                       (char *) external, size, ospf6);
-  return;
+                       htonl (info->id), ospf6->router_id,
+                       (char *) buffer, p - buffer, ospf6);
+  return 0;
+}
+
+int
+ospf6_asbr_schedule_external (void *data)
+{
+  struct ospf6_external_info *info = data;
+  u_long elasped_time, time = 0;
+
+  if (info->thread_originate)
+    {
+      if (IS_OSPF6_DUMP_ASBR)
+        {
+          char pbuf[64];
+          prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+          zlog_info ("ASBR: schedule redistribution %s: another thread",
+                     pbuf);
+        }
+      return 0;
+    }
+
+  elasped_time =
+    ospf6_lsa_has_elasped (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+                           htonl (info->id), ospf6->router_id, ospf6);
+  if (elasped_time < OSPF6_MIN_LS_INTERVAL)
+    time = OSPF6_MIN_LS_INTERVAL - elasped_time;
+  else
+    time = 0;
+
+  //if (IS_OSPF6_DUMP_ASBR)
+    {
+      char pbuf[64];
+      prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+      zlog_info ("ASBR: schedule redistribution %s as LS-ID %ld after %lu sec",
+                 pbuf, (u_long) info->id, time);
+    }
+
+  if (time)
+    info->thread_originate =
+      thread_add_timer (master, ospf6_asbr_external_lsa_originate, info, time);
+  else
+    info->thread_originate =
+      thread_add_timer (master, ospf6_asbr_external_lsa_originate, info, 0);
+
+  return 0;
+}
+
+int
+ospf6_asbr_external_lsa_flush (void *data)
+{
+  struct ospf6_lsa *lsa = data;
+  if (lsa)
+    ospf6_lsa_premature_aging (lsa);
+  return 0;
+}
+
+int
+ospf6_asbr_external_lsa_refresh (void *data)
+{
+  struct ospf6_lsa *lsa = data;
+  struct ospf6_lsa_as_external *e;
+  struct prefix prefix;
+  struct route_node *node;
+  struct ospf6_external_route *route = NULL;
+  struct ospf6_external_info *info = NULL;
+  struct ospf6_external_info *match = NULL;
+
+  if (IS_OSPF6_DUMP_ASBR)
+    zlog_info ("ASBR: refresh %s", lsa->str);
+
+  e = (struct ospf6_lsa_as_external *) (lsa->header + 1);
+  ospf6_prefix_in6_addr (&e->prefix, &prefix.u.prefix6);
+  prefix.prefixlen = e->prefix.prefix_length;
+  prefix.family = AF_INET6;
+  apply_mask_ipv6 ((struct prefix_ipv6 *) &prefix);
+
+  for (node = route_top (external_table); node; node = route_next (node))
+    {
+      route = node->info;
+      if (route == NULL)
+        continue;
+
+      for (info = route->info_head; info; info = info->next)
+        {
+          if (lsa->header->id == htonl (info->id))
+            match = info;
+        }
+    }
+
+  if (match == NULL)
+    {
+      ospf6_lsa_premature_aging (lsa);
+      return 0;
+    }
+
+  ospf6_asbr_schedule_external (match);
+  return 0;
+
+#if 0
+  node = route_node_lookup (external_table, &prefix);
+  if (! node || ! node->info)
+    {
+      char pname[64];
+
+      prefix2str (&prefix, pname, sizeof (pname));
+      if (IS_OSPF6_DUMP_ASBR)
+        zlog_info ("ASBR: could not find %s: premature age", pname);
+      ospf6_lsa_premature_aging (lsa);
+      return 0;
+    }
+
+  /* find external_info */
+  route = node->info;
+  for (info = route->info_head; info; info = info->next)
+    {
+      if (lsa->header->id == htonl (info->id))
+        break;
+    }
+
+  if (info)
+    ospf6_asbr_schedule_external (info);
+  else
+    ospf6_lsa_premature_aging (lsa);
+
+  return 0;
+#endif
 }
 
 void
-ospf6_asbr_external_route_add (struct ospf6_route_req *route)
+ospf6_asbr_route_add (int type, int ifindex, struct prefix *prefix,
+                      u_int nexthop_num, struct in6_addr *nexthop)
 {
-  ospf6_asbr_external_lsa_update (route);
+  int ret;
+  struct route_node *node;
+  struct ospf6_external_route *route;
+  struct ospf6_external_info *info, tinfo;
+
+  if (! ospf6_zebra_is_redistribute (type))
+    return;
+
+  /* apply route-map */
+  memset (&tinfo, 0, sizeof (struct ospf6_external_info));
+  if (rmap[type].map)
+    {
+      ret = route_map_apply (rmap[type].map, prefix, RMAP_OSPF6, &tinfo);
+      if (ret == RMAP_DENYMATCH)
+        {
+          if (IS_OSPF6_DUMP_ASBR)
+            zlog_info ("ASBR: denied by route-map %s", rmap[type].name);
+          return;
+        }
+    }
+
+  node = route_node_get (external_table, prefix);
+  route = node->info;
+
+  if (! route)
+    {
+      route = XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
+                       sizeof (struct ospf6_external_route));
+      memset (route, 0, sizeof (struct ospf6_external_route));
+
+      memcpy (&route->prefix, prefix, sizeof (struct prefix));
+
+      node->info = route;
+      route->node = node;
+    }
+
+  for (info = route->info_head; info; info = info->next)
+    {
+      if (info->type == type && info->ifindex == ifindex)
+        break;
+    }
+
+  if (! info)
+    {
+      info = XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
+                      sizeof (struct ospf6_external_info));
+      memset (info, 0, sizeof (struct ospf6_external_info));
+
+      info->route = route;
+      /* add tail */
+      info->prev = route->info_tail;
+      if (route->info_tail)
+        route->info_tail->next = info;
+      else
+        route->info_head = info;
+      route->info_tail = info;
+
+      info->id = link_state_id++;
+    }
+
+  /* copy result of route-map */
+  info->metric_type = tinfo.metric_type;
+  info->metric = tinfo.metric;
+  memcpy (&info->forwarding, &tinfo.forwarding,
+          sizeof (struct in6_addr));
+
+  info->type = type;
+  info->ifindex = ifindex;
+
+  if (nexthop_num && nexthop)
+    {
+      info->nexthop_num = nexthop_num;
+
+      if (info->nexthop)
+        XFREE (MTYPE_OSPF6_EXTERNAL_INFO, info->nexthop);
+
+      info->nexthop = (struct in6_addr *)
+        XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
+                 nexthop_num * sizeof (struct in6_addr));
+      memcpy (info->nexthop, nexthop,
+              nexthop_num * sizeof (struct in6_addr));
+    }
+
+  info->is_removed = 0;
+
+  //if (IS_OSPF6_DUMP_ASBR)
+    {
+      char pbuf[64];
+      struct timeval now;
+      prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+      gettimeofday (&now, NULL);
+      zlog_info ("ASBR: start redistributing %s as LS-ID %ld: %ld.%06ld",
+                 pbuf, (u_long) info->id, now.tv_sec, now.tv_usec);
+    }
+
+#ifdef HAVE_OSPF6_DAMP
+  ospf6_damp_event_up (OSPF6_DAMP_TYPE_ROUTE, prefix,
+                       ospf6_asbr_schedule_external, info);
+#else /*HAVE_OSPF6_DAMP*/
+  ospf6_asbr_schedule_external (info);
+#endif /*HAVE_OSPF6_DAMP*/
 }
 
 void
-ospf6_asbr_external_route_remove (struct ospf6_route_req *route)
+ospf6_asbr_route_remove (int type, int ifindex, struct prefix *prefix)
 {
+  struct route_node *node;
+  struct ospf6_external_route *route;
+  struct ospf6_external_info *info;
   struct ospf6_lsa *lsa;
 
-  lsa = ospf6_lsdb_lookup_lsdb (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
-                                route->path.origin.id,
-                                ospf6->router_id, ospf6->lsdb);
-  if (lsa)
-    ospf6_lsa_premature_aging (lsa);
+  node = route_node_get (external_table, prefix);
+  route = node->info;
+
+  if (! route)
+    return;
+
+  for (info = route->info_head; info; info = info->next)
+    {
+      if (info->type == type && info->ifindex == ifindex)
+        break;
+    }
+
+  if (! info)
+    return;
+
+  //if (IS_OSPF6_DUMP_ASBR)
+    {
+      char pbuf[64];
+      struct timeval now;
+      prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+      gettimeofday (&now, NULL);
+      zlog_info ("ASBR: quit redistributing %s as LS-ID %ld: %ld.%06ld",
+                 pbuf, (u_long) info->id, now.tv_sec, now.tv_usec);
+    }
+
+  if (info->thread_originate)
+    thread_cancel (info->thread_originate);
+  info->thread_originate = NULL;
+
+  lsa = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+                           htonl (info->id), ospf6->router_id, ospf6);
+#ifdef HAVE_OSPF6_DAMP
+  ospf6_damp_event_down (OSPF6_DAMP_TYPE_ROUTE, &info->route->prefix,
+                         ospf6_asbr_external_lsa_flush, lsa);
+#else /*HAVE_OSPF6_DAMP*/
+  ospf6_asbr_external_lsa_flush (lsa);
+#endif /*HAVE_OSPF6_DAMP*/
+
+#if 1
+  info->is_removed = 1;
+#else
+  /* remove from route */
+  if (info->prev)
+    info->prev->next = info->next;
+  else
+    info->route->info_head = info->next;
+  if (info->next)
+    info->next->prev = info->prev;
+  else
+    info->route->info_tail = info->prev;
+
+  /* if no info, free route */
+  if (! info->route->info_head && ! info->route->info_tail)
+    {
+      info->route->node->info = NULL;
+      free (info->route);
+    }
+
+  if (info->nexthop)
+    free (info->nexthop);
+  free (info);
+#endif /*0*/
 }
 
 void
@@ -134,22 +667,29 @@
   external = OSPF6_LSA_HEADER_END (lsa->header);
 
   if (IS_LSA_MAXAGE (lsa))
-    return;
+    {
+      if (IS_OSPF6_DUMP_ASBR)
+        zlog_info ("ASBR: maxage external lsa: %s seq: %lx",
+                   lsa->str, (u_long)ntohl (lsa->header->seqnum));
+      ospf6_asbr_external_lsa_remove (lsa);
+      return;
+    }
 
   if (IS_OSPF6_DUMP_ASBR)
-    zlog_info ("ASBR: Calculate %s", lsa->str);
+    zlog_info ("ASBR: new external lsa: %s seq: %lx",
+               lsa->str, (u_long)ntohl (lsa->header->seqnum));
 
   if (lsa->header->adv_router == ospf6->router_id)
     {
       if (IS_OSPF6_DUMP_ASBR)
-        zlog_info ("ASBR:   Self-originated, ignore");
+        zlog_info ("ASBR: my external LSA, ignore");
       return;
     }
 
   if (OSPF6_ASBR_METRIC (external) == LS_INFINITY)
     {
       if (IS_OSPF6_DUMP_ASBR)
-        zlog_info ("ASBR:   Metric is Infinity, ignore");
+        zlog_info ("ASBR: metric is infinity, ignore");
       return;
     }
 
@@ -167,7 +707,7 @@
         {
           char buf[64];
           inet_ntop (AF_INET, &asbr_id.adv_router, buf, sizeof (buf));
-          zlog_info ("ASBR:   ASBR %s not found, ignore", buf);
+          zlog_info ("ASBR: router %s not found, ignore", buf);
         }
       return;
     }
@@ -206,6 +746,14 @@
     {
       memcpy (&request.nexthop, &asbr_entry.nexthop,
               sizeof (struct ospf6_nexthop));
+      if (IS_OSPF6_DUMP_ASBR)
+        {
+          char buf[64], nhop[64], ifname[IFNAMSIZ];
+          prefix2str (&request.route.prefix, buf, sizeof (buf));
+          inet_ntop (AF_INET6, &request.nexthop.address, nhop, sizeof (nhop));
+          if_indextoname (request.nexthop.ifindex, ifname);
+          zlog_info ("ASBR: add route: %s %s%%%s", buf, nhop, ifname);
+        }
       ospf6_route_add (&request, ospf6->route_table);
       ospf6_route_next (&asbr_entry);
     }
@@ -220,12 +768,13 @@
   struct ospf6_route_req request;
 
   if (IS_OSPF6_DUMP_ASBR)
-    zlog_info ("ASBR: Withdraw route of %s", lsa->str);
+    zlog_info ("ASBR: withdraw external lsa: %s seq: %lx",
+               lsa->str, (u_long)ntohl (lsa->header->seqnum));
 
   if (lsa->header->adv_router == ospf6->router_id)
     {
       if (IS_OSPF6_DUMP_ASBR)
-        zlog_info ("ASBR:   Self-originated, ignore");
+        zlog_info ("ASBR: my external LSA, ignore");
       return;
     }
 
@@ -236,14 +785,14 @@
   memcpy (&dest.u.prefix6, (char *)(external + 1),
           OSPF6_PREFIX_SPACE (dest.prefixlen));
 
-  prefix2str (&dest, buf, sizeof (buf));
-  if (IS_OSPF6_DUMP_ASBR)
-    zlog_info ("ASBR:   route: %s", buf);
-
   ospf6_route_lookup (&request, &dest, ospf6->route_table);
   if (ospf6_route_end (&request))
     {
-      zlog_info ("ASBR:   route not found");
+      if (IS_OSPF6_DUMP_ASBR)
+        {
+          prefix2str (&dest, buf, sizeof (buf));
+          zlog_info ("ASBR: %s not found", buf);
+        }
       return;
     }
 
@@ -252,7 +801,8 @@
     {
       if (prefix_same (&request.route.prefix, &dest) != 1)
         {
-          zlog_info ("ASBR:   Can't find the entry matches the origin");
+          if (IS_OSPF6_DUMP_ASBR)
+            zlog_info ("ASBR:   Can't find the entry matches the origin");
           return;
         }
       ospf6_route_next (&request);
@@ -264,6 +814,15 @@
          request.path.origin.adv_router == lsa->header->adv_router &&
          prefix_same (&request.route.prefix, &dest) == 1)
     {
+      if (IS_OSPF6_DUMP_ASBR)
+        {
+          char nhop[64], ifname[IFNAMSIZ];
+          prefix2str (&dest, buf, sizeof (buf));
+          inet_ntop (AF_INET6, &request.nexthop.address, nhop, sizeof (nhop));
+          if_indextoname (request.nexthop.ifindex, ifname);
+          zlog_info ("ASBR: remove route: %s %s%%%s", buf, nhop, ifname);
+        }
+
       ospf6_route_remove (&request, ospf6->route_table);
       ospf6_route_next (&request);
     }
@@ -303,7 +862,7 @@
     {
       char buf[64];
       inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf));
-      zlog_info ("ASBR: New router found: %s", buf);
+      zlog_info ("ASBR: new router found: %s", buf);
     }
 
   if (ntohl (id) != 0 ||
@@ -335,7 +894,7 @@
     {
       char buf[64];
       inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf));
-      zlog_info ("ASBR: Router disappearing: %s", buf);
+      zlog_info ("ASBR: router disappearing: %s", buf);
     }
 
   if (ntohl (id) != 0 ||
@@ -410,37 +969,6 @@
   return 0;
 }
 
-int
-ospf6_asbr_external_refresh (void *old)
-{
-  struct ospf6_lsa *lsa = old;
-  struct ospf6_route_req route, *target;
-
-  assert (ospf6);
-
-  if (IS_OSPF6_DUMP_ASBR)
-    zlog_info ("ASBR: refresh %s", lsa->str);
-
-  target = NULL;
-  for (ospf6_route_head (&route, ospf6->external_table);
-       ! ospf6_route_end (&route);
-       ospf6_route_next (&route))
-    {
-      if (route.path.origin.id == lsa->header->id)
-        {
-          target = &route;
-          break;
-        }
-    }
-
-  if (target)
-    ospf6_asbr_external_lsa_update (target);
-  else
-    ospf6_lsa_premature_aging (lsa);
-
-  return 0;
-}
-
 void
 ospf6_asbr_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new)
 {
@@ -459,7 +987,7 @@
   slot.type              = htons (OSPF6_LSA_TYPE_AS_EXTERNAL);
   slot.name              = "AS-External";
   slot.func_show         = ospf6_asbr_external_show;
-  slot.func_refresh      = ospf6_asbr_external_refresh;
+  slot.func_refresh      = ospf6_asbr_external_lsa_refresh;
   ospf6_lsa_slot_register (&slot);
 
   ospf6_lsdb_hook[OSPF6_LSA_TYPE_AS_EXTERNAL & OSPF6_LSTYPE_CODE_MASK].hook = 
@@ -467,9 +995,71 @@
 }
 
 void
+ospf6_asbr_external_info_show (struct vty *vty,
+                               struct ospf6_external_info *info)
+{
+  char prefix_buf[64], id_buf[16];
+  struct in_addr id;
+
+  if (info->is_removed)
+    return;
+
+  id.s_addr = ntohl (info->id);
+  inet_ntop (AF_INET, &id, id_buf, sizeof (id_buf));
+  prefix2str (&info->route->prefix, prefix_buf, sizeof (prefix_buf));
+  vty_out (vty, "%s %-32s %3d %-15s %3d %lu(type-%d)%s",
+           ZROUTE_ABNAME(info->type), prefix_buf, info->ifindex, id_buf,
+           info->nexthop_num, (u_long) info->metric, info->metric_type,
+           VTY_NEWLINE);
+}
+
+void
+ospf6_asbr_external_route_show (struct vty *vty,
+                                struct ospf6_external_route *route)
+{
+  struct ospf6_external_info *info;
+  for (info = route->info_head; info; info = info->next)
+    ospf6_asbr_external_info_show (vty, info);
+}
+
+DEFUN (show_ipv6_route_ospf6_external,
+       show_ipv6_route_ospf6_external_cmd,
+       "show ipv6 ospf6 route redistribute",
+       SHOW_STR
+       IP6_STR
+       ROUTE_STR
+       OSPF6_STR
+       "redistributing External information\n"
+       )
+{
+  struct route_node *node;
+  struct ospf6_external_route *route;
+
+  vty_out (vty, "%s %-32s %3s %-15s %3s %s%s",
+           " ", "Prefix", "I/F", "LS-Id", "#NH", "Metric",
+           VTY_NEWLINE);
+  for (node = route_top (external_table); node; node = route_next (node))
+    {
+      route = node->info;
+      if (route)
+        ospf6_asbr_external_route_show (vty, route);
+    }
+  return CMD_SUCCESS;
+}
+
+void
 ospf6_asbr_init ()
 {
+  external_table = route_table_init ();
+  link_state_id = 0;
+
   ospf6_asbr_register_as_external ();
+
+  install_element (VIEW_NODE, &show_ipv6_route_ospf6_external_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_route_ospf6_external_cmd);
+  install_element (OSPF6_NODE, &ospf6_redistribute_cmd);
+  install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd);
+  install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd);
 }
 
 
diff -x CVS -urN ospf6d.old/ospf6_asbr.h ospf6d/ospf6_asbr.h
--- ospf6d.old/ospf6_asbr.h	Sat Apr 26 23:17:47 2003
+++ ospf6d/ospf6_asbr.h	Sat Nov  9 11:25:30 2002
@@ -22,6 +22,51 @@
 #ifndef OSPF6_ASBR_H
 #define OSPF6_ASBR_H
 
+#include "thread.h"
+
+struct ospf6_external_info
+{
+  int is_removed;
+  struct thread *thread_originate;
+
+  struct ospf6_external_route *route;
+
+  struct ospf6_external_info *prev;
+  struct ospf6_external_info *next;
+
+  /* external route type */
+  int type;
+
+  /* external route ifindex */
+  int ifindex;
+
+  /* LS-ID */
+  u_int32_t id;
+
+  /* nexthops */
+  u_int nexthop_num;
+  struct in6_addr *nexthop;
+
+  u_int8_t  prefix_options;
+
+  u_int8_t  metric_type;
+  u_int32_t metric;
+  struct in6_addr forwarding;
+  /* u_int32_t tag; */
+};
+
+struct ospf6_external_route
+{
+  struct route_node *node;
+
+  /* prefix */
+  struct prefix prefix;
+
+  /* external information */
+  struct ospf6_external_info *info_head;
+  struct ospf6_external_info *info_tail;
+};
+
 /* AS-External-LSA */
 struct ospf6_lsa_as_external
 {
@@ -42,8 +87,16 @@
   { (E)->bits_metric &= htonl (0xff000000); \
     (E)->bits_metric |= htonl (0x00ffffff) & htonl (C); }
 
-void ospf6_asbr_external_route_add (struct ospf6_route_req *route);
-void ospf6_asbr_external_route_remove (struct ospf6_route_req *route);
+void ospf6_asbr_routemap_update ();
+
+int ospf6_redistribute_config_write (struct vty *vty);
+void ospf6_redistribute_show_config (struct vty *vty);
+
+void
+ospf6_asbr_route_add (int type, int ifindex, struct prefix *prefix,
+                      u_int nexthop_num, struct in6_addr *nexthop);
+void
+ospf6_asbr_route_remove (int type, int ifindex, struct prefix *prefix);
 
 void ospf6_asbr_external_lsa_add (struct ospf6_lsa *lsa);
 void ospf6_asbr_external_lsa_remove (struct ospf6_lsa *lsa);
diff -x CVS -urN ospf6d.old/ospf6_damp.c ospf6d/ospf6_damp.c
--- ospf6d.old/ospf6_damp.c	Thu Jan  1 01:00:00 1970
+++ ospf6d/ospf6_damp.c	Sat Nov  9 11:25:30 2002
@@ -0,0 +1,748 @@
+/*
+ * OSPF flap dampening by Manav Bhatia
+ * Copyright (C) 2002 
+ * 
+ * This file is part of GNU Zebra.
+ * 
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ * 
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+#include <math.h>
+
+#include "log.h"
+#include "prefix.h"
+#include "thread.h"
+#include "table.h"
+#include "command.h"
+#include "vty.h"
+
+extern struct thread_master *master;
+
+#include "ospf6_damp.h"
+
+#ifdef HAVE_OSPF6_DAMP
+
+#define DELTA_REUSE         10 /* Time granularity for reuse lists */
+#define DELTA_T              5 /* Time granularity for decay arrays */
+#define DEFAULT_HALF_LIFE   60 /* (sec)     1 min */
+
+#define DEFAULT_PENALTY   1000
+#define DEFAULT_REUSE      750
+#define DEFAULT_SUPPRESS  2000
+
+#define REUSE_LIST_SIZE    256
+#define REUSE_ARRAY_SIZE  1024
+
+/* Global variable to access damping configuration */
+struct ospf6_damp_config damp_config;
+struct ospf6_damp_config *dc = &damp_config;
+u_int reuse_array_offset = 0;
+struct route_table *damp_info_table[OSPF6_DAMP_TYPE_MAX];
+struct thread *ospf6_reuse_thread = NULL;
+
+int ospf6_damp_debug = 0;
+#define IS_OSPF6_DEBUG_DAMP (ospf6_damp_debug)
+
+static struct ospf6_damp_info *
+ospf6_damp_lookup (u_short type, struct prefix *name)
+{
+  struct route_node *node;
+
+  node = route_node_lookup (damp_info_table[type], name);
+  if (node && node->info)
+    return (struct ospf6_damp_info *) node->info;
+  return NULL;
+}
+
+static struct ospf6_damp_info *
+ospf6_damp_create (u_short type, struct prefix *name)
+{
+  struct route_node *node;
+  struct ospf6_damp_info *di;
+  char namebuf[64];
+
+  di = ospf6_damp_lookup (type, name);
+  if (di)
+    return di;
+
+  if (IS_OSPF6_DEBUG_DAMP)
+    {
+      prefix2str (name, namebuf, sizeof (namebuf));
+      zlog_info ("DAMP: create: type: %d, name: %s", type, namebuf);
+    }
+
+  di = (struct ospf6_damp_info *)
+    malloc (sizeof (struct ospf6_damp_info));
+  memset (di, 0, sizeof (struct ospf6_damp_info));
+  di->type = type;
+  prefix_copy (&di->name, name);
+
+  node = route_node_get (damp_info_table[type], name);
+  node->info = di;
+
+  return di;
+}
+
+static void
+ospf6_damp_delete (u_short type, struct prefix *name)
+{
+  struct route_node *node;
+  struct ospf6_damp_info *di;
+  char namebuf[64];
+
+  node = route_node_lookup (damp_info_table[type], name);
+  if (! node || ! node->info)
+    return;
+
+  di = node->info;
+
+  if (IS_OSPF6_DEBUG_DAMP)
+    {
+      prefix2str (&di->name, namebuf, sizeof (namebuf));
+      zlog_info ("DAMP: delete: type: %d, name: %s",
+                 di->type, namebuf);
+    }
+
+  node->info = NULL;
+  free (di);
+}
+
+/* compute and fill the configuration parameter */
+void
+ospf6_damp_init_config (u_int half_life, u_int reuse,
+                        u_int suppress, u_int t_hold)
+{
+  int i;
+  double max_ratio, max_ratio1, max_ratio2;
+
+  dc->half_life = half_life ? half_life : DEFAULT_HALF_LIFE;
+  dc->reuse     = reuse     ? reuse     : DEFAULT_REUSE;
+  dc->suppress  = suppress  ? suppress  : DEFAULT_SUPPRESS;
+  dc->t_hold    = t_hold    ? t_hold    : 4 * dc->half_life;
+
+  /* Initialize system-wide params */
+  dc->delta_t = DELTA_T;
+  dc->delta_reuse = DELTA_REUSE;
+  dc->default_penalty = DEFAULT_PENALTY;
+  dc->reuse_index_array_size = REUSE_ARRAY_SIZE;
+
+  /* ceiling is the maximum penalty a route may attain */
+  /* ceiling = reuse * 2^(T-hold/half-life) */
+  dc->ceiling = (int)
+    (dc->reuse * (pow (2, (double) dc->t_hold / dc->half_life)));
+
+  /* Decay-array computations */
+  /* decay_array_size = decay memory/time granularity */
+  dc->decay_array_size = ceil ((double) dc->t_hold / dc->delta_t);
+  dc->decay_array = malloc (sizeof (double) * (dc->decay_array_size));
+
+  /* Each i-th element is per tick delay raised to the i-th power */
+  dc->decay_array[0] = 1.0;
+  dc->decay_array[1] = exp ((1.0 / (dc->half_life / dc->delta_t)) * log (0.5));
+  for (i = 2; i < dc->decay_array_size; i++)
+    dc->decay_array[i] = dc->decay_array[i - 1] * dc->decay_array[1];
+
+  /* Reuse-list computations (reuse queue head array ?) */
+  dc->reuse_list_size = ceil ((double) dc->t_hold / dc->delta_reuse) + 1;
+  if (dc->reuse_list_size == 0 || dc->reuse_list_size > REUSE_LIST_SIZE)
+    dc->reuse_list_size = REUSE_LIST_SIZE;
+  dc->reuse_list_array = (struct ospf6_damp_info **)
+    malloc (dc->reuse_list_size * sizeof (struct ospf6_reuse_list *));
+  memset (dc->reuse_list_array, 0x00,
+          dc->reuse_list_size * sizeof (struct ospf6_reuse_list *));
+
+  /* Reuse-array computations */
+  dc->reuse_index_array = malloc (sizeof (int) * dc->reuse_index_array_size);
+
+  /*
+   * This is the maximum ratio between the current value of the penalty and
+   * the reuse value which can be indexed by the reuse array. It will be 
+   * limited by the ceiling or by the amount of time that the reuse list 
+   * covers 
+   */
+  max_ratio1 = (double) dc->ceiling / dc->reuse;
+  max_ratio2 = exp ((double) dc->t_hold / dc->half_life) * log10 (2.0);
+  max_ratio = (max_ratio2 != 0 && max_ratio2 < max_ratio1 ?
+               max_ratio2 : max_ratio1);
+
+  /*
+   * reuse array is just an estimator and we need something
+   * to use the full array 
+   */
+  dc->scale_factor = (double) dc->reuse_index_array_size / (max_ratio - 1);
+
+  for (i = 0; i < dc->reuse_index_array_size; i++)
+    {
+      dc->reuse_index_array[i] = (int)
+        (((double) dc->half_life / dc->delta_reuse) *
+         log10 (1.0 / (dc->reuse * (1.0 + ((double) i / dc->scale_factor))))
+         / log10 (0.5));
+    }
+
+  dc->enabled = ON;
+}
+
+static double
+ospf6_damp_decay (time_t tdiff)
+{
+  int index = tdiff / dc->delta_t;
+
+  if (index >= dc->decay_array_size)
+    return 0;
+
+  return dc->decay_array[index];
+}
+
+static int
+ospf6_damp_reuse_index (int penalty)
+{
+  int index;
+
+  index = (int) (((double) penalty / dc->reuse - 1.0) * dc->scale_factor);
+
+  if (index >= dc->reuse_index_array_size)
+    index = dc->reuse_index_array_size - 1;
+
+  return (dc->reuse_index_array[index] - dc->reuse_index_array[0]);
+}
+
+static int
+ospf6_reuse_list_lookup (struct ospf6_damp_info *di)
+{
+  struct ospf6_damp_info *info;
+
+  for (info = dc->reuse_list_array[di->index]; info; info = info->next)
+    {
+      if (info == di)
+        return 1;
+    }
+  return 0;
+}
+
+static void
+ospf6_reuse_list_remove (struct ospf6_damp_info *di)
+{
+  if (di->prev)
+    di->prev->next = di->next;
+  else
+    dc->reuse_list_array[di->index] = di->next;
+  if (di->next)
+    di->next->prev = di->prev;
+
+  di->index = -1;
+  di->prev = NULL;
+  di->next = NULL;
+}
+
+static void
+ospf6_reuse_list_add (struct ospf6_damp_info *di)
+{
+  /* set the index of reuse-array */
+  di->index = (reuse_array_offset + (ospf6_damp_reuse_index (di->penalty)))
+              % dc->reuse_list_size;
+
+  /* insert to the head of the reuse list */
+  di->next = dc->reuse_list_array[di->index];
+  if (di->next)
+    di->next->prev = di;
+  di->prev = NULL;
+  dc->reuse_list_array[di->index] = di;
+}
+
+/* When we quit damping for a target, we should execute proper event
+   which have been postponed during damping */
+static void
+ospf6_damp_stop (struct ospf6_damp_info *di)
+{
+  time_t t_now;
+  char namebuf[64];
+  struct timeval now;
+
+  if (IS_OSPF6_DEBUG_DAMP)
+    {
+      t_now = time (NULL);
+      prefix2str (&di->name, namebuf, sizeof (namebuf));
+      gettimeofday (&now, NULL);
+      zlog_info ("DAMP: %lu.%06lu stop damping: %ld: type: %d, name: %s",
+                 now.tv_sec, now.tv_usec,
+                 t_now, di->type, namebuf);
+    }
+
+  /* set flag indicates that we're damping this target */
+  di->damping = OFF;
+
+  /* if the target's current status differ from that it should be,
+     execute the proper event to repair his status */
+  if (di->target_status != di->event_type)
+    {
+      (*(di->event)) (di->target);
+      di->target_status = di->event_type;
+
+      di->event = NULL;
+      di->event_type = event_none;
+    }
+}
+
+/* ospf6_reuse_timer is called every DELTA_REUSE seconds.
+   Each route in the current reuse-list is evaluated
+   and is used or requeued */
+int
+ospf6_damp_reuse_timer (struct thread *t)
+{
+  struct ospf6_damp_info *di, *next;
+  time_t t_now, t_diff;
+  char namebuf[64];
+  struct timeval now;
+
+  /* Restart the reuse timer */
+  ospf6_reuse_thread =
+    thread_add_timer (master, ospf6_damp_reuse_timer, NULL, dc->delta_reuse);
+
+  t_now = time (NULL);
+
+  /* get the damp info list head */
+  di = dc->reuse_list_array[reuse_array_offset];
+  dc->reuse_list_array[reuse_array_offset] = NULL;
+
+  /* rotate the circular reuse list head array */
+  reuse_array_offset = (reuse_array_offset + 1) % dc->reuse_list_size;
+
+  /* for each damp info */
+  while (di)
+    {
+      next = di->next;
+      di->next = NULL;
+
+      /* Update penalty */
+      t_diff = t_now - di->t_updated;
+      di->t_updated = t_now;
+      di->penalty = (int)
+        ((double) di->penalty * ospf6_damp_decay (t_diff));
+      /* configration of ceiling may be just changed */
+      if (di->penalty > dc->ceiling)
+        di->penalty = dc->ceiling;
+
+      if (IS_OSPF6_DEBUG_DAMP)
+        {
+          prefix2str (&di->name, namebuf, sizeof (namebuf));
+          gettimeofday (&now, NULL);
+          zlog_info ("DAMP: %lu.%06lu update penalty: type: %d, name: %s, penalty: %d",
+                     now.tv_sec, now.tv_usec,
+                     di->type, namebuf, di->penalty);
+        }
+
+      /* If the penalty becomes under reuse,
+         call real event that we have been postponed. */
+      if (di->penalty < dc->reuse && di->damping == ON)
+        ospf6_damp_stop (di);
+
+      /* If the penalty becomes less than the half of the
+         reuse value, this damp info will be freed from reuse-list,
+         by assuming that it is considered to be stable enough already,
+         and there's no need to maintain flapping history for this. */
+      if (di->penalty <= dc->reuse / 2)
+        {
+          ospf6_damp_delete (di->type, &di->name);
+          di = next;
+          continue;
+        }
+
+      /* re-insert to the reuse-list */
+      ospf6_reuse_list_add (di);
+
+      di = next;
+    }
+
+  return 0;
+}
+
+static void
+ospf6_damp_event (damp_event_t event_type,
+                  u_short type, struct prefix *name,
+                  int (*event) (void *), void *target)
+{
+  time_t t_now, t_diff;
+  struct ospf6_damp_info *di;
+  char namebuf[64];
+  struct timeval now;
+
+  if (dc->enabled == OFF)
+    {
+      (*event) (target);
+      return;
+    }
+
+  di = ospf6_damp_lookup (type, name);
+  if (! di)
+    di = ospf6_damp_create (type, name);
+
+  t_now = time (NULL);
+
+  di->event = event;
+  di->target = target;
+  di->event_type = event_type;
+
+  if (! ospf6_reuse_list_lookup (di))
+    di->t_start = t_now;
+  else
+    {
+      ospf6_reuse_list_remove (di);
+
+      t_diff = t_now - di->t_updated;
+      di->penalty = (int) (di->penalty * ospf6_damp_decay (t_diff));
+    }
+
+  /* penalty only on down event */
+  if (event_type == event_down)
+    {
+      di->flap++;
+      di->penalty += dc->default_penalty;
+    }
+
+  /* limit penalty up to ceiling */
+  if (di->penalty > dc->ceiling)
+    di->penalty = dc->ceiling;
+
+  if (IS_OSPF6_DEBUG_DAMP)
+    {
+      prefix2str (&di->name, namebuf, sizeof (namebuf));
+      gettimeofday (&now, NULL);
+      zlog_info ("DAMP: %lu.%06lu update penalty: type: %d, name: %s, penalty: %d",
+                 now.tv_sec, now.tv_usec,
+                 di->type, namebuf, di->penalty);
+    }
+
+  /* if penalty < reuse, stop damping here */
+  if (di->penalty < dc->reuse && di->damping == ON)
+    {
+      if (IS_OSPF6_DEBUG_DAMP)
+        {
+          prefix2str (&di->name, namebuf, sizeof (namebuf));
+          gettimeofday (&now, NULL);
+          zlog_info ("DAMP: %lu.%06lu stop damping: %ld: type: %d, name: %s",
+                     now.tv_sec, now.tv_usec,
+                     t_now, di->type, namebuf);
+        }
+      di->damping = OFF;
+    }
+
+  /* if event == up and if penalty >= suppress , start damping here */
+  if (di->event_type == event_up && di->penalty >= dc->suppress &&
+      di->damping == OFF)
+    {
+      if (IS_OSPF6_DEBUG_DAMP)
+        {
+          prefix2str (&di->name, namebuf, sizeof (namebuf));
+          gettimeofday (&now, NULL);
+          zlog_info ("DAMP: %lu.%06lu start damping: %ld: type: %d, name: %s",
+                     now.tv_sec, now.tv_usec,
+                     t_now, type, namebuf);
+        }
+      di->damping = ON;
+    }
+
+  /* execute event if we're not damping */
+  if (di->damping == OFF)
+    {
+      (*(di->event)) (di->target);
+      di->target_status = di->event_type;
+    }
+
+  /* if the penalty goes beyond suppress value, start damping */
+  if (di->penalty >= dc->suppress && di->damping == OFF)
+    {
+      if (IS_OSPF6_DEBUG_DAMP)
+        {
+          prefix2str (name, namebuf, sizeof (namebuf));
+          gettimeofday (&now, NULL);
+          zlog_info ("DAMP: %lu.%06lu start damping: %ld: type: %d, name: %s",
+                     now.tv_sec, now.tv_usec,
+                     t_now, type, namebuf);
+        }
+      di->damping = ON;
+    }
+
+  /* update last-updated-time field */
+  di->t_updated = t_now;
+
+  /* Insert it into the reuse list */
+  ospf6_reuse_list_add (di);
+}
+
+void
+ospf6_damp_event_up (u_short type, struct prefix *name,
+                     int (*event) (void *), void *target)
+{
+  struct timeval now;
+
+  gettimeofday (&now, NULL);
+  if (IS_OSPF6_DEBUG_DAMP)
+    zlog_info ("DAMP: Up   Event at %lu.%06lu", now.tv_sec, now.tv_usec);
+
+  ospf6_damp_event (event_up, type, name, event, target);
+}
+
+void
+ospf6_damp_event_down (u_short type, struct prefix *name,
+                       int (*event) (void *), void *target)
+{
+  struct timeval now;
+
+  gettimeofday (&now, NULL);
+  if (IS_OSPF6_DEBUG_DAMP)
+    zlog_info ("DAMP: Down Event at %lu.%06lu", now.tv_sec, now.tv_usec);
+
+  ospf6_damp_event (event_down, type, name, event, target);
+}
+
+int
+ospf6_damp_debug_thread (struct thread *thread)
+{
+  int i;
+  struct ospf6_damp_info *di;
+  char buf[256];
+  time_t t_now;
+  struct timeval now;
+
+  for (i = 0; i < dc->reuse_list_size; i++)
+    {
+      for (di = dc->reuse_list_array[i]; di; di = di->next)
+        {
+          t_now = time (NULL);
+          gettimeofday (&now, NULL);
+          prefix2str (&di->name, buf, sizeof (buf));
+          zlog_info ("DAMP: %lu.%06lu %c %-32s penalty %7u",
+                     now.tv_sec, now.tv_usec,
+                     (di->damping == ON ? 'D' : 'A'), buf,
+                     (u_int) (di->penalty *
+                              ospf6_damp_decay (t_now - di->t_updated)));
+        }
+    }
+  thread_add_timer (master, ospf6_damp_debug_thread, NULL, 1);
+  return 0;
+}
+
+DEFUN (show_ipv6_ospf6_route_flapping,
+       show_ipv6_ospf6_route_flapping_cmd,
+       "show ipv6 ospf6 route flapping",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR)
+{
+  int i;
+  struct ospf6_damp_info *di;
+  char buf[256];
+  time_t t_now;
+
+  t_now = time (NULL);
+  vty_out (vty, "%c %-32s %7s%s", ' ', "Prefix", "penalty", VTY_NEWLINE);
+
+  for (i = 0; i < dc->reuse_list_size; i++)
+    {
+      for (di = dc->reuse_list_array[i]; di; di = di->next)
+        {
+          prefix2str (&di->name, buf, sizeof (buf));
+          vty_out (vty, "%c %-32s %7u%s",
+                   (di->damping == ON ? 'D' : ' '), buf,
+                   (u_int) (di->penalty *
+                            ospf6_damp_decay (t_now - di->t_updated)),
+                   VTY_NEWLINE);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (flap_damping_route,
+       flap_damping_route_cmd,
+       "flap-damping route <0-4294967295> <0-4294967295> "
+                          "<0-4294967295> <0-4294967295>",
+       "enable flap dampening\n"
+       "enable route flap dampening\n"
+       "half-life in second\n"
+       "reuse value\n"
+       "suppress value\n"
+       "t-hold in second (maximum time that the target can be damped)\n"
+      )
+{
+  u_int half_life, reuse, suppress, t_hold;
+
+  if (argc)
+    {
+      half_life = (u_int) strtoul (argv[0], NULL, 10);
+      reuse     = (u_int) strtoul (argv[1], NULL, 10);
+      suppress  = (u_int) strtoul (argv[2], NULL, 10);
+      t_hold    = (u_int) strtoul (argv[3], NULL, 10);
+    }
+  else
+    {
+      half_life = (u_int) DEFAULT_HALF_LIFE;
+      reuse     = (u_int) DEFAULT_REUSE;
+      suppress  = (u_int) DEFAULT_SUPPRESS;
+      t_hold    = (u_int) DEFAULT_HALF_LIFE * 4;
+    }
+
+  if (reuse && suppress && reuse >= suppress)
+    {
+      vty_out (vty, "reuse value exceeded suppress value, failed%s\n",
+               VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  if (half_life && t_hold && half_life >= t_hold)
+    {
+      vty_out (vty, "half-life exceeded t-hold, failed%s\n", VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  ospf6_damp_init_config (half_life, reuse, suppress, t_hold);
+
+  if (ospf6_reuse_thread == NULL)
+    ospf6_reuse_thread =
+      thread_add_timer (master, ospf6_damp_reuse_timer, NULL, dc->delta_reuse);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_ospf6_damp_config,
+       show_ipv6_ospf6_camp_config_cmd,
+       "show ipv6 ospf6 damp config",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Flap-dampening information\n"
+       "shows dampening configuration\n"
+      )
+{
+  int i;
+
+  vty_out (vty, "%10s %10s %10s %10s%s",
+           "Half life", "Suppress", "Reuse", "T-hold",
+           VTY_NEWLINE);
+  vty_out (vty, "%10u %10u %10u %10u%s",
+           dc->half_life, dc->suppress, dc->reuse, dc->t_hold,
+           VTY_NEWLINE);
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  vty_out (vty, "Delta-t = %u%s", dc->delta_t, VTY_NEWLINE);
+  vty_out (vty, "Delta-Reuse = %u%s", dc->delta_reuse, VTY_NEWLINE);
+  vty_out (vty, "Default-Penalty = %u%s", dc->default_penalty, VTY_NEWLINE);
+  vty_out (vty, "Ceiling = %u%s", dc->ceiling, VTY_NEWLINE);
+  vty_out (vty, "ScaleFactor = %f%s", dc->scale_factor, VTY_NEWLINE);
+
+  vty_out (vty, "DecayArray(%d) =%s", dc->decay_array_size, VTY_NEWLINE);
+  for (i = 0; i < dc->decay_array_size; i++)
+    {
+      if (i % 10 == 0)
+        vty_out (vty, "  ");
+      vty_out (vty, " %f", dc->decay_array[i]);
+      if (i % 10 == 0)
+        vty_out (vty, "%s", VTY_NEWLINE);
+    }
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  vty_out (vty, "ReuseIndexArray(%d) =%s",
+           dc->reuse_index_array_size, VTY_NEWLINE);
+  for (i = 0; i < dc->reuse_index_array_size; i++)
+    {
+      if (i % 10 == 0)
+        vty_out (vty, "  ");
+      vty_out (vty, " %d", dc->reuse_index_array[i]);
+      if (i % 10 == 0)
+        vty_out (vty, "%s", VTY_NEWLINE);
+    }
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  return CMD_SUCCESS;
+}
+
+void
+ospf6_damp_config_write (struct vty *vty)
+{
+  if (dc->enabled == ON)
+    {
+      vty_out (vty, " flap-damping route %u %u %u %u%s",
+               dc->half_life, dc->reuse, dc->suppress, dc->t_hold,
+               VTY_NEWLINE);
+    }
+}
+
+DEFUN (debug_ospf6_damp,
+       debug_ospf6_damp_cmd,
+       "debug ospf6 damp",
+       DEBUG_STR
+       OSPF6_STR
+       "Flap-dampening information\n"
+      )
+{
+  ospf6_damp_debug = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ospf6_damp,
+       no_debug_ospf6_damp_cmd,
+       "no debug ospf6 damp",
+       NO_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Flap-dampening information\n"
+      )
+{
+  ospf6_damp_debug = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_debug_ospf6_damp,
+       show_debug_ospf6_damp_cmd,
+       "show debugging ospf6 damp",
+       SHOW_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Flap-dampening information\n"
+      )
+{
+  vty_out (vty, "debugging ospf6 damp is ");
+  if (IS_OSPF6_DEBUG_DAMP)
+    vty_out (vty, "enabled.");
+  else
+    vty_out (vty, "disabled.");
+  vty_out (vty, "%s", VTY_NEWLINE);
+  return CMD_SUCCESS;
+}
+
+void
+ospf6_damp_init ()
+{
+  int i;
+  for (i = 0; i < OSPF6_DAMP_TYPE_MAX; i++)
+    damp_info_table[i] = route_table_init ();
+
+  install_element (VIEW_NODE, &show_ipv6_ospf6_route_flapping_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_route_flapping_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_camp_config_cmd);
+  install_element (OSPF6_NODE, &flap_damping_route_cmd);
+
+  install_element (ENABLE_NODE, &show_debug_ospf6_damp_cmd);
+  install_element (CONFIG_NODE, &debug_ospf6_damp_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf6_damp_cmd);
+
+  thread_add_event (master, ospf6_damp_debug_thread, NULL, 0);
+}
+
+#endif /* HAVE_OSPF6_DAMP */
+
+
diff -x CVS -urN ospf6d.old/ospf6_damp.h ospf6d/ospf6_damp.h
--- ospf6d.old/ospf6_damp.h	Thu Jan  1 01:00:00 1970
+++ ospf6d/ospf6_damp.h	Tue Oct  1 00:41:10 2002
@@ -0,0 +1,109 @@
+/*
+ * OSPF flap dampening by Manav Bhatia
+ * Copyright (C) 2002 
+ * 
+ * This file is part of GNU Zebra.
+ * 
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ * 
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+/*
+ * Flap Damping (target e.g. link/route)
+ */
+
+#define HAVE_OSPF6_DAMP
+
+typedef enum
+{
+  OFF,
+  ON,
+} onoff_t;
+
+typedef enum
+{
+  event_none,
+  event_up,
+  event_down,
+} damp_event_t;
+
+/* Structure maintained per target basis */
+struct ospf6_damp_info
+{
+  /* identifier to decide which target */
+  u_short type;
+  struct prefix name;
+
+  /* do we damping this info */
+  onoff_t damping;
+
+  u_int penalty;
+  u_int flap;
+  time_t t_start;   /* First flap (down event) time */
+  time_t t_updated; /* Last time the penalty was updated */
+
+  /* index and double-link for reuse list */
+  int                    index;
+  struct ospf6_damp_info *next;
+  struct ospf6_damp_info *prev;
+
+  /* the last event that we are avoiding */
+  int (*event) (void *target);
+  void *target;
+  damp_event_t event_type;
+  damp_event_t target_status;
+};
+
+#define OSPF6_DAMP_TYPE_ROUTE      0
+#define OSPF6_DAMP_TYPE_MAX        1
+
+/* Global Configuration Parameters */
+struct ospf6_damp_config
+{
+  /* is damping enabled ? */
+  onoff_t enabled;
+
+  /* configurable parameters */
+  u_int half_life;
+  u_int suppress;
+  u_int reuse;
+  u_int t_hold;                 /* Maximum hold down time */
+
+  /* Non configurable parameters */
+  u_int   delta_t;
+  u_int   delta_reuse;
+  u_int   default_penalty;
+  u_int   ceiling;              /* Max value a penalty can attain */
+  double  scale_factor;
+
+  int     decay_array_size;     /* Calculated using config parameters */
+  double *decay_array;          /* Storage for decay values */
+
+  int  reuse_index_array_size;  /* Size of reuse index array */
+  int *reuse_index_array;
+
+  int  reuse_list_size;         /* Number of reuse lists */
+  struct ospf6_damp_info **reuse_list_array;
+};
+
+int ospf6_damp_reuse_timer (struct thread *);
+void ospf6_damp_event_up   (u_short type, struct prefix *name,
+                           int (*exec_up)   (void *), void *target);
+void ospf6_damp_event_down (u_short type, struct prefix *name,
+                           int (*exec_down) (void *), void *target);
+
+void ospf6_damp_config_write (struct vty *);
+void ospf6_damp_init ();
+
diff -x CVS -urN ospf6d.old/ospf6_dbex.c ospf6d/ospf6_dbex.c
--- ospf6d.old/ospf6_dbex.c	Sat Apr 26 23:17:47 2003
+++ ospf6d/ospf6_dbex.c	Sat Nov  9 11:25:30 2002
@@ -230,12 +230,11 @@
   ismore_recent = -1;
   recent_reason = "no instance";
 
+  zlog_info ("Receive LSA (header -> %p)", lsa_header);
+
   /* make lsa structure for received lsa */
   received = ospf6_lsa_create (lsa_header);
 
-  if (IS_OSPF6_DUMP_DBEX)
-    zlog_info ("Receive %s from %s", received->str, from->str);
-
   /* set LSA scope */
   if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (htons (lsa_header->type)))
     received->scope = from->ospf6_interface;
@@ -248,27 +247,24 @@
   cksum = ntohs (lsa_header->checksum);
   if (ntohs (ospf6_lsa_checksum (lsa_header)) != cksum)
     {
-      zlog_warn ("DBEX: LSA cksum wrong: %s checksum %#hx should be %#hx",
-                 received->str, cksum, ntohs (ospf6_lsa_checksum (lsa_header)));
+      if (IS_OSPF6_DUMP_DBEX)
+        zlog_info ("DBEX: received %s from %s%%%s"
+                   ": wrong checksum, drop",
+                   received->str, from->str,
+                   from->ospf6_interface->interface->name);
       ospf6_lsa_delete (received);
       return;
     }
 
-#if 0
-  /* (2) warn if unknown */
-  if (! ospf6_lsa_is_known_type (lsa_header))
-    zlog_warn ("[%s:%s] receive LSA unknown: %#x",
-               from->str, from->ospf6_interface->interface->name,
-               ntohs (lsa_header->type));
-#endif /*0*/
-
   /* (3) Ebit Missmatch: AS-External-LSA */
   if (lsa_header->type == htons (OSPF6_LSA_TYPE_AS_EXTERNAL) &&
       ospf6_area_is_stub (from->ospf6_interface->area))
     {
-      zlog_err ("DBEX: [%s:%s] receive LSA E-bit mismatch: %s",
-                 from->str, from->ospf6_interface->interface->name,
-                 received->str);
+      if (IS_OSPF6_DUMP_DBEX)
+        zlog_info ("DBEX: received %s from %s%%%s"
+                   ": E-bit mismatch, drop",
+                   received->str, from->str,
+                   from->ospf6_interface->interface->name);
       ospf6_lsa_delete (received);
       return;
     }
@@ -279,8 +275,10 @@
     {
       /* log */
       if (IS_OSPF6_DUMP_DBEX)
-        zlog_info ("Drop MaxAge LSA: no instance, no neighbor "
-                   "exchanging DB: %s", received->str);
+        zlog_info ("DBEX: received %s from %s%%%s"
+                   ": MaxAge, no instance, no neighbor exchange, drop",
+                   received->str, from->str,
+                   from->ospf6_interface->interface->name);
 
       /* a) Acknowledge back to neighbor (13.5) */
         /* Direct Acknowledgement */
@@ -312,18 +310,29 @@
 
       /* (a) MinLSArrival check */
       gettimeofday (&now, (struct timezone *)NULL);
-      if (have && now.tv_sec - have->installed.tv_sec <= OSPF6_MIN_LS_ARRIVAL)
+      if (have && SEC_TVDIFF (&now, &have->installed) < OSPF6_MIN_LS_ARRIVAL)
         {
-          if (IS_OSPF6_DUMP_DBEX)
-            zlog_info ("DBEX: [%s:%s] received LSA too soon: %s",
-                       from->str, from->ospf6_interface->interface->name,
-                       received->str);
+          //if (IS_OSPF6_DUMP_DBEX)
+            zlog_info ("DBEX: Receive new LSA from %s: %s seq: %#x age: %d "
+                       "within MinLSArrival, drop: %ld.%06ld",
+                       from->str, received->str,
+                       ntohl (received->header->seqnum),
+                       ntohs (received->header->age),
+                       now.tv_sec, now.tv_usec);
 
           /* this will do free this lsa */
           ospf6_lsa_delete (received);
           return;   /* examin next lsa */
         }
 
+      //if (IS_OSPF6_DUMP_DBEX)
+        zlog_info ("DBEX: Receive new LSA from %s: %s seq: %#x age: %d: "
+                   "%ld.%06ld",
+                   from->str, received->str,
+                   ntohl (received->header->seqnum),
+                   ntohs (received->header->age),
+                   now.tv_sec, now.tv_usec);
+
       /* (b) immediately flood */
       ospf6_dbex_flood (received, from);
 
@@ -344,18 +353,20 @@
       acktype = ack_type (received, ismore_recent, from);
       if (acktype == DIRECT_ACK)
         {
+          if (IS_OSPF6_DUMP_DBEX)
+            zlog_info ("DBEX: Direct Ack to %s", from->str);
           ospf6_dbex_acknowledge_direct (received, from);
         }
       else if (acktype == DELAYED_ACK)
         {
+          if (IS_OSPF6_DUMP_DBEX)
+            zlog_info ("DBEX: Delayed Ack to %s", from->str);
           ospf6_dbex_acknowledge_delayed (received, from->ospf6_interface);
         }
       else
         {
           if (IS_OSPF6_DUMP_DBEX)
-            zlog_info ("DBEX: [%s:%s] don't ack %s",
-                       from->str, from->ospf6_interface->interface->name,
-                       received->str);
+            zlog_info ("DBEX: No Ack to %s", from->str);
         }
 
       /* (f) */
@@ -413,6 +424,9 @@
                                     from->retrans_list);
       if (rem)
         {
+          if (IS_OSPF6_DUMP_DBEX)
+            zlog_info ("DBEX: Implied Ack from %s, (remove retrans)",
+                       from->str);
           SET_FLAG (received->flag, OSPF6_LSA_FLAG_IMPLIEDACK);
           ospf6_neighbor_retrans_remove (rem, from);
         }
@@ -421,18 +435,20 @@
       acktype = ack_type (received, ismore_recent, from);
       if (acktype == DIRECT_ACK)
         {
+          if (IS_OSPF6_DUMP_DBEX)
+            zlog_info ("DBEX: Direct Ack to %s", from->str);
           ospf6_dbex_acknowledge_direct (received, from);
         }
       else if (acktype == DELAYED_ACK)
         {
+          if (IS_OSPF6_DUMP_DBEX)
+            zlog_info ("DBEX: Delayed Ack to %s", from->str);
           ospf6_dbex_acknowledge_delayed (received, from->ospf6_interface);
         }
       else
         {
           if (IS_OSPF6_DUMP_DBEX)
-            zlog_info ("DBEX: [%s:%s] will no ack %s",
-                       from->str, from->ospf6_interface->interface->name,
-                       received->str);
+            zlog_info ("DBEX: No Ack to %s", from->str);
         }
       ospf6_lsa_delete (received);
     }
@@ -443,6 +459,9 @@
       if (! IS_LSA_MAXAGE (received) ||
           received->lsa_hdr->lsh_seqnum != MAX_SEQUENCE_NUMBER)
         {
+          if (IS_OSPF6_DUMP_DBEX)
+            zlog_info ("DBEX: database is more recent: send back to %s",
+                       from->str);
           ospf6_send_lsupdate_direct (have, from);
         }
       ospf6_lsa_delete (received);
@@ -455,83 +474,52 @@
           struct ospf6_neighbor *from)
 {
   struct ospf6_interface *ospf6_interface;
-  struct ospf6_neighbor *nbr;
-  listnode n, m;
+  struct ospf6_lsa *have;
+  int count;
 
   assert (from && from->ospf6_interface);
   ospf6_interface = from->ospf6_interface;
 
   if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_FLOODBACK))
+    return NO_ACK;
+
+  if (ismore_recent < 0)
     {
+      if (ospf6_interface->state != IFS_BDR)
+        return DELAYED_ACK;
+
+      if (ospf6_interface->dr == from->router_id)
+        return DELAYED_ACK;
       return NO_ACK;
     }
-  else if (ismore_recent < 0 &&
-           ! CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_FLOODBACK))
-    {
-      if (ospf6_interface->state == IFS_BDR)
-        {
-          if (ospf6_interface->dr == from->router_id)
-            {
-              return DELAYED_ACK;
-            }
-          else
-            {
-              return NO_ACK;
-            }
-        }
-      else
-        {
-          return DELAYED_ACK;
-        }
-    }
-  else if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_DUPLICATE) &&
-           CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_IMPLIEDACK))
-    {
-      if (ospf6_interface->state == IFS_BDR)
-        {
-          if (ospf6_interface->dr == from->router_id)
-            {
-              return DELAYED_ACK;
-            }
-          else
-            {
-              return NO_ACK;
-            }
-        }
-      else
-        {
-          return NO_ACK;
-        }
-    }
-  else if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_DUPLICATE) &&
-           ! CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_IMPLIEDACK))
-    {
-      return DIRECT_ACK;
-    }
-  else if (IS_LSA_MAXAGE (newp))
+
+  if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_DUPLICATE) &&
+      CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_IMPLIEDACK))
     {
-      if (! ospf6_lsdb_lookup (newp->header->type, newp->header->id,
-                               newp->header->adv_router,
-                               ospf6_lsa_get_scope (newp->header->type,
-                                                    from->ospf6_interface)))
-        {
-          for (n = listhead (from->ospf6_interface->area->if_list);
-               n; nextnode (n))
-            {
-              ospf6_interface = (struct ospf6_interface *) getdata (n);
-              for (m = listhead (ospf6_interface->neighbor_list);
-                   m; nextnode (m))
-                {
-                  nbr = (struct ospf6_neighbor *) getdata (m);
-                  if (nbr->state == NBS_EXCHANGE || nbr->state == NBS_LOADING)
-                    {
-                      return NO_ACK;
-                    }
-                }
-            }
-          return DIRECT_ACK;
-        }
+      if (ospf6_interface->state != IFS_BDR)
+        return NO_ACK;
+
+      if (ospf6_interface->dr == from->router_id)
+        return DELAYED_ACK;
+
+      return NO_ACK;
     }
+
+  if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_DUPLICATE) &&
+      ! CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_IMPLIEDACK))
+    return DIRECT_ACK;
+
+  have = ospf6_lsdb_lookup (newp->header->type, newp->header->id,
+                            newp->header->adv_router,
+                            ospf6_lsa_get_scope (newp->header->type,
+                                                 from->ospf6_interface));
+
+  count = 0;
+  ospf6->foreach_nei (ospf6, &count, NBS_EXCHANGE, ospf6_count_state);
+  ospf6->foreach_nei (ospf6, &count, NBS_LOADING, ospf6_count_state);
+
+  if (IS_LSA_MAXAGE (newp) && have == NULL && count == 0)
+    return DIRECT_ACK;
  
   return NO_ACK;
 }
@@ -600,11 +588,13 @@
 
   /* (2) */
   if (addretrans == 0)
+    return; /* examin next interface */
+
+  if (from && from->ospf6_interface == o6i)
     {
-      return; /* examin next interface */
-    }
-  else if (from && from->ospf6_interface == o6i)
-    {
+      if (IS_OSPF6_DUMP_DBEX)
+        zlog_info ("DBEX: flood back %s to %s",
+                   lsa->str, o6i->interface->name);
       /* note occurence of floodback */
       SET_FLAG (lsa->flag, OSPF6_LSA_FLAG_FLOODBACK);
     }
@@ -624,7 +614,7 @@
     return; /* examin next interface */
 
   if (IS_OSPF6_DUMP_DBEX)
-    zlog_info ("  Flood to interface %s", o6i->interface->name);
+    zlog_info ("Flood to interface %s", o6i->interface->name);
 
   /* (5) send LinkState Update */
   ospf6_send_lsupdate_flood (lsa, o6i);
@@ -678,14 +668,13 @@
 
   lsa_header = (struct ospf6_lsa_header *) lsa->lsa_hdr;
 
-  if (IS_OSPF6_DUMP_DBEX)
-    zlog_info ("Flood: %s", lsa->str);
-
   if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (ntohs (lsa_header->type)))
     {
       o6i = (struct ospf6_interface *) lsa->scope;
       assert (o6i);
 
+      if (IS_OSPF6_DUMP_DBEX)
+        zlog_info ("Flood Linklocal: %s", o6i->interface->name);
       ospf6_dbex_flood_linklocal (lsa, o6i, from);
     }
   else if (OSPF6_LSA_IS_SCOPE_AREA (ntohs (lsa_header->type)))
@@ -693,6 +682,8 @@
       o6a = (struct ospf6_area *) lsa->scope;
       assert (o6a);
 
+      if (IS_OSPF6_DUMP_DBEX)
+        zlog_info ("Flood Area: %s", o6a->str);
       ospf6_dbex_flood_area (lsa, o6a, from);
     }
   else if (OSPF6_LSA_IS_SCOPE_AS (ntohs (lsa_header->type)))
@@ -700,6 +691,8 @@
       o6 = (struct ospf6 *) lsa->scope;
       assert (o6);
 
+      if (IS_OSPF6_DUMP_DBEX)
+        zlog_info ("Flood AS");
       ospf6_dbex_flood_as (lsa, o6, from);
     }
   else
diff -x CVS -urN ospf6d.old/ospf6_interface.c ospf6d/ospf6_interface.c
--- ospf6d.old/ospf6_interface.c	Sat Apr 26 23:17:47 2003
+++ ospf6d/ospf6_interface.c	Sat Nov  9 13:26:03 2002
@@ -126,6 +126,9 @@
 
   CALL_ADD_HOOK (&interface_hook, o6i);
 
+  /* Get the interface's link-local if any */
+  ospf6_interface_address_update(ifp);
+
   return o6i;
 }
 
diff -x CVS -urN ospf6d.old/ospf6_lsa.c ospf6d/ospf6_lsa.c
--- ospf6d.old/ospf6_lsa.c	Sat Apr 26 23:17:47 2003
+++ ospf6d/ospf6_lsa.c	Sat Nov  9 11:25:30 2002
@@ -51,7 +51,6 @@
 #include "ospf6_area.h"
 #include "ospf6_interface.h"
 #include "ospf6_neighbor.h"
-#include "ospf6_redistribute.h"
 #include "ospf6_ism.h"
 #include "ospf6_nsm.h"
 #include "ospf6_dbex.h"
@@ -142,8 +141,11 @@
 
   lsa->birth.tv_sec = now.tv_sec - ntohs (lsa->header->age);
   lsa->birth.tv_usec = now.tv_usec;
-  lsa->expire = thread_add_timer (master, ospf6_lsa_expire, lsa,
-                                  lsa->birth.tv_sec + MAXAGE - now.tv_sec);
+  if (ntohs (lsa->header->age) != MAXAGE)
+    lsa->expire = thread_add_timer (master, ospf6_lsa_expire, lsa,
+                                    lsa->birth.tv_sec + MAXAGE - now.tv_sec);
+  else
+    lsa->expire = NULL;
   return;
 }
 
@@ -692,38 +694,6 @@
     ospf6_lsa_delete (lsa);
 }
 
-/* check necessity to update LSA:
-   returns 1 if it's necessary to reoriginate */
-static int
-ospf6_lsa_is_really_reoriginate (struct ospf6_lsa *new)
-{
-  struct ospf6_lsa *old;
-  int diff;
-
-  /* find previous LSA */
-  old = ospf6_lsdb_lookup (new->header->type, new->header->id,
-                           new->header->adv_router, new->scope);
-  if (! old)
-    return 1;
-
-  /* Check if this is refresh */
-  if (CHECK_FLAG (old->flag, OSPF6_LSA_FLAG_REFRESH))
-    {
-      zlog_warn ("LSA: reoriginate: %s: Refresh", new->str);
-      return 1;
-    }
-
-  /* Are these contents different ? */
-  diff = ospf6_lsa_differ (new, old);
-
-  if (diff)
-    return 1;
-
-  if (IS_OSPF6_DUMP_LSA)
-    zlog_info ("LSA: Suppress updating %s", new->str);
-  return 0;
-}
-
 void
 ospf6_lsa_originate (u_int16_t type, u_int32_t id, u_int32_t adv_router,
                      char *data, int data_len, void *scope)
@@ -731,6 +701,7 @@
   char buffer[MAXLSASIZE];
   struct ospf6_lsa_header *lsa_header;
   struct ospf6_lsa *lsa;
+  struct ospf6_lsa *old;
 
   assert (data_len <= sizeof (buffer) - sizeof (struct ospf6_lsa_header));
 
@@ -754,18 +725,37 @@
 
   /* create LSA */
   lsa = ospf6_lsa_create ((struct ospf6_lsa_header *) buffer);
-  lsa->refresh = thread_add_timer (master, ospf6_lsa_refresh, lsa,
-                                   OSPF6_LS_REFRESH_TIME);
   lsa->scope = scope;
 
-  if (ospf6_lsa_is_really_reoriginate (lsa))
-    {
-      ospf6_dbex_remove_from_all_retrans_list (lsa);
-      ospf6_dbex_flood (lsa, NULL);
-      ospf6_lsdb_install (lsa);
+  /* find previous LSA */
+  old = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id,
+                           lsa->header->adv_router, lsa->scope);
+  if (old)
+    {
+      /* Check if this is neither different instance nor refresh, return */
+      if (! CHECK_FLAG (old->flag, OSPF6_LSA_FLAG_REFRESH) &&
+          ! ospf6_lsa_differ (lsa, old))
+        {
+          if (IS_OSPF6_DUMP_LSA)
+            zlog_info ("LSA: Suppress updating %s", lsa->str);
+          ospf6_lsa_delete (lsa);
+          return;
+        }
     }
-  else
-    ospf6_lsa_delete (lsa);
+
+  lsa->refresh = thread_add_timer (master, ospf6_lsa_refresh, lsa,
+                                   OSPF6_LS_REFRESH_TIME);
+  gettimeofday (&lsa->originated, NULL);
+
+  //if (IS_OSPF6_DUMP_LSA)
+    zlog_info ("LSA: originate %s seq: %#x age: %hu %ld.%06ld",
+               lsa->str, ntohl (lsa->header->seqnum),
+               ospf6_lsa_age_current (lsa),
+               lsa->originated.tv_sec, lsa->originated.tv_usec);
+
+  ospf6_dbex_remove_from_all_retrans_list (lsa);
+  ospf6_dbex_flood (lsa, NULL);
+  ospf6_lsdb_install (lsa);
 }
 
 
@@ -1130,14 +1120,32 @@
   return 0;
 }
 
-void
-ospf6_lsa_router_update (u_int32_t area_id)
+u_long
+ospf6_lsa_has_elasped (u_int16_t type, u_int32_t id,
+                       u_int32_t adv_router, void *scope)
+{
+  struct ospf6_lsa *old;
+  struct timeval now;
+
+  if (adv_router != ospf6->router_id)
+    zlog_info ("LSA: Router-ID changed ?");
+
+  old = ospf6_lsdb_lookup (type, id, adv_router, scope);
+  if (! old)
+    return OSPF6_LSA_MAXAGE;
+
+  gettimeofday (&now, NULL);
+  return ((u_long) SEC_TVDIFF (&now, &old->originated));
+}
+
+int
+ospf6_lsa_originate_router (struct thread *thread)
 {
   char buffer [MAXLSASIZE];
   u_int16_t size;
-  struct ospf6_lsa *old;
   struct ospf6_area *o6a;
   int count;
+  u_int32_t area_id;
 
   struct ospf6_router_lsa *router_lsa;
   struct ospf6_router_lsd *router_lsd;
@@ -1145,22 +1153,22 @@
   struct ospf6_interface *o6i;
   struct ospf6_neighbor *o6n = NULL;
 
+  area_id = (u_int32_t) THREAD_ARG (thread);
+
   o6a = ospf6_area_lookup (area_id, ospf6);
   if (! o6a)
     {
       inet_ntop (AF_INET, &area_id, buffer, sizeof (buffer));
       if (IS_OSPF6_DUMP_LSA)
-        zlog_warn ("Update Router-LSA: No such area: %s", buffer);
-      return;
+        zlog_info ("LSA: Update Router-LSA: No such area: %s", buffer);
+      return 0;
     }
 
-  if (IS_OSPF6_DUMP_LSA)
-    zlog_info ("Update Router-LSA: for Area %s", o6a->str);
+  /* clear thread */
+  o6a->thread_router_lsa = NULL;
 
-  /* find previous LSA */
-  /* xxx, there may be multiple Router-LSAs */
-  old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_ROUTER),
-                           htonl (0), o6a->ospf6->router_id, o6a);
+  if (IS_OSPF6_DUMP_LSA)
+    zlog_info ("LSA: originate Router-LSA for Area %s", o6a->str);
 
   size = sizeof (struct ospf6_router_lsa);
   memset (buffer, 0, sizeof (buffer));
@@ -1277,6 +1285,42 @@
   ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_ROUTER),
                        htonl (0), o6a->ospf6->router_id,
                        (char *) router_lsa, size, o6a);
+  return 0;
+}
+
+void
+ospf6_lsa_schedule_router (struct ospf6_area *area)
+{
+  u_long elasped_time, time = 0;
+
+  if (area->thread_router_lsa)
+    {
+      if (IS_OSPF6_DUMP_LSA)
+        zlog_info ("LSA: schedule: Router-LSA for Area %s: another thread",
+                   area->str);
+      return;
+    }
+
+  elasped_time =
+    ospf6_lsa_has_elasped (htons (OSPF6_LSA_TYPE_ROUTER), htonl (0),
+                           area->ospf6->router_id, area);
+  if (elasped_time < OSPF6_MIN_LS_INTERVAL)
+    time = (u_long) (OSPF6_MIN_LS_INTERVAL - elasped_time);
+  else
+    time = 0;
+
+  if (IS_OSPF6_DUMP_LSA)
+    zlog_info ("LSA: schedule: Router-LSA for Area %s after %lu sec",
+               area->str, time);
+
+  if (time)
+    area->thread_router_lsa =
+      thread_add_timer (master, ospf6_lsa_originate_router,
+                        (void *) area->area_id, time);
+  else
+    area->thread_router_lsa =
+      thread_add_event (master, ospf6_lsa_originate_router,
+                        (void *) area->area_id, 0);
 }
 
 int
@@ -1284,7 +1328,7 @@
 {
   struct ospf6_neighbor *o6n = neighbor;
   if (o6n->ospf6_interface->area)
-    ospf6_lsa_router_update (o6n->ospf6_interface->area->area_id);
+    ospf6_lsa_schedule_router (o6n->ospf6_interface->area);
   return 0;
 }
 
@@ -1293,7 +1337,7 @@
 {
   struct ospf6_interface *o6i = interface;
   if (o6i->area)
-    ospf6_lsa_router_update (o6i->area->area_id);
+    ospf6_lsa_schedule_router (o6i->area);
   return 0;
 }
 
@@ -1301,7 +1345,7 @@
 ospf6_lsa_router_hook_area (void *area)
 {
   struct ospf6_area *o6a = area;
-  ospf6_lsa_router_update (o6a->area_id);
+  ospf6_lsa_schedule_router (o6a);
   return 0;
 }
 
@@ -1315,7 +1359,7 @@
   for (node = listhead (o6->area_list); node; nextnode (node))
     {
       o6a = getdata (node);
-      ospf6_lsa_router_update (o6a->area_id);
+      ospf6_lsa_schedule_router (o6a);
     }
   return 0;
 }
@@ -1327,7 +1371,7 @@
   struct ospf6_area *o6a;
 
   o6a = lsa->scope;
-  ospf6_lsa_router_update (o6a->area_id);
+  ospf6_lsa_schedule_router (o6a);
   return 0;
 }
 
diff -x CVS -urN ospf6d.old/ospf6_lsa.h ospf6d/ospf6_lsa.h
--- ospf6d.old/ospf6_lsa.h	Sat Apr 26 23:17:47 2003
+++ ospf6d/ospf6_lsa.h	Sat Nov  9 11:25:30 2002
@@ -25,6 +25,13 @@
 
 #include "ospf6_hook.h"
 
+#define ONESECOND_USEC  1000000
+#define USEC_TVDIFF(tv2,tv1) \
+  (((tv2)->tv_sec - (tv1)->tv_sec) * ONESECOND_USEC \
+   + ((tv2)->tv_usec - (tv1)->tv_usec))
+#define SEC_TVDIFF(tv2,tv1) \
+  (USEC_TVDIFF((tv2),(tv1)) / ONESECOND_USEC)
+
 /* LSA definition */
 
 #define MAXLSASIZE   1024
@@ -211,6 +218,7 @@
   unsigned char          flag;      /* to decide ack type and refresh */
   struct timeval         birth;     /* tv_sec when LS age 0 */
   struct timeval         installed; /* installed time */
+  struct timeval         originated; /* installed time */
   struct thread         *expire;
   struct thread         *refresh;   /* For self-originated LSA */
   u_int32_t              from;      /* from which neighbor */
@@ -397,22 +405,22 @@
 
 u_short ospf6_lsa_checksum (struct ospf6_lsa_header *);
 
-void ospf6_lsa_update_router (u_int32_t area_id);
 void ospf6_lsa_update_network (char *ifname);
 void ospf6_lsa_update_link (char *ifname);
 void ospf6_lsa_update_as_external (u_int32_t ls_id);
 void ospf6_lsa_update_intra_prefix_transit (char *ifname);
 void ospf6_lsa_update_intra_prefix_stub (u_int32_t area_id);
 
-void ospf6_lsa_reoriginate (struct ospf6_lsa *);
-void
-ospf6_lsa_originate (u_int16_t, u_int32_t, u_int32_t, char *, int, void *);
-
 u_int16_t ospf6_lsa_get_scope_type (u_int16_t);
 int ospf6_lsa_is_known_type (struct ospf6_lsa_header *lsa_header);
 
 char *ospf6_lsa_type_string (u_int16_t type, char *buf, int bufsize);
 char *ospf6_lsa_router_bits_string (u_char router_bits, char *buf, int size);
+
+u_long
+ospf6_lsa_has_elasped (u_int16_t, u_int32_t, u_int32_t, void *);
+void
+ospf6_lsa_originate (u_int16_t, u_int32_t, u_int32_t, char *, int, void *);
 
 #endif /* OSPF6_LSA_H */
 
diff -x CVS -urN ospf6d.old/ospf6_message.c ospf6d/ospf6_message.c
--- ospf6d.old/ospf6_message.c	Sat Apr 26 23:17:47 2003
+++ ospf6d/ospf6_message.c	Sat Nov  9 11:25:30 2002
@@ -1108,14 +1108,14 @@
   if (!o6n)
     {
       if (IS_OSPF6_DUMP_LSACK)
-        zlog_info ("  neighbor not found, reject");
+        zlog_info ("LSACK: neighbor not found, reject");
       return;
     }
 
   if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr)))
     {
-      if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
-        zlog_info ("From Secondary I/F of the neighbor: ignore");
+      if (IS_OSPF6_DUMP_LSACK)
+        zlog_info ("LSACK: From Secondary I/F of the neighbor: ignore");
       return;
     }
 
@@ -1123,7 +1123,7 @@
   if (o6n->state < NBS_EXCHANGE)
     {
       if (IS_OSPF6_DUMP_LSACK)
-        zlog_info ("  neighbor state less than Exchange, reject");
+        zlog_info ("LSACK: neighbor state less than Exchange, reject");
       return;
     }
 
@@ -1141,7 +1141,7 @@
       if (!copy)
         {
           if (IS_OSPF6_DUMP_LSACK)
-            zlog_info ("no database copy, ignore");
+            zlog_info ("LSACK: no database copy, ignore");
           continue;
         }
 
@@ -1152,7 +1152,7 @@
       if (rem == NULL)
         {
           if (IS_OSPF6_DUMP_LSACK)
-            zlog_info ("not on %s's retranslist, ignore", o6n->str);
+            zlog_info ("LSACK: not on %s's retranslist, ignore", o6n->str);
           continue;
         }
 
@@ -1167,7 +1167,13 @@
         {
           /* Log the questionable acknowledgement,
              and examine the next one. */
-          zlog_warn ("LSAck: questionable acknowledge: LSAs differ");
+          zlog_info ("LSACK: questionable acknowledge: %s", copy->str);
+          zlog_info ("LSACK:   received: seq: %#x age: %hu",
+                     ntohl (lsa->header->seqnum),
+                     ntohs (lsa->header->age));
+          zlog_info ("LSACK:   instance: seq: %#x age: %hu",
+                     ntohl (copy->header->seqnum),
+                     ospf6_lsa_age_current (copy));
         }
 
       /* release temporary LSA from Ack message */
@@ -1242,6 +1248,22 @@
       return;
     }
 
+  /* message type check */
+  type = (ospf6_header->type >= OSPF6_MESSAGE_TYPE_MAX ?
+          OSPF6_MESSAGE_TYPE_UNKNOWN : ospf6_header->type);
+
+  /* log */
+  if (IS_OSPF6_DUMP_MESSAGE (type))
+    {
+      char srcname[64], dstname[64];
+      inet_ntop (AF_INET6, dst, dstname, sizeof (dstname));
+      inet_ntop (AF_INET6, src, srcname, sizeof (srcname));
+      zlog_info ("Receive %s on %s",
+                 ospf6_message_type_string[type], o6i->interface->name);
+      zlog_info ("    %s -> %s", srcname, dstname);
+      ospf6_message_log (message);
+    }
+
   /* router id check */
   router_id = ospf6_header->router_id;
   if (ospf6_header->router_id == o6i->area->ospf6->router_id)
@@ -1252,10 +1274,6 @@
       return;
     }
 
-  /* message type check */
-  type = (ospf6_header->type >= OSPF6_MESSAGE_TYPE_MAX ?
-          OSPF6_MESSAGE_TYPE_UNKNOWN : ospf6_header->type);
-
   /* octet statistics relies on some asumption:
        on ethernet, no IPv6 Extention header, etc */
 #define OSPF6_IP6_HEADER_SIZE   40
@@ -1280,12 +1298,14 @@
   struct ospf6_header ospf6_header;
   char buffer[OSPF6_MESSAGE_RECEIVE_BUFSIZE];
   struct ospf6_interface *o6i;
-  char srcname[64], dstname[64];
   unsigned char type;
 
   /* get socket */
   sockfd = THREAD_FD (thread);
 
+  /* add next read thread */
+  thread_add_read (master, ospf6_receive, NULL, sockfd);
+
   /* initialize */
   OSPF6_MESSAGE_CLEAR (message);
   memset (&ospf6_header, 0, sizeof (struct ospf6_header));
@@ -1302,22 +1322,10 @@
   o6i = ospf6_interface_lookup_by_index (ifindex);
   if (!o6i || !o6i->area)
     {
-      zlog_warn ("*** received interface ospf6 disabled");
-      thread_add_read (master, ospf6_receive, NULL, sockfd);
+      //zlog_warn ("*** received interface ospf6 disabled");
       return 0;
     }
 
-  /* log */
-  if (IS_OSPF6_DUMP_MESSAGE (type))
-    {
-      inet_ntop (AF_INET6, &dst, dstname, sizeof (dstname));
-      inet_ntop (AF_INET6, &src, srcname, sizeof (srcname));
-      zlog_info ("Receive %s on %s",
-                 ospf6_message_type_string[type], o6i->interface->name);
-      zlog_info ("    %s -> %s", srcname, dstname);
-      ospf6_message_log (message);
-    }
-
   /* if not passive, process message */
   if (! CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE))
     ospf6_message_process (message, &src, &dst, o6i);
@@ -1325,9 +1333,6 @@
     zlog_info ("Ignore message on passive interface %s",
                o6i->interface->name);
 
-  /* add next read thread */
-  thread_add_read (master, ospf6_receive, NULL, sockfd);
-
   return 0;
 }
 
@@ -1828,6 +1833,9 @@
     return 0;
   lsupdate.lsupdate_num = htonl (lsupdate.lsupdate_num);
 
+  if (IS_OSPF6_DUMP_LSUPDATE)
+    zlog_info ("MESSAGE: retrsnsmit LSUpdate to %s", o6n->str);
+
   /* statistics */
   o6n->ospf6_stat_retrans_lsupdate++;
 
@@ -1915,6 +1923,9 @@
 
   o6i = THREAD_ARG (thread);
   assert (o6i);
+
+  if (IS_OSPF6_DUMP_LSACK)
+    zlog_info ("LSACK: Delayed LSAck for %s\n", o6i->interface->name);
 
   o6i->thread_send_lsack_delayed = (struct thread *) NULL;
 
diff -x CVS -urN ospf6d.old/ospf6_neighbor.c ospf6d/ospf6_neighbor.c
--- ospf6d.old/ospf6_neighbor.c	Sat Apr 26 23:17:47 2003
+++ ospf6d/ospf6_neighbor.c	Sat Nov  9 11:25:30 2002
@@ -179,6 +179,13 @@
     }
 
   ospf6_lsdb_remove (lsa, nei->retrans_list);
+
+  if (nei->retrans_list->count == 0)
+    {
+      if (nei->send_update)
+        thread_cancel (nei->send_update);
+      nei->send_update = NULL;
+    }
 }
 
 void
diff -x CVS -urN ospf6d.old/ospf6_network.c ospf6d/ospf6_network.c
--- ospf6d.old/ospf6_network.c	Sat Apr 26 23:17:47 2003
+++ ospf6d/ospf6_network.c	Tue Oct  1 10:28:08 2002
@@ -255,8 +255,10 @@
                   &mreq6, sizeof (mreq6)) < 0)
     zlog_warn ("Network: Leave AllSPFRouters on ifindex %d Failed: %s",
                ifindex, strerror (errno));
+#if 0
   else
     zlog_info ("Network: Leave AllSPFRouters on ifindex %d", ifindex);
+#endif
 }
 
 void
@@ -273,8 +275,10 @@
                   &mreq6, sizeof (mreq6)) < 0)
     zlog_warn ("Network: Join AllDRouters on ifindex %d Failed: %s",
                ifindex, strerror (errno));
+#if 0
   else
     zlog_info ("Network: Join AllDRouters on ifindex %d", ifindex);
+#endif
 }
 
 void
@@ -290,8 +294,10 @@
   if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
                   &mreq6, sizeof (mreq6)) < 0)
     zlog_warn ("Network: Leave AllDRouters on ifindex %d Failed", ifindex);
+#if 0
   else
     zlog_info ("Network: Leave AllDRouters on ifindex %d", ifindex);
+#endif
 }
 
 /* setsockopt ReUseAddr to on */
diff -x CVS -urN ospf6d.old/ospf6_route.h ospf6d/ospf6_route.h
--- ospf6d.old/ospf6_route.h	Sat Apr 26 23:17:47 2003
+++ ospf6d/ospf6_route.h	Tue Oct  1 00:41:10 2002
@@ -186,6 +186,9 @@
 void ospf6_route_table_freeze (struct ospf6_route_table *);
 void ospf6_route_table_thaw (struct ospf6_route_table *);
 
+void ospf6_route_log_request (char *what, char *where,
+                              struct ospf6_route_req *request);
+
 void
 ospf6_route_hook_register (void (*add)    (struct ospf6_route_req *),
                            void (*change) (struct ospf6_route_req *),
diff -x CVS -urN ospf6d.old/ospf6_routemap.c ospf6d/ospf6_routemap.c
--- ospf6d.old/ospf6_routemap.c	Sat Apr 26 23:17:47 2003
+++ ospf6d/ospf6_routemap.c	Tue Oct  1 00:41:10 2002
@@ -22,9 +22,6 @@
 
 #include <zebra.h>
 
-#if 1
-#include "ospf6d.h"
-#else
 #include "log.h"
 #include "memory.h"
 #include "linklist.h"
@@ -32,11 +29,13 @@
 #include "command.h"
 #include "vty.h"
 #include "routemap.h"
+#include "table.h"
 #include "plist.h"
 
-#include "ospf6_top.h"
-#include "ospf6_redistribute.h"
-#endif
+#include "ospf6_route.h"
+#include "ospf6_prefix.h"
+#include "ospf6_lsa.h"
+#include "ospf6_asbr.h"
 
 route_map_result_t
 ospf6_routemap_rule_match_address_prefixlist (void *rule,
@@ -70,7 +69,8 @@
   XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
 }
 
-struct route_map_rule_cmd ospf6_routemap_rule_match_address_prefixlist_cmd =
+struct route_map_rule_cmd
+ospf6_routemap_rule_match_address_prefixlist_cmd =
 {
   "ipv6 address prefix-list",
   ospf6_routemap_rule_match_address_prefixlist,
@@ -83,15 +83,15 @@
                                      route_map_object_t type, void *object)
 {
   char *metric_type = rule;
-  struct ospf6_route_req *route = object;
+  struct ospf6_external_info *info = object;
 
   if (type != RMAP_OSPF6)
     return RMAP_OKAY;
 
   if (strcmp (metric_type, "type-2") == 0)
-    route->path.metric_type = 2;
+    info->metric_type = 2;
   else
-    route->path.metric_type = 1;
+    info->metric_type = 1;
 
   return RMAP_OKAY;
 }
@@ -108,7 +108,8 @@
   XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
 }
 
-struct route_map_rule_cmd ospf6_routemap_rule_set_metric_type_cmd =
+struct route_map_rule_cmd
+ospf6_routemap_rule_set_metric_type_cmd =
 {
   "metric-type",
   ospf6_routemap_rule_set_metric_type,
@@ -121,14 +122,12 @@
                                 route_map_object_t type, void *object)
 {
   char *metric = rule;
-  struct ospf6_route_req *route = object;
+  struct ospf6_external_info *info = object;
 
   if (type != RMAP_OSPF6)
     return RMAP_OKAY;
 
-  route->path.cost = atoi (metric);
-  route->path.cost_e2 = atoi (metric);
-
+  info->metric = atoi (metric);
   return RMAP_OKAY;
 }
 
@@ -144,7 +143,8 @@
   XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
 }
 
-struct route_map_rule_cmd ospf6_routemap_rule_set_metric_cmd =
+struct route_map_rule_cmd
+ospf6_routemap_rule_set_metric_cmd =
 {
   "metric",
   ospf6_routemap_rule_set_metric,
@@ -157,14 +157,14 @@
                                     route_map_object_t type, void *object)
 {
   char *forwarding = rule;
-  struct ospf6_route_req *route = object;
+  struct ospf6_external_info *info = object;
 
   if (type != RMAP_OSPF6)
     return RMAP_OKAY;
 
-  if (inet_pton (AF_INET6, forwarding, &route->nexthop.address) != 1)
+  if (inet_pton (AF_INET6, forwarding, &info->forwarding) != 1)
     {
-      memset (&route->nexthop.address, 0, sizeof (struct in6_addr));
+      memset (&info->forwarding, 0, sizeof (struct in6_addr));
       return RMAP_ERROR;
     }
 
@@ -183,7 +183,8 @@
   XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
 }
 
-struct route_map_rule_cmd ospf6_routemap_rule_set_forwarding_cmd =
+struct route_map_rule_cmd
+ospf6_routemap_rule_set_forwarding_cmd =
 {
   "forwarding-address",
   ospf6_routemap_rule_set_forwarding,
@@ -331,8 +332,8 @@
 {
   route_map_init ();
   route_map_init_vty ();
-  route_map_add_hook (ospf6_redistribute_routemap_update);
-  route_map_delete_hook (ospf6_redistribute_routemap_update);
+  route_map_add_hook (ospf6_asbr_routemap_update);
+  route_map_delete_hook (ospf6_asbr_routemap_update);
 
   route_map_install_match (&ospf6_routemap_rule_match_address_prefixlist_cmd);
   route_map_install_set (&ospf6_routemap_rule_set_metric_type_cmd);
diff -x CVS -urN ospf6d.old/ospf6_spf.c ospf6d/ospf6_spf.c
--- ospf6d.old/ospf6_spf.c	Sat Apr 26 23:17:47 2003
+++ ospf6d/ospf6_spf.c	Sat Nov  9 11:25:30 2002
@@ -281,7 +281,7 @@
 static struct in6_addr *
 ospf6_spf_get_ipaddr (u_int32_t id, u_int32_t adv_router, u_int32_t ifindex)
 {
-  char buf[64];
+  char buf[64], nhbuf[64];
   struct ospf6_interface *o6i;
   struct ospf6_neighbor *o6n;
   struct ospf6_lsa *lsa;
@@ -303,26 +303,30 @@
     lsa = node.lsa;
 
   /* return Linklocal Address field if the Link-LSA exists */
-  if (lsa)
+  if (lsa && lsa->header->adv_router == adv_router)
     {
       struct ospf6_link_lsa *link_lsa;
       link_lsa = (struct ospf6_link_lsa *) (lsa->header + 1);
       return &link_lsa->llsa_linklocal;
     }
 
-  zlog_warn ("SPF: Can't find Link-LSA for %s, "
-             "use source address from his packet",
+  zlog_warn ("SPF: Can't find Link-LSA for %s",
              inet_ntop (AF_INET, &adv_router, buf, sizeof (buf)));
 
   o6n = ospf6_neighbor_lookup (adv_router, o6i);
   if (! o6n)
     {
       inet_ntop (AF_INET, &adv_router, buf, sizeof (buf));
-      zlog_err ("SPF: Can't find neighbor %s in %s",
+      zlog_err ("SPF: Can't find neighbor %s in %s, "
+                "unable to find his linklocal address",
                 buf, o6i->interface->name);
       return (struct in6_addr *) NULL;
     }
 
+  zlog_warn ("SPF: use packet's source address for %s's nexthop: %s",
+             inet_ntop (AF_INET, &adv_router, buf, sizeof (buf)),
+             inet_ntop (AF_INET6, &o6n->hisaddr, nhbuf, sizeof (nhbuf)));
+
   return &o6n->hisaddr;
 }
 
@@ -478,18 +482,22 @@
       inet_ntop (AF_INET, &adv_router, buf_router, sizeof (buf_router));
       inet_ntop (AF_INET, &id, buf_id, sizeof (buf_id));
 
-      if (type == htons (OSPF6_LSA_TYPE_ROUTER))
-        zlog_err ("SPF: Can't find LSA for W (%s *): not found",
-                  buf_router);
-      else
-        zlog_err ("SPF: Can't find LSA for W (%s %s): not found",
-                  buf_router, buf_id);
+      if (IS_OSPF6_DUMP_SPF)
+        {
+          if (type == htons (OSPF6_LSA_TYPE_ROUTER))
+            zlog_info ("SPF: Can't find LSA for W (%s *): not found",
+                      buf_router);
+          else
+            zlog_info ("SPF: Can't find LSA for W (%s %s): not found",
+                      buf_router, buf_id);
+        }
       return (struct ospf6_vertex *) NULL;
     }
 
   if (IS_LSA_MAXAGE (lsa))
     {
-      zlog_err ("SPF: Associated LSA for W is MaxAge: %s", lsa->str);
+      if (IS_OSPF6_DUMP_SPF)
+        zlog_info ("SPF: Associated LSA for W is MaxAge: %s", lsa->str);
       return (struct ospf6_vertex *) NULL;
     }
 
@@ -504,8 +512,9 @@
     }
   if (! backreference)
     {
-      zlog_err ("SPF: Back reference failed: V: %s, W: %s",
-                V->lsa->str, lsa->str);
+      if (IS_OSPF6_DUMP_SPF)
+        zlog_info ("SPF: Back reference failed: V: %s, W: %s",
+                   V->lsa->str, lsa->str);
       return (struct ospf6_vertex *) NULL;
     }
 
diff -x CVS -urN ospf6d.old/ospf6_top.c ospf6d/ospf6_top.c
--- ospf6d.old/ospf6_top.c	Sat Apr 26 23:17:47 2003
+++ ospf6d/ospf6_top.c	Tue Oct  1 00:51:40 2002
@@ -43,7 +43,6 @@
 #include "ospf6_area.h"
 #include "ospf6_top.h"
 
-#include "ospf6_redistribute.h"
 #include "ospf6_route.h"
 #include "ospf6_zebra.h"
 
@@ -152,7 +151,7 @@
   vty_out (vty, " Supports only single TOS(TOS0) routes%s", VTY_NEWLINE);
 
   /* Redistribute config */
-  ospf6_redistribute_show_config (vty, ospf6);
+  ospf6_redistribute_show_config (vty);
 
   /* LSAs */
   vty_out (vty, " Number of AS scoped LSAs is %u%s",
@@ -250,9 +249,6 @@
 
   o6->lsdb = ospf6_lsdb_create ();
 
-  /* route table init */
-  ospf6_redistribute_init (o6);
-
   o6->foreach_area = ospf6_top_foreach_area;
   o6->foreach_if = ospf6_top_foreach_interface;
   o6->foreach_nei = ospf6_top_foreach_neighbor;
@@ -264,12 +260,14 @@
                              ospf6_top_topology_remove,
                              o6->topology_table);
 
+#if 0
   snprintf (namebuf, sizeof (namebuf), "External table");
   o6->external_table = ospf6_route_table_create (namebuf);
   ospf6_route_hook_register (ospf6_asbr_external_route_add,
                              ospf6_asbr_external_route_add,
                              ospf6_asbr_external_route_remove,
                              o6->external_table);
+#endif /*0*/
 
   snprintf (namebuf, sizeof (namebuf), "Top route table");
   o6->route_table = ospf6_route_table_create (namebuf);
diff -x CVS -urN ospf6d.old/ospf6_zebra.c ospf6d/ospf6_zebra.c
--- ospf6d.old/ospf6_zebra.c	Sat Apr 26 23:17:47 2003
+++ ospf6d/ospf6_zebra.c	Wed Oct  2 17:16:56 2002
@@ -22,7 +22,7 @@
 #include "ospf6d.h"
 
 #include "ospf6_interface.h"
-#include "ospf6_redistribute.h"
+#include "ospf6_asbr.h"
 
 #include "ospf6_linklist.h"
 
@@ -202,13 +202,14 @@
   struct stream *s;
   struct zapi_ipv6 api;
   unsigned long ifindex;
-  struct in6_addr nexthop;
   struct prefix_ipv6 p;
+  struct in6_addr *nexthop;
   char prefixstr[128], nexthopstr[128];
 
   s = zclient->ibuf;
   ifindex = 0;
-  memset (&nexthop, 0, sizeof (struct in6_addr));
+  nexthop = NULL;
+  memset (&api, 0, sizeof (api));
 
   /* Type, flags, message. */
   api.type = stream_getc (s);
@@ -225,7 +226,9 @@
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
     {
       api.nexthop_num = stream_getc (s);
-      stream_get (&nexthop, s, 16);
+      nexthop = (struct in6_addr *)
+        malloc (api.nexthop_num * sizeof (struct in6_addr));
+      stream_get (nexthop, s, api.nexthop_num * sizeof (struct in6_addr));
     }
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
     {
@@ -256,11 +259,15 @@
 		   zebra_route_name [api.type], prefixstr,
 		   nexthopstr, ifindex);
     }
-  
+ 
   if (command == ZEBRA_IPV6_ROUTE_ADD)
-    ospf6_redistribute_route_add (api.type, ifindex, &p);
+    ospf6_asbr_route_add (api.type, ifindex, (struct prefix *) &p,
+                          api.nexthop_num, nexthop);
   else
-    ospf6_redistribute_route_remove (api.type, ifindex, &p);
+    ospf6_asbr_route_remove (api.type, ifindex, (struct prefix *) &p);
+
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+    free (nexthop);
 
   return 0;
 }
@@ -448,10 +455,6 @@
 
           if (IS_OSPF6_DUMP_ZEBRA)
             zlog_info ("ZEBRA:   found alternative path to add");
-
-          linklist_remove (nexthop, nexthop_list);
-          XFREE (MTYPE_OSPF6_OTHER, nexthop);
-          assert (nexthop_list->count == 0);
 
           memcpy (&seconde_path, &route.path, sizeof (struct ospf6_path));
           type = ADD;
diff -x CVS -urN ospf6d.old/ospf6d.c ospf6d/ospf6d.c
--- ospf6d.old/ospf6d.c	Sat Apr 26 23:17:47 2003
+++ ospf6d/ospf6d.c	Mon Mar 24 17:45:16 2003
@@ -21,6 +21,8 @@
 
 #include "ospf6d.h"
 
+#include "ospf6_damp.h"
+
 /* global ospf6d variable */
 int  ospf6_sock;
 list iflist;
@@ -536,8 +538,8 @@
   return CMD_SUCCESS;
 }
 
-DEFUN (area_range,
-       area_range_cmd,
+DEFUN (ospf6_area_range,
+       ospf6_area_range_cmd,
        "area A.B.C.D range X:X::X:X/M",
        "OSPFv3 area parameters\n"
        "OSPFv3 area ID in IPv4 address format\n"
@@ -689,6 +691,7 @@
   vty_out (vty, " router-id %s%s", buf, VTY_NEWLINE);
 
   ospf6_redistribute_config_write (vty);
+  ospf6_damp_config_write (vty);
 
   for (j = listhead (ospf6->area_list); j; nextnode (j))
     {
@@ -745,7 +748,7 @@
   install_element (OSPF6_NODE, &no_interface_area_cmd);
   install_element (OSPF6_NODE, &passive_interface_cmd);
   install_element (OSPF6_NODE, &no_passive_interface_cmd);
-  install_element (OSPF6_NODE, &area_range_cmd);
+  install_element (OSPF6_NODE, &ospf6_area_range_cmd);
 
   /* Make empty list of top list. */
   if_init ();
@@ -757,6 +760,10 @@
   prefix_list_init ();
 
   ospf6_dump_init ();
+
+#ifdef HAVE_OSPF6_DAMP
+  ospf6_damp_init ();
+#endif /*HAVE_OSPF6_DAMP*/
 
   ospf6_hook_init ();
   ospf6_lsa_init ();
diff -x CVS -urN ospf6d.old/ospf6d.h ospf6d/ospf6d.h
--- ospf6d.old/ospf6d.h	Sat Apr 26 23:17:47 2003
+++ ospf6d/ospf6d.h	Fri Apr 25 11:40:31 2003
@@ -59,7 +59,6 @@
 #include "ospf6_neighbor.h"
 #include "ospf6_ism.h"
 #include "ospf6_nsm.h"
-#include "ospf6_redistribute.h"
 #include "ospf6_route.h"
 #include "ospf6_dbex.h"
 #include "ospf6_network.h"
@@ -74,7 +73,7 @@
 #define HASHVAL 64
 #define MAXIOVLIST 1024
 
-#define OSPF6_DAEMON_VERSION    "0.9.6l"
+#define OSPF6_DAEMON_VERSION    "0.9.6p"
 
 #define AF_LINKSTATE  0xff
 
