Ospf6d merge from Zebra repository with added privs stuff and merged
zclient changes.
diff --git a/ospf6d/.cvsignore b/ospf6d/.cvsignore
index 5e76e4d..cec4061 100644
--- a/ospf6d/.cvsignore
+++ b/ospf6d/.cvsignore
@@ -1,5 +1,4 @@
 Makefile
-Makefile.in
 *.o
 *.patch
 ospf6d
diff --git a/ospf6d/ChangeLog b/ospf6d/ChangeLog
index 0e9d7fc..b74dead 100644
--- a/ospf6d/ChangeLog
+++ b/ospf6d/ChangeLog
@@ -1,20 +1,17 @@
-2004-05-08 Paul Jakma <paul@dishone.st>
+2004-05-18  Hasso Tepper <hasso@estpak.ee>
 
-	* ospf6_zebra.c: Sync to zclient changes
-	
+	* *.*: Merge rewritten ospf6d from Zebra repository.
+	* ospf6_network.c, ospf6_main.c: Merged privs stuff back in.
+	* ospf6_zebra.c: Sync back to zclient changes.
+
+2003-08-18  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* *.[ch]: rewrite all source code from scratch
+	* ospf6d.h: version 0.9.7
+
 2003-08-11  Taisuke Sasaki <sasaki@soft.net.fujitsu.co.jp>
 
-	* ospf6_ism.c: DR Election bug fix.
-	
-2003-05-18 Hasso Tepper <hasso@estpak.ee>
-
-	* ospf6_{dump,interface,zebra}.c,ospf6d.c: show router and interface
-	nodes from ospf6d when using vtysh,  and don't show defaults in
-	interface node (from ^WIND patch).
-
-2003-04-23 Hasso Tepper <hasso@estpak.ee>
-          
-        * {ospf6_damp,ospf6d}.c: fix "router xxx" node commands in vtysh
+        * ospf6_ism.c: DR Election bug fix.
 
 2003-04-25  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
 
@@ -22,11 +19,6 @@
 	prefix of the obsolete LSA. It was wrong so fixed.
 	* version: 0.9.6p
 
-2003-04-19 Hasso Tepper <hasso@estpak.ee>
-
-	* rip_routemap.c: sync daemon's route-map commands to have same
-        syntax
-
 2002-11-09  Vincent Jardin  <jardin@6wind.com>
 
 	* ospf6_interface.c: update link-local address on interface creation.
diff --git a/ospf6d/Makefile.am b/ospf6d/Makefile.am
index 14b87af..de18391 100644
--- a/ospf6d/Makefile.am
+++ b/ospf6d/Makefile.am
@@ -8,22 +8,16 @@
 sbin_PROGRAMS = ospf6d
 
 libospf6_a_SOURCES = \
-	ospf6_dump.c ospf6d.c ospf6_interface.c ospf6_network.c \
-	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_routemap.c ospf6_proto.c \
-	ospf6_hook.c ospf6_asbr.c ospf6_bintree.c ospf6_linklist.c \
-	ospf6_abr.c ospf6_intra.c ospf6_damp.c
+	ospf6_network.c ospf6_message.c ospf6_lsa.c ospf6_lsdb.c \
+	ospf6_top.c ospf6_area.c ospf6_interface.c ospf6_neighbor.c \
+	ospf6_flood.c ospf6_route.c ospf6_intra.c ospf6_zebra.c \
+	ospf6_spf.c ospf6_proto.c ospf6_asbr.c ospf6d.c
 
 noinst_HEADERS = \
-	ospf6_area.h ospf6_dump.h ospf6_interface.h ospf6_lsa.h \
-	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_routemap.h \
-        ospf6_hook.h ospf6_asbr.h ospf6_bintree.h ospf6_linklist.h \
-	ospf6_abr.h ospf6_intra.h ospf6_damp.h
+	ospf6_network.h ospf6_message.h ospf6_lsa.h ospf6_lsdb.h \
+	ospf6_top.h ospf6_area.h ospf6_interface.h ospf6_neighbor.h \
+	ospf6_flood.h ospf6_route.h ospf6_intra.h ospf6_zebra.h \
+	ospf6_spf.h ospf6_proto.h ospf6_asbr.h ospf6d.h
 
 ospf6d_SOURCES = \
 	ospf6_main.c $(libospf6_a_SOURCES)
diff --git a/ospf6d/README b/ospf6d/README
index b3b4d16..883486f 100644
--- a/ospf6d/README
+++ b/ospf6d/README
@@ -1,6 +1,14 @@
 
 		  Zebra OSPF daemon for IPv6 network
 
+			     2003/08/18
+
+README for newer code is not yet. General usage should remain
+the same. For further usage, see command helps by typing '?'
+in vty, and then imagin ! ;p) Previous README contents follows.
+
+		  Zebra OSPF daemon for IPv6 network
+
 			     2001/12/20
 
 Zebra OSPF6d is OSPF version 3 daemon which is specified by
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
deleted file mode 100644
index 864e0c2..0000000
--- a/ospf6d/ospf6_abr.c
+++ /dev/null
@@ -1,655 +0,0 @@
-/*
- * Copyright (C) 2001 Yasuhiro Ohara
- *
- * 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 "ospf6d.h"
-
-#include "ospf6_dump.h"
-#include "ospf6_abr.h"
-
-static int abr_index;
-#define IS_OSPF6_DUMP_ABR (ospf6_dump_is_on (abr_index))
-
-#define ADD    0
-#define CHANGE 1
-#define REMOVE 2
-
-/* Inter-Area-Prefix-LSA Calculation */
-
-static struct ospf6_route_req *
-ospf6_abr_entry_lookup (struct ospf6_route_req *abr_entry,
-                        u_int32_t router_id, struct ospf6_area *area)
-{
-  struct prefix_ls abr_id;
-  char router_string[32];
-
-  inet_ntop (AF_INET, &router_id, router_string, sizeof (router_string));
-
-  //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;
-  abr_id.prefixlen = 64; /* xxx */
-  abr_id.id.s_addr = htonl (0);
-  abr_id.adv_router.s_addr = router_id;
-
-  ospf6_route_lookup (abr_entry, (struct prefix *) &abr_id,
-                      area->table_topology);
-
-  if (ospf6_route_end (abr_entry))
-    {
-      if (IS_OSPF6_DUMP_ABR)
-        zlog_info ("ABR:   Router %s not found in area %s",
-                   router_string, area->str);
-      return NULL;
-    }
-
-  if (abr_entry->path.area_id != area->area_id)
-    {
-      if (IS_OSPF6_DUMP_ABR)
-        zlog_info ("ABR: ABR area id mismatch");
-      return NULL;
-    }
-
-  if (! CHECK_FLAG (abr_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_B))
-    {
-      if (IS_OSPF6_DUMP_ABR)
-        zlog_info ("ABR: ABR entry's B bit off");
-      return NULL;
-    }
-
-  return abr_entry;
-}
-
-static int
-ospf6_abr_prefix_lsa_to_route (struct ospf6_lsa *lsa,
-                               struct ospf6_route_req *request)
-{
-  struct ospf6_inter_area_prefix_lsa *iep;
-  struct ospf6_route_req abr_entry;
-
-  if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTER_PREFIX))
-    {
-      if (IS_OSPF6_DUMP_ABR)
-        zlog_info ("ABR: LSA type mismatch");
-      return -1;
-    }
-
-  if (IS_LSA_MAXAGE (lsa))
-    {
-      if (IS_OSPF6_DUMP_ABR)
-        zlog_info ("ABR: LSA MaxAge");
-      return -1;
-    }
-
-  if (! ospf6_abr_entry_lookup (&abr_entry, lsa->header->adv_router,
-                                (struct ospf6_area *) lsa->scope))
-    {
-      if (IS_OSPF6_DUMP_ABR)
-        zlog_info ("ABR: ABR check failed");
-      return -1;
-    }
-
-  iep = OSPF6_LSA_HEADER_END (lsa->header);
-
-  memset (request, 0, sizeof (struct ospf6_route_req));
-  request->route.type = OSPF6_DEST_TYPE_NETWORK;
-  request->route.prefix.family = AF_INET6;
-  request->route.prefix.prefixlen = iep->prefix.prefix_length;
-  ospf6_prefix_in6_addr (&iep->prefix, &request->route.prefix.u.prefix6);
-
-  request->path.cost = abr_entry.path.cost +
-                      (ntohl (iep->metric) & ntohl (0x000fffff));
-  request->path.type = OSPF6_PATH_TYPE_INTER;
-  request->path.origin.type = lsa->header->type;
-  request->path.origin.id = lsa->header->id;
-  request->path.origin.adv_router = lsa->header->adv_router;
-  memcpy (&request->nexthop.address, &abr_entry.nexthop.address,
-          sizeof (request->nexthop.address));
-  request->nexthop.ifindex = abr_entry.nexthop.ifindex;
-
-  return 0;
-}
-
-void
-ospf6_abr_prefix_lsa_add (struct ospf6_lsa *lsa)
-{
-  struct ospf6_route_req request;
-  int ret;
-
-  if (IS_OSPF6_DUMP_ABR)
-    zlog_info ("ABR: Calculate %s", lsa->str);
-
-  ret = ospf6_abr_prefix_lsa_to_route (lsa, &request);
-  if (ret < 0)
-    return;
-
-  if (IS_OSPF6_DUMP_ABR)
-    zlog_info ("ABR: Inter Area Route add for %s", lsa->str);
-
-  ospf6_route_add (&request, ospf6->route_table);
-}
-
-void
-ospf6_abr_prefix_lsa_remove (struct ospf6_lsa *lsa)
-{
-  struct ospf6_inter_area_prefix_lsa *iep;
-  struct prefix_ipv6 prefix6;
-  struct ospf6_route_req request;
-
-  iep = OSPF6_LSA_HEADER_END (lsa->header);
-
-  prefix6.family = AF_INET6;
-  prefix6.prefixlen = iep->prefix.prefix_length;
-  ospf6_prefix_in6_addr (&iep->prefix, &prefix6.prefix);
-
-  if (IS_OSPF6_DUMP_ABR)
-    zlog_info ("ABR: Inter Area Route remove for %s", lsa->str);
-
-  for (ospf6_route_lookup (&request, (struct prefix *) &prefix6,
-                           ospf6->route_table);
-       ! ospf6_route_end (&request);
-       ospf6_route_next (&request))
-   {
-     if (memcmp (&prefix6, &request.route.prefix, sizeof (prefix6)))
-       break;
-     if (request.path.origin.type != htons (OSPF6_LSA_TYPE_INTER_PREFIX) ||
-         request.path.origin.adv_router != lsa->header->adv_router ||
-         request.path.origin.id != lsa->header->id)
-       continue;
-
-     ospf6_route_remove (&request, ospf6->route_table);
-   }
-}
-
-static int
-ospf6_abr_router_lsa_to_route (struct ospf6_lsa *lsa,
-                               struct ospf6_route_req *request)
-{
-  struct ospf6_inter_area_router_lsa *ier;
-  struct ospf6_route_req abr_entry;
-
-  if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTER_ROUTER))
-    {
-      if (IS_OSPF6_DUMP_ABR)
-        zlog_info ("ABR: LSA type mismatch");
-      return -1;
-    }
-
-  if (IS_LSA_MAXAGE (lsa))
-    {
-      if (IS_OSPF6_DUMP_ABR)
-        zlog_info ("ABR: LSA MaxAge");
-      return -1;
-    }
-
-  if (! ospf6_abr_entry_lookup (&abr_entry, lsa->header->adv_router,
-                                (struct ospf6_area *) lsa->scope))
-    {
-      if (IS_OSPF6_DUMP_ABR)
-        zlog_info ("ABR: Advertising router check failed");
-      return -1;
-    }
-
-  ier = OSPF6_LSA_HEADER_END (lsa->header);
-
-  memset (request, 0, sizeof (struct ospf6_route_req));
-  request->route.type = OSPF6_DEST_TYPE_ROUTER;
-  request->route.prefix.family = AF_UNSPEC;
-  request->route.prefix.prefixlen = 64; /* XXX */
-  ((struct prefix_ls *) &request->route.prefix)->adv_router.s_addr
-    = ier->router_id;
-
-  request->path.cost = abr_entry.path.cost +
-                      (ntohl (ier->metric & htonl (0x000fffff)));
-  request->path.type = OSPF6_PATH_TYPE_INTER;
-  request->path.origin.type = lsa->header->type;
-  request->path.origin.id = lsa->header->id;
-  request->path.origin.adv_router = lsa->header->adv_router;
-  SET_FLAG (request->path.router_bits, OSPF6_ROUTER_LSA_BIT_E);
-  request->path.capability[0] = ier->options[0];
-  request->path.capability[1] = ier->options[1];
-  request->path.capability[2] = ier->options[2];
-
-  memcpy (&request->nexthop.address, &abr_entry.nexthop.address,
-          sizeof (request->nexthop.address));
-  request->nexthop.ifindex = abr_entry.nexthop.ifindex;
-
-  return 0;
-}
-
-void
-ospf6_abr_router_lsa_add (struct ospf6_lsa *lsa)
-{
-  struct ospf6_route_req request;
-  int ret;
-
-  if (IS_OSPF6_DUMP_ABR)
-    zlog_info ("ABR: Calculate %s", lsa->str);
-
-  ret = ospf6_abr_router_lsa_to_route (lsa, &request);
-  if (ret < 0)
-    return;
-
-  if (IS_OSPF6_DUMP_ABR)
-    zlog_info ("ABR: Inter Area Router add for %s", lsa->str);
-
-  ospf6_route_add (&request, ospf6->topology_table);
-}
-
-void
-ospf6_abr_router_lsa_remove (struct ospf6_lsa *lsa)
-{
-  struct ospf6_inter_area_router_lsa *ier;
-  struct prefix_ls prefix_ls;
-  struct ospf6_route_req request;
-
-  ier = OSPF6_LSA_HEADER_END (lsa->header);
-
-  memset (&prefix_ls, 0, sizeof (prefix_ls));
-  prefix_ls.family = AF_INET6;
-  prefix_ls.prefixlen = 64; /* XXX */
-  prefix_ls.adv_router.s_addr = ier->router_id;
-
-  if (IS_OSPF6_DUMP_ABR)
-    zlog_info ("ABR: Inter Area Route remove for %s", lsa->str);
-
-  for (ospf6_route_lookup (&request, (struct prefix *) &prefix_ls,
-                           ospf6->route_table);
-       ! ospf6_route_end (&request);
-       ospf6_route_next (&request))
-   {
-     if (memcmp (&prefix_ls, &request.route.prefix, sizeof (prefix_ls)))
-       break;
-     if (request.path.origin.type != htons (OSPF6_LSA_TYPE_INTER_ROUTER) ||
-         request.path.origin.adv_router != lsa->header->adv_router ||
-         request.path.origin.id != lsa->header->id)
-       continue;
-
-     ospf6_route_remove (&request, ospf6->route_table);
-   }
-}
-
-
-void
-ospf6_abr_abr_entry_add (struct ospf6_route_req *abr_entry)
-{
-  struct ospf6_lsdb_node node;
-  struct prefix_ls *abr_id;
-  struct ospf6_route_req request;
-  struct ospf6_area *area;
-
-  if (IS_OSPF6_DUMP_ABR)
-    zlog_info ("ABR: New Area Border Router found");
-
-  area = ospf6_area_lookup (abr_entry->path.area_id, ospf6);
-  if (! area)
-    {
-      if (IS_OSPF6_DUMP_ABR)
-        zlog_info ("ABR: Can't find associated area");
-      return;
-    }
-
-  abr_id = (struct prefix_ls *) &abr_entry->route.prefix;
-  if (! ospf6_abr_entry_lookup (&request, abr_id->adv_router.s_addr, area))
-    {
-      if (IS_OSPF6_DUMP_ABR)
-        zlog_info ("ABR: back check failed");
-      return;
-    }
-
-  /* for each inter-prefix LSA this ABR originated */
-  for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_INTER_PREFIX),
-                               abr_id->adv_router.s_addr, area->lsdb);
-       ! ospf6_lsdb_is_end (&node);
-       ospf6_lsdb_next (&node))
-    ospf6_abr_prefix_lsa_add (node.lsa);
-
-  /* for each inter-router LSA this ABR originated */
-  for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_INTER_ROUTER),
-                               abr_id->adv_router.s_addr, area->lsdb);
-       ! ospf6_lsdb_is_end (&node);
-       ospf6_lsdb_next (&node))
-    ospf6_abr_router_lsa_add (node.lsa);
-}
-
-void
-ospf6_abr_abr_entry_remove (struct ospf6_route_req *abr_entry)
-{
-  struct ospf6_lsdb_node node;
-  struct prefix_ls *abr_id;
-  struct ospf6_area *area;
-
-  if (IS_OSPF6_DUMP_ABR)
-    zlog_info ("ABR: Area Border Router removed");
-
-  abr_id = (struct prefix_ls *) &abr_entry->route.prefix;
-
-  area = ospf6_area_lookup (abr_entry->path.area_id, ospf6);
-  if (! area)
-    {
-      if (IS_OSPF6_DUMP_ABR)
-        zlog_info ("ABR: Can't find associated area");
-      return;
-    }
-
-  /* for each inter-prefix LSA this ABR originated */
-  for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_INTER_PREFIX),
-                               abr_id->adv_router.s_addr, area->lsdb);
-       ! ospf6_lsdb_is_end (&node);
-       ospf6_lsdb_next (&node))
-    ospf6_abr_prefix_lsa_remove (node.lsa);
-
-  /* for each inter-router LSA this ABR originated */
-  for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_INTER_ROUTER),
-                               abr_id->adv_router.s_addr, area->lsdb);
-       ! ospf6_lsdb_is_end (&node);
-       ospf6_lsdb_next (&node))
-    ospf6_abr_router_lsa_remove (node.lsa);
-}
-
-/* Inter-Area-Prefix-LSA Origination */
-
-static void
-ospf6_abr_prefix_lsa_update_add (struct ospf6_route_req *request,
-                                 struct ospf6_area *area)
-{
-  char buffer [MAXLSASIZE];
-  u_int16_t size;
-  struct ospf6_inter_area_prefix_lsa *iep;
-  char *p;
-
-  if (IS_OSPF6_DUMP_ABR)
-    zlog_info ("Update Inter-Prefix for %s: ID: %lu",
-               area->str, (u_long) ntohl (request->route_id));
-
-  /* prepare buffer */
-  memset (buffer, 0, sizeof (buffer));
-  size = sizeof (struct ospf6_inter_area_prefix_lsa);
-  iep = (struct ospf6_inter_area_prefix_lsa *) buffer;
-  p = (char *) (iep + 1);
-
-  /* prefixlen */
-  iep->prefix.prefix_length = request->route.prefix.prefixlen;
-
-  /* PrefixOptions */
-  iep->prefix.prefix_options = request->path.prefix_options;
-
-  /* set Prefix */
-  memcpy (p, &request->route.prefix.u.prefix6,
-          OSPF6_PREFIX_SPACE (request->route.prefix.prefixlen));
-  ospf6_prefix_apply_mask (&iep->prefix);
-  size += OSPF6_PREFIX_SPACE (request->route.prefix.prefixlen);
-
-  ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_INTER_PREFIX),
-                       htonl (request->route_id), ospf6->router_id,
-                       (char *) iep, size, area);
-}
-
-static void
-ospf6_abr_prefix_lsa_update_remove (struct ospf6_route_req *request,
-                                    struct ospf6_area *area)
-{
-  struct ospf6_lsa *lsa;
-  lsa = ospf6_lsdb_lookup_lsdb (htons (OSPF6_LSA_TYPE_INTER_PREFIX),
-                                htonl (request->route_id),
-                                ospf6->router_id, area->lsdb);
-  if (lsa)
-    ospf6_lsa_premature_aging (lsa);
-}
-
-static void
-ospf6_abr_prefix_lsa_update (int type, struct ospf6_route_req *request)
-{
-  struct ospf6_route_req route, target;
-  listnode node;
-  struct ospf6_area *area;
-  struct ospf6_interface *o6i;
-
-  if (request->route.type != OSPF6_DEST_TYPE_NETWORK)
-    return;
-
-  /* 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;
-
-  if (target.path.cost >= LS_INFINITY ||
-      target.path.cost_e2 >= LS_INFINITY)
-    {
-      if (IS_OSPF6_DUMP_ABR)
-        zlog_info ("ABR: Exceeds LS Infinity, ignore");
-      return;
-    }
-
-  ospf6_route_lookup (&target, &request->route.prefix, request->table);
-  if (type == REMOVE)
-    {
-      ospf6_route_next (&route);
-      if (! memcmp (&route.route, &request->route, sizeof (route.route)))
-        {
-          type = ADD;
-          ospf6_route_next (&target);
-        }
-    }
-
-  for (node = listhead (ospf6->area_list); node; nextnode (node))
-    {
-      area = getdata (node);
-
-      if (target.path.area_id == area->area_id)
-        continue;
-
-      o6i = ospf6_interface_lookup_by_index (target.nexthop.ifindex);
-      if (o6i && o6i->area && o6i->area->area_id == area->area_id)
-        {
-          zlog_info ("ABR: Logical equivalent of split horizon, skip for %s",
-                     area->str);
-          continue;
-        }
-
-      if (area->area_id == ntohs (0) && /* Backbone */
-          target.path.type != OSPF6_PATH_TYPE_INTRA)
-        continue;
-
-      /* XXX, stub area check */
-
-      /* XXX, aggregate */
-        /* if either the area of the route or the area trying to
-           advertise is backbone, do not aggregate */
-
-      if (type == ADD)
-        ospf6_abr_prefix_lsa_update_add (&target, area);
-      else
-        ospf6_abr_prefix_lsa_update_remove (&target, area);
-    }
-}
-
-void
-ospf6_abr_route_add (struct ospf6_route_req *request)
-{
-  ospf6_abr_prefix_lsa_update (ADD, request);
-}
-
-void
-ospf6_abr_route_remove (struct ospf6_route_req *request)
-{
-  ospf6_abr_prefix_lsa_update (REMOVE, request);
-}
-
-int
-ospf6_abr_prefix_lsa_refresh (void *data)
-{
-  struct ospf6_lsa *lsa = data;
-  struct ospf6_inter_area_prefix_lsa *ier;
-  struct prefix_ipv6 prefix6;
-  struct ospf6_route_req route;
-
-  ier = OSPF6_LSA_HEADER_END (lsa->header);
-  memset (&prefix6, 0, sizeof (prefix6));
-  prefix6.family = AF_INET6;
-  prefix6.prefixlen = ier->prefix.prefix_length;
-  ospf6_prefix_in6_addr (&ier->prefix, &prefix6.prefix);
-
-  ospf6_route_lookup (&route, (struct prefix *) &prefix6,
-                      ospf6->route_table);
-  assert (! ospf6_route_end (&route));
-
-  ospf6_abr_prefix_lsa_update (ADD, &route);
-  return 0;
-}
-
-int
-ospf6_abr_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
-{
-  struct ospf6_inter_area_prefix_lsa *ier;
-  char prefix[128];
-
-  assert (lsa->header);
-  ier = OSPF6_LSA_HEADER_END (lsa->header);
-
-  ospf6_prefix_string (&ier->prefix, prefix, sizeof (prefix));
-
-  vty_out (vty, "     Metric: %d%s",
-           ntohl (ier->metric & htonl (0x000fffff)), VTY_NEWLINE);
-  vty_out (vty, "     Prefix: %s%s", prefix, VTY_NEWLINE);
-
-  return 0;
-}
-
-int
-ospf6_abr_prefix_lsa_hook_add (void *data)
-{
-  struct ospf6_lsa *lsa = data;
-  ospf6_abr_prefix_lsa_add (lsa);
-  return 0;
-}
-
-int
-ospf6_abr_prefix_lsa_hook_remove (void *data)
-{
-  struct ospf6_lsa *lsa = data;
-  ospf6_abr_prefix_lsa_remove (lsa);
-  return 0;
-}
-
-void
-ospf6_abr_database_hook_inter_prefix (struct ospf6_lsa *old,
-                                      struct ospf6_lsa *new)
-{
-  if (old)
-    ospf6_abr_prefix_lsa_hook_remove (old);
-  if (new && ! IS_LSA_MAXAGE (new))
-    ospf6_abr_prefix_lsa_hook_add (new);
-}
-
-void
-ospf6_abr_register_inter_prefix ()
-{
-  struct ospf6_lsa_slot slot;
-
-  memset (&slot, 0, sizeof (slot));
-  slot.type         = htons (OSPF6_LSA_TYPE_INTER_PREFIX);
-  slot.name         = "Inter-Prefix";
-  slot.func_show    = ospf6_abr_prefix_lsa_show;
-  slot.func_refresh = ospf6_abr_prefix_lsa_refresh;
-  ospf6_lsa_slot_register (&slot);
-
-  ospf6_lsdb_hook[OSPF6_LSA_TYPE_INTER_PREFIX & OSPF6_LSTYPE_CODE_MASK].hook = 
-    ospf6_abr_database_hook_inter_prefix;
-}
-
-int
-ospf6_abr_router_lsa_hook_add (void *data)
-{
-  struct ospf6_lsa *lsa = data;
-  ospf6_abr_router_lsa_add (lsa);
-  return 0;
-}
-
-int
-ospf6_abr_router_lsa_hook_remove (void *data)
-{
-  struct ospf6_lsa *lsa = data;
-  ospf6_abr_router_lsa_remove (lsa);
-  return 0;
-}
-
-int
-ospf6_abr_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
-{
-  return 0;
-}
-
-int
-ospf6_abr_router_lsa_refresh (void *data)
-{
-  return 0;
-}
-
-void
-ospf6_abr_database_hook_inter_router (struct ospf6_lsa *old,
-                                      struct ospf6_lsa *new)
-{
-  if (old)
-    ospf6_abr_router_lsa_hook_remove (old);
-  if (new && ! IS_LSA_MAXAGE (new))
-    ospf6_abr_router_lsa_hook_add (new);
-}
-
-void
-ospf6_abr_register_inter_router ()
-{
-  struct ospf6_lsa_slot slot;
-
-  memset (&slot, 0, sizeof (slot));
-  slot.type         = htons (OSPF6_LSA_TYPE_INTER_ROUTER);
-  slot.name         = "Inter-Router";
-  slot.func_show    = ospf6_abr_router_lsa_show;
-  slot.func_refresh = ospf6_abr_router_lsa_refresh;
-  ospf6_lsa_slot_register (&slot);
-
-  ospf6_lsdb_hook[OSPF6_LSA_TYPE_INTER_ROUTER & OSPF6_LSTYPE_CODE_MASK].hook = 
-    ospf6_abr_database_hook_inter_router;
-}
-
-void
-ospf6_abr_inter_route_calculation (struct ospf6_area *area)
-{
-  struct ospf6_lsdb_node node;
-
-  /* for each inter-prefix LSA */
-  for (ospf6_lsdb_type (&node, htons (OSPF6_LSA_TYPE_INTER_PREFIX),
-                        area->lsdb);
-       ! ospf6_lsdb_is_end (&node);
-       ospf6_lsdb_next (&node))
-    ospf6_abr_prefix_lsa_add (node.lsa);
-}
-
-void
-ospf6_abr_init ()
-{
-  abr_index = ospf6_dump_install ("abr", "Area Border Router Function\n");
-
-  ospf6_abr_register_inter_prefix ();
-  ospf6_abr_register_inter_router ();
-}
-
-
diff --git a/ospf6d/ospf6_abr.h b/ospf6d/ospf6_abr.h
deleted file mode 100644
index 510532e..0000000
--- a/ospf6d/ospf6_abr.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2001 Yasuhiro Ohara
- *
- * 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.  
- */
-
-#ifndef OSPF6_ABR_H
-#define OSPF6_ABR_H
-
-/* Inter-Area-Prefix-LSA */
-struct ospf6_inter_area_prefix_lsa
-{
-  u_int32_t metric;           /* 12bits reserved, 20bits metric */
-  struct ospf6_prefix prefix; /* followed by one address prefix */
-};
-
-/* Inter-Area-Router-LSA */
-struct ospf6_inter_area_router_lsa
-{
-  u_char reserved;
-  u_char options[3];      /* Optional Capability */
-  u_int32_t metric;       /* 12bits reserved, 20bits metric */
-  u_int32_t router_id;    /* Destination Router ID */
-};
-
-void ospf6_abr_prefix_lsa_add (struct ospf6_lsa *);
-void ospf6_abr_prefix_lsa_remove (struct ospf6_lsa *);
-void ospf6_abr_prefix_lsa_change (struct ospf6_lsa *, struct ospf6_lsa *);
-
-void ospf6_abr_abr_entry_add (struct ospf6_route_req *);
-void ospf6_abr_abr_entry_remove (struct ospf6_route_req *);
-
-void ospf6_abr_route_add (struct ospf6_route_req *);
-void ospf6_abr_route_remove (struct ospf6_route_req *);
-
-void ospf6_abr_inter_route_calculation (struct ospf6_area *);
-
-void ospf6_abr_init ();
-
-#endif /* OSPF6_ABR_H */
-
diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c
index 51af508..ef283cd 100644
--- a/ospf6d/ospf6_area.c
+++ b/ospf6d/ospf6_area.c
@@ -1,6 +1,5 @@
 /*
- * OSPF6 Area Data Structure
- * Copyright (C) 1999-2002 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -20,67 +19,35 @@
  * Boston, MA 02111-1307, USA.  
  */
 
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "linklist.h"
+#include "thread.h"
+#include "vty.h"
+#include "command.h"
+#include "if.h"
+#include "prefix.h"
+#include "table.h"
+
 #include "ospf6d.h"
+#include "ospf6_proto.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+#include "ospf6_route.h"
+#include "ospf6_spf.h"
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_interface.h"
+#include "ospf6_intra.h"
 
-static int area_index;
-#define IS_OSPF6_DUMP_AREA (ospf6_dump_is_on (area_index))
-
-static void
-ospf6_area_foreach_interface (struct ospf6_area *o6a, void *arg, int val,
-                              void (*func) (void *, int, void *))
+int
+ospf6_area_cmp (void *va, void *vb)
 {
-  listnode node;
-  struct ospf6_interface *o6i;
-
-  for (node = listhead (o6a->if_list); node; nextnode (node))
-    {
-      o6i = (struct ospf6_interface *) getdata (node);
-      (*func) (arg, val, o6i);
-    }
-}
-
-static void
-ospf6_area_foreach_neighbor (struct ospf6_area *o6a, void *arg, int val,
-                             void (*func) (void *, int, void *))
-{
-  listnode node;
-  struct ospf6_interface *o6i;
-
-  for (node = listhead (o6a->if_list); node; nextnode (node))
-    {
-      o6i = (struct ospf6_interface *) getdata (node);
-      (*o6i->foreach_nei) (o6i, arg, val, func);
-    }
-}
-
-static int
-ospf6_area_maxage_remover (struct thread *t)
-{
-  int count;
-  struct ospf6_area *o6a = (struct ospf6_area *) THREAD_ARG (t);
-
-  o6a->maxage_remover = (struct thread *) NULL;
-
-  count = 0;
-  o6a->foreach_nei (o6a, &count, NBS_EXCHANGE, ospf6_count_state);
-  o6a->foreach_nei (o6a, &count, NBS_LOADING, ospf6_count_state);
-  if (count != 0)
-    return 0;
-
-  ospf6_lsdb_remove_maxage (o6a->lsdb);
-  return 0;
-}
-
-void
-ospf6_area_schedule_maxage_remover (void *arg, int val, void *obj)
-{
-  struct ospf6_area *o6a = (struct ospf6_area *) obj;
-
-  if (o6a->maxage_remover != NULL)
-    return;
-
-  o6a->maxage_remover =
-    thread_add_event (master, ospf6_area_maxage_remover, o6a, 0);
+  struct ospf6_area *oa = (struct ospf6_area *) va;
+  struct ospf6_area *ob = (struct ospf6_area *) vb;
+  return (ntohl (oa->area_id) - ntohl (ob->area_id));
 }
 
 int
@@ -91,242 +58,811 @@
   return 1;
 }
 
-int
-ospf6_area_is_transit (struct ospf6_area *o6a)
-{
-  return 0;
-}
-
-
-
+/* schedule routing table recalculation */
 void
-ospf6_area_route_add (void *data)
+ospf6_area_lsdb_hook_add (struct ospf6_lsa *lsa)
 {
-  struct ospf6_route_req *route = data;
-  struct in6_addr local;
+  struct ospf6_area *oa;
 
-  inet_pton (AF_INET6, "::1", &local);
-  if (! memcmp (&route->nexthop.address, &local, sizeof (struct in6_addr)))
+  oa = (struct ospf6_area *) lsa->scope;
+  switch (ntohs (lsa->header->type))
     {
-      if (IS_OSPF6_DUMP_AREA)
-        zlog_info ("AREA: Self-originated route add, ignore");
-      return;
-    }
+    case OSPF6_LSTYPE_ROUTER:
+    case OSPF6_LSTYPE_NETWORK:
+      ospf6_spf_schedule (oa);
+      break;
 
-  ospf6_route_add (route, ospf6->route_table);
+    case OSPF6_LSTYPE_INTRA_PREFIX:
+      ospf6_intra_prefix_lsa_add (lsa);
+      break;
+
+    case OSPF6_LSTYPE_INTER_PREFIX:
+    case OSPF6_LSTYPE_INTER_ROUTER:
+      break;
+
+    default:
+      if (IS_OSPF6_DEBUG_LSA (RECV))
+	zlog_info ("Unknown LSA in Area %s's lsdb", oa->name);
+      break;
+    }
 }
 
 void
-ospf6_area_route_remove (void *data)
+ospf6_area_lsdb_hook_remove (struct ospf6_lsa *lsa)
 {
-  struct ospf6_route_req *route = data;
-  struct in6_addr local;
+  struct ospf6_area *oa;
 
-  inet_pton (AF_INET6, "::1", &local);
-  if (! memcmp (&route->nexthop.address, &local, sizeof (struct in6_addr)))
+  oa = (struct ospf6_area *) lsa->scope;
+  switch (ntohs (lsa->header->type))
     {
-      if (IS_OSPF6_DUMP_AREA)
-        zlog_info ("AREA: Self-originated route remove, ignore");
-      return;
-    }
+    case OSPF6_LSTYPE_ROUTER:
+    case OSPF6_LSTYPE_NETWORK:
+      ospf6_spf_schedule (oa);
+      break;
 
-  ospf6_route_remove (route, ospf6->route_table);
+    case OSPF6_LSTYPE_INTRA_PREFIX:
+      ospf6_intra_prefix_lsa_remove (lsa);
+      break;
+
+    case OSPF6_LSTYPE_INTER_PREFIX:
+    case OSPF6_LSTYPE_INTER_ROUTER:
+      break;
+
+    default:
+      if (IS_OSPF6_DEBUG_LSA (RECV))
+	zlog_info ("Unknown LSA in Area %s's lsdb", oa->name);
+      break;
+    }
+}
+
+void
+ospf6_area_route_hook_add (struct ospf6_route *route)
+{
+  struct ospf6_route *copy = ospf6_route_copy (route);
+  ospf6_route_add (copy, ospf6->route_table);
+}
+
+void
+ospf6_area_route_hook_remove (struct ospf6_route *route)
+{
+  struct ospf6_route *copy;
+
+  copy = ospf6_route_lookup_identical (route, ospf6->route_table);
+  if (copy)
+    ospf6_route_remove (copy, ospf6->route_table);
 }
 
 /* Make new area structure */
 struct ospf6_area *
-ospf6_area_create (u_int32_t area_id)
+ospf6_area_create (u_int32_t area_id, struct ospf6 *o)
 {
-  struct ospf6_area *o6a;
-  char namebuf[64];
+  struct ospf6_area *oa;
 
-  /* allocate memory */
-  o6a = XCALLOC (MTYPE_OSPF6_AREA, sizeof (struct ospf6_area));
+  oa = XCALLOC (MTYPE_OSPF6_AREA, sizeof (struct ospf6_area));
 
-  /* initialize */
-  inet_ntop (AF_INET, &area_id, o6a->str, sizeof (o6a->str));
-  o6a->area_id = area_id;
-  o6a->if_list = list_new ();
+  inet_ntop (AF_INET, &area_id, oa->name, sizeof (oa->name));
+  oa->area_id = area_id;
+  oa->if_list = list_new ();
 
-  o6a->lsdb = ospf6_lsdb_create ();
-  o6a->spf_tree = ospf6_spftree_create ();
+  oa->lsdb = ospf6_lsdb_create ();
+  oa->lsdb->hook_add = ospf6_area_lsdb_hook_add;
+  oa->lsdb->hook_remove = ospf6_area_lsdb_hook_remove;
 
-  snprintf (namebuf, sizeof (namebuf), "Area %s's route table", o6a->str);
-  o6a->route_table = ospf6_route_table_create (namebuf);
-  o6a->route_table->hook_add = ospf6_area_route_add;
-  o6a->route_table->hook_change = ospf6_area_route_add;
-  o6a->route_table->hook_remove = ospf6_area_route_remove;
+  oa->spf_table = ospf6_route_table_create ();
+  oa->route_table = ospf6_route_table_create ();
+  oa->route_table->hook_add = ospf6_area_route_hook_add;
+  oa->route_table->hook_remove = ospf6_area_route_hook_remove;
 
-  snprintf (namebuf, sizeof (namebuf), "Area %s's topology table", o6a->str);
-  o6a->table_topology = ospf6_route_table_create (namebuf);
-  o6a->table_topology->hook_add = ospf6_intra_topology_add;
-  o6a->table_topology->hook_change = ospf6_intra_topology_add;
-  o6a->table_topology->hook_remove = ospf6_intra_topology_remove;
+  /* set default options */
+  OSPF6_OPT_SET (oa->options, OSPF6_OPT_V6);
+  OSPF6_OPT_SET (oa->options, OSPF6_OPT_E);
+  OSPF6_OPT_SET (oa->options, OSPF6_OPT_R);
 
-  /* xxx, set options */
-  OSPF6_OPT_SET (o6a->options, OSPF6_OPT_V6);
-  OSPF6_OPT_SET (o6a->options, OSPF6_OPT_E);
-  OSPF6_OPT_SET (o6a->options, OSPF6_OPT_R);
+  oa->ospf6 = o;
+  listnode_add_sort (o->area_list, oa);
 
-  o6a->foreach_if = ospf6_area_foreach_interface;
-  o6a->foreach_nei = ospf6_area_foreach_neighbor;
-
-  return o6a;
+  return oa;
 }
 
 void
-ospf6_area_bind_top (struct ospf6_area *o6a, struct ospf6 *o6)
-{
-  o6a->ospf6 = o6;
-  CALL_CHANGE_HOOK (&area_hook, o6a);
-  return;
-}
-
-void
-ospf6_area_delete (struct ospf6_area *o6a)
+ospf6_area_delete (struct ospf6_area *oa)
 {
   listnode n;
-  struct ospf6_interface *o6i;
-
-  CALL_REMOVE_HOOK (&area_hook, o6a);
+  struct ospf6_interface *oi;
 
   /* ospf6 interface list */
-  for (n = listhead (o6a->if_list); n; nextnode (n))
+  for (n = listhead (oa->if_list); n; nextnode (n))
     {
-      o6i = (struct ospf6_interface *) getdata (n);
-      /* ospf6_interface_delete (o6i); */
+      oi = (struct ospf6_interface *) getdata (n);
+      ospf6_interface_delete (oi);
     }
-  list_delete (o6a->if_list);
+  list_delete (oa->if_list);
 
-  /* terminate LSDB */
-  ospf6_lsdb_remove_all (o6a->lsdb);
+  ospf6_lsdb_delete (oa->lsdb);
+  ospf6_route_table_delete (oa->spf_table);
+  ospf6_route_table_delete (oa->route_table);
 
-  /* spf tree terminate */
-  /* xxx */
+#if 0
+  ospf6_spftree_delete (oa->spf_tree);
+  ospf6_route_table_delete (oa->topology_table);
+#endif /*0*/
 
-  /* threads */
-  if (o6a->spf_calc)
-    thread_cancel (o6a->spf_calc);
-  o6a->spf_calc = (struct thread *) NULL;
-  if (o6a->route_calc)
-    thread_cancel (o6a->route_calc);
-  o6a->route_calc = (struct thread *) NULL;
+  THREAD_OFF (oa->thread_spf_calculation);
+  THREAD_OFF (oa->thread_route_calculation);
 
-  /* new */
-  ospf6_route_table_delete (o6a->route_table);
-
-  ospf6_spftree_delete (o6a->spf_tree);
-  ospf6_route_table_delete (o6a->table_topology);
+  listnode_delete (oa->ospf6->area_list, oa);
+  oa->ospf6 = NULL;
 
   /* free area */
-  XFREE (MTYPE_OSPF6_AREA, o6a);
+  XFREE (MTYPE_OSPF6_AREA, oa);
 }
 
 struct ospf6_area *
-ospf6_area_lookup (u_int32_t area_id, struct ospf6 *o6)
+ospf6_area_lookup (u_int32_t area_id, struct ospf6 *ospf6)
 {
-  struct ospf6_area *o6a;
+  struct ospf6_area *oa;
   listnode n;
 
-  for (n = listhead (o6->area_list); n; nextnode (n))
+  for (n = listhead (ospf6->area_list); n; nextnode (n))
     {
-      o6a = (struct ospf6_area *) getdata (n);
-      if (o6a->area_id == area_id)
-        return o6a;
+      oa = (struct ospf6_area *) getdata (n);
+      if (oa->area_id == area_id)
+        return oa;
     }
 
   return (struct ospf6_area *) NULL;
 }
 
 void
-ospf6_area_show (struct vty *vty, struct ospf6_area *o6a)
+ospf6_area_enable (struct ospf6_area *oa)
 {
   listnode i;
-  struct ospf6_interface *o6i;
+  struct ospf6_interface *oi;
 
-  vty_out (vty, " Area %s%s", o6a->str, VTY_NEWLINE);
-  vty_out (vty, "     Number of Area scoped LSAs is %u%s",
-           o6a->lsdb->count, VTY_NEWLINE);
+  UNSET_FLAG (oa->flag, OSPF6_AREA_DISABLE);
 
-  ospf6_spf_statistics_show (vty, o6a->spf_tree);
-
-  vty_out (vty, "     Interface attached to this area:");
-  for (i = listhead (o6a->if_list); i; nextnode (i))
+  for (i = listhead (oa->if_list); i; nextnode (i))
     {
-      o6i = (struct ospf6_interface *) getdata (i);
-      vty_out (vty, " %s", o6i->interface->name);
-    }
-  vty_out (vty, "%s", VTY_NEWLINE);
-
-  for (i = listhead (o6a->if_list); i; nextnode (i))
-    {
-      o6i = (struct ospf6_interface *) getdata (i);
-      if (listcount (o6i->neighbor_list) != 0)
-        ospf6_interface_statistics_show (vty, o6i);
+      oi = (struct ospf6_interface *) getdata (i);
+      ospf6_interface_enable (oi);
     }
 }
 
 void
-ospf6_area_statistics_show (struct vty *vty, struct ospf6_area *o6a)
+ospf6_area_disable (struct ospf6_area *oa)
 {
-#if 0
-  listnode node;
-  struct ospf6_interface *o6i;
+  listnode i;
+  struct ospf6_interface *oi;
 
-  vty_out (vty, "  Statistics of Area %s%s", o6a->str, VTY_NEWLINE);
-#endif
+  SET_FLAG (oa->flag, OSPF6_AREA_DISABLE);
+
+  for (i = listhead (oa->if_list); i; nextnode (i))
+    {
+      oi = (struct ospf6_interface *) getdata (i);
+      ospf6_interface_disable (oi);
+    }
 }
 
-DEFUN (show_ipv6_ospf6_area_route,
-       show_ipv6_ospf6_area_route_cmd,
-       "show ipv6 ospf6 area A.B.C.D route",
+
+void
+ospf6_area_show (struct vty *vty, struct ospf6_area *oa)
+{
+  listnode i;
+  struct ospf6_interface *oi;
+
+  vty_out (vty, " Area %s%s", oa->name, VTY_NEWLINE);
+  vty_out (vty, "     Number of Area scoped LSAs is %u%s",
+           oa->lsdb->count, VTY_NEWLINE);
+
+  vty_out (vty, "     Interface attached to this area:");
+  for (i = listhead (oa->if_list); i; nextnode (i))
+    {
+      oi = (struct ospf6_interface *) getdata (i);
+      vty_out (vty, " %s", oi->interface->name);
+    }
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+
+#define OSPF6_CMD_AREA_LOOKUP(str, oa)                             \
+{                                                                  \
+  u_int32_t area_id = 0;                                           \
+  if (inet_pton (AF_INET, str, &area_id) != 1)                     \
+    {                                                              \
+      vty_out (vty, "Malformed Area-ID: %s%s", str, VTY_NEWLINE);  \
+      return CMD_SUCCESS;                                          \
+    }                                                              \
+  oa = ospf6_area_lookup (area_id, ospf6);                         \
+  if (oa == NULL)                                                  \
+    {                                                              \
+      vty_out (vty, "No such Area: %s%s", str, VTY_NEWLINE);       \
+      return CMD_SUCCESS;                                          \
+    }                                                              \
+}
+
+DEFUN (show_ipv6_ospf6_area_route_intra,
+       show_ipv6_ospf6_area_route_intra_cmd,
+       "show ipv6 ospf6 area A.B.C.D route intra-area",
        SHOW_STR
        IP6_STR
        OSPF6_STR
        OSPF6_AREA_STR
        OSPF6_AREA_ID_STR
        ROUTE_STR
+       "Display Intra-Area routes\n"
        )
 {
-  struct ospf6_area *o6a;
-  u_int32_t area_id;
-
-  OSPF6_CMD_CHECK_RUNNING ();
-
-  inet_pton (AF_INET, argv[0], &area_id);
-  o6a = ospf6_area_lookup (area_id, ospf6);
-
-  if (! o6a)
-    return CMD_SUCCESS;
-
-  argc -= 1;
-  argv += 1;
-
-  return ospf6_route_table_show (vty, argc, argv, o6a->route_table);
+  struct ospf6_area *oa;
+  OSPF6_CMD_AREA_LOOKUP (argv[0], oa);
+  argc--;
+  argv++;
+  return ospf6_route_table_show (vty, argc, argv, oa->route_table);
 }
 
-ALIAS (show_ipv6_ospf6_area_route,
-       show_ipv6_ospf6_area_route_prefix_cmd,
-       "show ipv6 ospf6 area A.B.C.D route (X::X|detail)",
+ALIAS (show_ipv6_ospf6_area_route_intra,
+       show_ipv6_ospf6_area_route_intra_detail_cmd,
+       "show ipv6 ospf6 area A.B.C.D route intra-area (X::X|X::X/M|detail)",
        SHOW_STR
        IP6_STR
        OSPF6_STR
        OSPF6_AREA_STR
        OSPF6_AREA_ID_STR
        ROUTE_STR
+       "Display Intra-Area routes\n"
        "Specify IPv6 address\n"
+       "Specify IPv6 prefix\n"
+       "Detailed information\n"
+       );
+
+DEFUN (show_ipv6_ospf6_area_route_intra_match,
+       show_ipv6_ospf6_area_route_intra_match_cmd,
+       "show ipv6 ospf6 area A.B.C.D route intra-area X::X/M match",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       ROUTE_STR
+       "Display Intra-Area routes\n"
+       OSPF6_AREA_STR
+       OSPF6_AREA_ID_STR
+       "Specify IPv6 prefix\n"
+       "Display routes which match the specified route\n"
+       )
+{
+  char *sargv[CMD_ARGC_MAX];
+  int i, sargc;
+  struct ospf6_area *oa;
+
+  OSPF6_CMD_AREA_LOOKUP (argv[0], oa);
+  argc--;
+  argv++;
+
+  /* copy argv to sargv and then append "match" */
+  for (i = 0; i < argc; i++)
+    sargv[i] = argv[i];
+  sargc = argc;
+  sargv[sargc++] = "match";
+  sargv[sargc] = NULL;
+
+  return ospf6_route_table_show (vty, sargc, sargv, oa->route_table);
+}
+
+DEFUN (show_ipv6_ospf6_area_route_intra_match_detail,
+       show_ipv6_ospf6_area_route_intra_match_detail_cmd,
+       "show ipv6 ospf6 area A.B.C.D route intra-area X::X/M match detail",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       OSPF6_AREA_STR
+       OSPF6_AREA_ID_STR
+       ROUTE_STR
+       "Display Intra-Area routes\n"
+       "Specify IPv6 prefix\n"
+       "Display routes which match the specified route\n"
        "Detailed information\n"
        )
+{
+  char *sargv[CMD_ARGC_MAX];
+  int i, sargc;
+  struct ospf6_area *oa;
+
+  OSPF6_CMD_AREA_LOOKUP (argv[0], oa);
+  argc--;
+  argv++;
+
+  /* copy argv to sargv and then append "match" and "detail" */
+  for (i = 0; i < argc; i++)
+    sargv[i] = argv[i];
+  sargc = argc;
+  sargv[sargc++] = "match";
+  sargv[sargc++] = "detail";
+  sargv[sargc] = NULL;
+
+  return ospf6_route_table_show (vty, sargc, sargv, oa->route_table);
+}
+
+DEFUN (show_ipv6_ospf6_route_intra,
+       show_ipv6_ospf6_route_intra_cmd,
+       "show ipv6 ospf6 route intra-area",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       ROUTE_STR
+       "Display Intra-Area routes\n"
+       )
+{
+  listnode node;
+  struct ospf6_area *oa;
+
+  for (node = listhead (ospf6->area_list); node; nextnode (node))
+    {
+      oa = (struct ospf6_area *) getdata (node);
+      vty_out (vty, "Area %s%s", oa->name, VTY_NEWLINE);
+      ospf6_route_table_show (vty, argc, argv, oa->route_table);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_route_intra,
+       show_ipv6_ospf6_route_intra_detail_cmd,
+       "show ipv6 ospf6 route intra-area (X::X|X::X/M|detail|summary)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       ROUTE_STR
+       "Display Intra-Area routes\n"
+       "Specify IPv6 address\n"
+       "Specify IPv6 prefix\n"
+       "Detailed information\n"
+       "Summary of route table\n"
+       );
+
+DEFUN (show_ipv6_ospf6_route_intra_match,
+       show_ipv6_ospf6_route_intra_match_cmd,
+       "show ipv6 ospf6 route intra-area X::X/M match",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       ROUTE_STR
+       "Display Intra-Area routes\n"
+       "Specify IPv6 prefix\n"
+       "Display routes which match the specified route\n"
+       )
+{
+  char *sargv[CMD_ARGC_MAX];
+  int i, sargc;
+  listnode node;
+  struct ospf6_area *oa;
+
+  /* copy argv to sargv and then append "match" */
+  for (i = 0; i < argc; i++)
+    sargv[i] = argv[i];
+  sargc = argc;
+  sargv[sargc++] = "match";
+  sargv[sargc] = NULL;
+
+  for (node = listhead (ospf6->area_list); node; nextnode (node))
+    {
+      oa = (struct ospf6_area *) getdata (node);
+      ospf6_route_table_show (vty, sargc, sargv, oa->route_table);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_ospf6_route_intra_match_detail,
+       show_ipv6_ospf6_route_intra_match_detail_cmd,
+       "show ipv6 ospf6 route intra-area X::X/M match detail",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       ROUTE_STR
+       "Display Intra-Area routes\n"
+       "Specify IPv6 prefix\n"
+       "Display routes which match the specified route\n"
+       "Detailed information\n"
+       )
+{
+  char *sargv[CMD_ARGC_MAX];
+  int i, sargc;
+  listnode node;
+  struct ospf6_area *oa;
+
+  /* copy argv to sargv and then append "match" and "detail" */
+  for (i = 0; i < argc; i++)
+    sargv[i] = argv[i];
+  sargc = argc;
+  sargv[sargc++] = "match";
+  sargv[sargc++] = "detail";
+  sargv[sargc] = NULL;
+
+  for (node = listhead (ospf6->area_list); node; nextnode (node))
+    {
+      oa = (struct ospf6_area *) getdata (node);
+      ospf6_route_table_show (vty, sargc, sargv, oa->route_table);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_ospf6_spf_tree,
+       show_ipv6_ospf6_spf_tree_cmd,
+       "show ipv6 ospf6 spf tree",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Shortest Path First caculation\n"
+       "Show SPF tree\n")
+{
+  listnode node;
+  struct ospf6_area *oa;
+  struct ospf6_vertex *root;
+  struct ospf6_route *route;
+  struct prefix prefix;
+
+  ospf6_linkstate_prefix (ospf6->router_id, htonl (0), &prefix);
+  for (node = listhead (ospf6->area_list); node; nextnode (node))
+    {
+      oa = (struct ospf6_area *) getdata (node);
+      route = ospf6_route_lookup (&prefix, oa->spf_table);
+      if (route == NULL)
+        {
+          vty_out (vty, "LS entry for root not found in area %s%s",
+                   oa->name, VTY_NEWLINE);
+          continue;
+        }
+      root = (struct ospf6_vertex *) route->route_option;
+      ospf6_spf_display_subtree (vty, "", 0, root);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_ospf6_area_spf_tree,
+       show_ipv6_ospf6_area_spf_tree_cmd,
+       "show ipv6 ospf6 area A.B.C.D spf tree",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       OSPF6_AREA_STR
+       OSPF6_AREA_ID_STR
+       "Shortest Path First caculation\n"
+       "Show SPF tree\n")
+{
+  u_int32_t area_id;
+  struct ospf6_area *oa;
+  struct ospf6_vertex *root;
+  struct ospf6_route *route;
+  struct prefix prefix;
+
+  ospf6_linkstate_prefix (ospf6->router_id, htonl (0), &prefix);
+
+  if (inet_pton (AF_INET, argv[0], &area_id) != 1)
+    {
+      vty_out (vty, "Malformed Area-ID: %s%s", argv[0], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+  oa = ospf6_area_lookup (area_id, ospf6);
+  if (oa == NULL)
+    {
+      vty_out (vty, "No such Area: %s%s", argv[0], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  route = ospf6_route_lookup (&prefix, oa->spf_table);
+  if (route == NULL)
+    {
+      vty_out (vty, "LS entry for root not found in area %s%s",
+               oa->name, VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+  root = (struct ospf6_vertex *) route->route_option;
+  ospf6_spf_display_subtree (vty, "", 0, root);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_ospf6_area_spf_table,
+       show_ipv6_ospf6_area_spf_table_cmd,
+       "show ipv6 ospf6 area A.B.C.D spf table",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       OSPF6_AREA_STR
+       OSPF6_AREA_ID_STR
+       "Shortest Path First caculation\n"
+       "Show table contains SPF result\n"
+       )
+{
+  u_int32_t area_id;
+  struct ospf6_area *oa;
+
+  if (inet_pton (AF_INET, argv[0], &area_id) != 1)
+    {
+      vty_out (vty, "Malformed Area-ID: %s%s", argv[0], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+  oa = ospf6_area_lookup (area_id, ospf6);
+  if (oa == NULL)
+    {
+      vty_out (vty, "No such Area: %s%s", argv[0], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  argc--;
+  argv++;
+
+  ospf6_lsentry_table_show (vty, argc, argv, oa->spf_table);
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_area_spf_table,
+       show_ipv6_ospf6_area_spf_table_1_cmd,
+       "show ipv6 ospf6 area A.B.C.D spf table (A.B.C.D|A.B.C.D/M|detail)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       OSPF6_AREA_STR
+       OSPF6_AREA_ID_STR
+       "Shortest Path First caculation\n"
+       "Show table contains SPF result\n"
+       "Specify Router-ID\n"
+       "Display multiple entry by specifying match-prefix of Router-ID\n"
+       "Display Detail\n"
+       );
+
+ALIAS (show_ipv6_ospf6_area_spf_table,
+       show_ipv6_ospf6_area_spf_table_2_cmd,
+       "show ipv6 ospf6 area A.B.C.D spf table (A.B.C.D|*) (A.B.C.D|A.B.C.D/M|detail)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       OSPF6_AREA_STR
+       OSPF6_AREA_ID_STR
+       "Shortest Path First caculation\n"
+       "Show table contains SPF result\n"
+       "Specify Router-ID\n"
+       "Wildcard Router-ID\n"
+       "Specify Link State ID\n"
+       "Display multiple entry by specifying match-prefix of Link State ID\n"
+       "Display Detail\n"
+       );
+
+DEFUN (show_ipv6_ospf6_area_spf_table_3,
+       show_ipv6_ospf6_area_spf_table_3_cmd,
+       "show ipv6 ospf6 area A.B.C.D spf table (A.B.C.D|*) A.B.C.D/M detail",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       OSPF6_AREA_STR
+       OSPF6_AREA_ID_STR
+       "Shortest Path First caculation\n"
+       "Show table contains SPF result\n"
+       "Specify Router-ID\n"
+       "Wildcard Router-ID\n"
+       "Display multiple entry by specifying match-prefix of Link State ID\n"
+       "Display Detail\n"
+       )
+{
+  u_int32_t area_id;
+  struct ospf6_area *oa;
+  char *sargv[CMD_ARGC_MAX];
+  int i, sargc;
+
+  if (inet_pton (AF_INET, argv[0], &area_id) != 1)
+    {
+      vty_out (vty, "Malformed Area-ID: %s%s", argv[0], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+  oa = ospf6_area_lookup (area_id, ospf6);
+  if (oa == NULL)
+    {
+      vty_out (vty, "No such Area: %s%s", argv[0], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  argc--;
+  argv++;
+
+  /* copy argv to sargv and then append "detail" */
+  for (i = 0; i < argc; i++)
+    sargv[i] = argv[i];
+  sargc = argc;
+  sargv[sargc++] = "detail";
+  sargv[sargc] = NULL;
+
+  ospf6_lsentry_table_show (vty, sargc, sargv, oa->spf_table);
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_ospf6_spf_table,
+       show_ipv6_ospf6_spf_table_cmd,
+       "show ipv6 ospf6 spf table",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Shortest Path First caculation\n"
+       "Show table contains SPF result\n"
+       )
+{
+  listnode node;
+  struct ospf6_area *oa;
+
+  for (node = listhead (ospf6->area_list); node; nextnode (node))
+    {
+      oa = (struct ospf6_area *) getdata (node);
+      ospf6_lsentry_table_show (vty, argc, argv, oa->spf_table);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_spf_table,
+       show_ipv6_ospf6_spf_table_1_cmd,
+       "show ipv6 ospf6 spf table (A.B.C.D|A.B.C.D/M|detail)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Shortest Path First caculation\n"
+       "Show table contains SPF result\n"
+       "Specify Router-ID\n"
+       "Display multiple entry by specifying match-prefix of Router-ID\n"
+       "Display Detail\n"
+       );
+
+ALIAS (show_ipv6_ospf6_spf_table,
+       show_ipv6_ospf6_spf_table_2_cmd,
+       "show ipv6 ospf6 spf table (A.B.C.D|A.B.C.D/M|*) (A.B.C.D|A.B.C.D/M|detail)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Shortest Path First caculation\n"
+       "Show table contains SPF result\n"
+       "Specify Router-ID\n"
+       "Display multiple entry by specifying match-prefix of Router-ID\n"
+       "Wildcard Router-ID\n"
+       "Specify Link State ID\n"
+       "Display multiple entry by specifying match-prefix of Link State ID\n"
+       "Display Detail\n"
+       );
+
+DEFUN (show_ipv6_ospf6_spf_table_3,
+       show_ipv6_ospf6_spf_table_3_cmd,
+       "show ipv6 ospf6 spf table (A.B.C.D|*) A.B.C.D/M detail",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Shortest Path First caculation\n"
+       "Show table contains SPF result\n"
+       "Specify Router-ID\n"
+       "Wildcard Router-ID\n"
+       "Display multiple entry by specifying match-prefix of Link State ID\n"
+       "Display Detail\n"
+       )
+{
+  listnode node;
+  struct ospf6_area *oa;
+  char *sargv[CMD_ARGC_MAX];
+  int i, sargc;
+
+  /* copy argv to sargv and then append "detail" */
+  for (i = 0; i < argc; i++)
+    sargv[i] = argv[i];
+  sargc = argc;
+  sargv[sargc++] = "detail";
+  sargv[sargc] = NULL;
+
+  for (node = listhead (ospf6->area_list); node; nextnode (node))
+    {
+      oa = (struct ospf6_area *) getdata (node);
+      ospf6_lsentry_table_show (vty, sargc, sargv, oa->spf_table);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_ospf6_simulate_spf_tree_root,
+       show_ipv6_ospf6_simulate_spf_tree_root_cmd,
+       "show ipv6 ospf6 simulate spf-tree A.B.C.D area A.B.C.D",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Shortest Path First caculation\n"
+       "Show SPF tree\n"
+       "Specify root's router-id to calculate another router's SPF tree\n")
+{
+  u_int32_t area_id;
+  struct ospf6_area *oa;
+  struct ospf6_vertex *root;
+  struct ospf6_route *route;
+  struct prefix prefix;
+  u_int32_t router_id;
+  struct ospf6_route_table *spf_table;
+  unsigned char tmp_debug_ospf6_spf = 0;
+
+  inet_pton (AF_INET, argv[0], &router_id);
+  ospf6_linkstate_prefix (router_id, htonl (0), &prefix);
+
+  if (inet_pton (AF_INET, argv[1], &area_id) != 1)
+    {
+      vty_out (vty, "Malformed Area-ID: %s%s", argv[1], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+  oa = ospf6_area_lookup (area_id, ospf6);
+  if (oa == NULL)
+    {
+      vty_out (vty, "No such Area: %s%s", argv[1], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  tmp_debug_ospf6_spf = conf_debug_ospf6_spf;
+  conf_debug_ospf6_spf = 0;
+
+  spf_table = ospf6_route_table_create ();
+  ospf6_spf_calculation (router_id, spf_table, oa);
+
+  conf_debug_ospf6_spf = tmp_debug_ospf6_spf;
+
+  route = ospf6_route_lookup (&prefix, spf_table);
+  if (route == NULL)
+    {
+      ospf6_spf_table_finish (spf_table);
+      ospf6_route_table_delete (spf_table);
+      return CMD_SUCCESS;
+    }
+  root = (struct ospf6_vertex *) route->route_option;
+  ospf6_spf_display_subtree (vty, "", 0, root);
+
+  ospf6_spf_table_finish (spf_table);
+  ospf6_route_table_delete (spf_table);
+
+  return CMD_SUCCESS;
+}
 
 void
 ospf6_area_init ()
 {
-  area_index = ospf6_dump_install ("area", "Area information\n");
+  install_element (VIEW_NODE, &show_ipv6_ospf6_spf_tree_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_spf_table_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_spf_table_1_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_spf_table_2_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_spf_table_3_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_tree_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_table_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_table_1_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_table_2_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_table_3_cmd);
 
-  install_element (VIEW_NODE, &show_ipv6_ospf6_area_route_cmd);
-  install_element (VIEW_NODE, &show_ipv6_ospf6_area_route_prefix_cmd);
-  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_route_cmd);
-  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_route_prefix_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_route_intra_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_route_intra_detail_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_route_intra_match_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_route_intra_match_detail_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_route_intra_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_route_intra_detail_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_route_intra_match_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_area_route_intra_match_detail_cmd);
+
+  install_element (VIEW_NODE, &show_ipv6_ospf6_simulate_spf_tree_root_cmd);
+
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_spf_tree_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_spf_table_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_spf_table_1_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_spf_table_2_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_spf_table_3_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_tree_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_table_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_table_1_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_table_2_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_table_3_cmd);
+
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_route_intra_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_route_intra_detail_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_route_intra_match_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_route_intra_match_detail_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_route_intra_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_route_intra_detail_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_route_intra_match_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_route_intra_match_detail_cmd);
+
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_simulate_spf_tree_root_cmd);
 }
-
-
diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h
index 0684464..14d3eb9 100644
--- a/ospf6d/ospf6_area.h
+++ b/ospf6d/ospf6_area.h
@@ -1,6 +1,5 @@
 /*
- * OSPF6 Area Data Structure
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -23,67 +22,54 @@
 #ifndef OSPF_AREA_H
 #define OSPF_AREA_H
 
-/* This file defines area parameters and data structures. */
-
-#define OSPF6_AREA_RANGE_ADVERTISE     0
-#define OSPF6_AREA_RANGE_NOT_ADVERTISE 1
-
-#include "ospf6_spf.h"
 #include "ospf6_top.h"
 
 struct ospf6_area
 {
-  char            str[16];
+  /* Reference to Top data structure */
+  struct ospf6 *ospf6;
 
-  struct ospf6   *ospf6;      /* back pointer */
-  u_int32_t       area_id;
-  u_char          options[3]; /* OSPF Option including ExternalCapability */
+  /* Area-ID */
+  u_int32_t area_id;
 
-  list            if_list; /* OSPF interface to this area */
+  /* Area-ID string */
+  char name[16];
 
-  struct ospf6_lsdb *lsdb;
+  /* flag */
+  u_char flag;
 
-  struct thread  *spf_calc;
-  struct thread  *route_calc;
-  int             stat_spf_execed;
-  int             stat_route_execed;
+  /* OSPF Option */
+  u_char options[3];
 
-  struct route_table *table; /* new route table */
+  /* OSPF interface list */
+  list if_list;
 
-  struct prefix_ipv6 area_range;
-  struct ospf6_spftree *spf_tree;
-
+  struct ospf6_lsdb        *lsdb;
+  struct ospf6_route_table *spf_table;
   struct ospf6_route_table *route_table;
-  struct ospf6_route_table *table_topology;
 
-  void (*foreach_if)  (struct ospf6_area *, void *, int,
-                       void (*func) (void *, int, void *));
-  void (*foreach_nei) (struct ospf6_area *, void *, int,
-                       void (*func) (void *, int, void *));
-
-  struct thread *maxage_remover;
+  struct thread  *thread_spf_calculation;
+  struct thread  *thread_route_calculation;
 
   struct thread *thread_router_lsa;
+  struct thread *thread_intra_prefix_lsa;
+  u_int32_t router_lsa_size_limit;
 };
 
+#define OSPF6_AREA_DISABLE 0x01
+#define OSPF6_AREA_STUB    0x02
 
 /* prototypes */
-
-int
-ospf6_area_count_neighbor_in_state (u_char state, struct ospf6_area *o6a);
-
-void
-ospf6_area_schedule_maxage_remover (void *arg, int val, void *obj);
-
+int ospf6_area_cmp (void *va, void *vb);
 int ospf6_area_is_stub (struct ospf6_area *o6a);
-int ospf6_area_is_transit (struct ospf6_area *o6a);
-struct ospf6_area *ospf6_area_lookup (u_int32_t, struct ospf6 *);
-struct ospf6_area *ospf6_area_create (u_int32_t);
+struct ospf6_area *ospf6_area_create (u_int32_t, struct ospf6 *);
 void ospf6_area_delete (struct ospf6_area *);
-void ospf6_area_show (struct vty *, struct ospf6_area *);
-void
-ospf6_area_statistics_show (struct vty *vty, struct ospf6_area *o6a);
+struct ospf6_area *ospf6_area_lookup (u_int32_t, struct ospf6 *);
 
+void ospf6_area_enable (struct ospf6_area *);
+void ospf6_area_disable (struct ospf6_area *);
+
+void ospf6_area_show (struct vty *, struct ospf6_area *);
 void ospf6_area_init ();
 
 #endif /* OSPF_AREA_H */
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index 5846ab8..81edb60 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001-2002 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -30,78 +30,644 @@
 #include "table.h"
 #include "plist.h"
 #include "thread.h"
+#include "linklist.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 "ospf6d.h"
 #include "ospf6_proto.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+#include "ospf6_route.h"
+#include "ospf6_zebra.h"
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_asbr.h"
+#include "ospf6_intra.h"
 
-extern struct thread_master *master;
+unsigned char conf_debug_ospf6_asbr = 0;
 
-struct route_table *external_table;
-struct
+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])
+
+/* AS External LSA origination */
+void
+ospf6_as_external_lsa_originate_sub (struct ospf6_route *route, int force)
 {
-  char *name;
-  struct route_map *map;
-} rmap [ZEBRA_ROUTE_MAX];
+  char buffer[OSPF6_MAX_LSASIZE];
+  struct ospf6_lsa_header *lsa_header;
+  struct ospf6_lsa *old, *lsa;
 
-static u_int32_t link_state_id = 0;
+  struct ospf6_external_info *info = route->route_option;
+  struct ospf6_as_external_lsa *as_external_lsa;
+  char buf[64];
+  caddr_t p;
 
-char *
-zroute_name[] =
-{ 
-  "system", "kernel", "connected", "static",
-  "rip", "ripng", "ospf", "ospf6", "isis", "bgp", "unknown"
-};
-char *
-zroute_abname[] =
+  /* find previous LSA */
+  old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_AS_EXTERNAL),
+                           htonl (info->id), ospf6->router_id,
+                           ospf6->lsdb);
+
+  if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+    {
+      prefix2str (&route->prefix, buf, sizeof (buf));
+      zlog_info ("Originate AS-External-LSA for %s", buf);
+    }
+
+  /* prepare buffer */
+  memset (buffer, 0, sizeof (buffer));
+  lsa_header = (struct ospf6_lsa_header *) buffer;
+  as_external_lsa = (struct ospf6_as_external_lsa *)
+    ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header));
+  p = (caddr_t)
+    ((caddr_t) as_external_lsa + sizeof (struct ospf6_as_external_lsa));
+
+  /* Fill AS-External-LSA */
+  /* Metric type */
+  if (route->path.metric_type == 2)
+    SET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E);
+  else
+    UNSET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E);
+
+  /* forwarding address */
+  if (! IN6_IS_ADDR_UNSPECIFIED (&info->forwarding))
+    SET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F);
+  else
+    UNSET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F);
+
+  /* external route tag */
+  UNSET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T);
+
+  /* Set metric */
+  OSPF6_ASBR_METRIC_SET (as_external_lsa, route->path.cost);
+
+  /* prefixlen */
+  as_external_lsa->prefix.prefix_length = route->prefix.prefixlen;
+
+  /* PrefixOptions */
+  as_external_lsa->prefix.prefix_options = route->path.prefix_options;
+
+  /* don't use refer LS-type */
+  as_external_lsa->prefix.prefix_refer_lstype = htons (0);
+
+  /* set Prefix */
+  memcpy (p, &route->prefix.u.prefix6,
+          OSPF6_PREFIX_SPACE (route->prefix.prefixlen));
+  ospf6_prefix_apply_mask (&as_external_lsa->prefix);
+  p += OSPF6_PREFIX_SPACE (route->prefix.prefixlen);
+
+  /* Forwarding address */
+  if (CHECK_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F))
+    {
+      memcpy (p, &info->forwarding, sizeof (struct in6_addr));
+      p += sizeof (struct in6_addr);
+    }
+
+  /* External Route Tag */
+  if (CHECK_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T))
+    {
+      /* xxx */
+    }
+
+  /* Fill LSA Header */
+  lsa_header->age = 0;
+  lsa_header->type = htons (OSPF6_LSTYPE_AS_EXTERNAL);
+  lsa_header->id = htonl (info->id);
+  lsa_header->adv_router = ospf6->router_id;
+  lsa_header->seqnum =
+    ospf6_lsa_new_seqnum (lsa_header->type, lsa_header->id,
+                          lsa_header->adv_router, ospf6);
+  lsa_header->length = htons ((caddr_t) p - (caddr_t) lsa_header);
+
+  /* LSA checksum */
+  ospf6_lsa_checksum (lsa_header);
+
+  /* create LSA */
+  lsa = ospf6_lsa_create (lsa_header);
+  lsa->scope = ospf6;
+  if (force)
+    SET_FLAG (lsa->flag, OSPF6_LSA_REFRESH);
+
+  /* Originate */
+  ospf6_lsa_originate (lsa);
+}
+
+int
+ospf6_as_external_lsa_reoriginate (struct ospf6_lsa *lsa)
 {
-  "X", "K", "C", "S", "R", "R", "O", "O", "I", "B", "?"
-};
+  struct prefix prefix_id;
+  struct route_node *node;
+  struct ospf6_route *route;
 
-#define ZROUTE_NAME(x) \
-  (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \
-   zroute_name[(x)] : zroute_name[ZEBRA_ROUTE_MAX])
+  /* create/update binding in external_id_table */
+  prefix_id.family = AF_INET;
+  prefix_id.prefixlen = 32;
+  prefix_id.u.prefix4.s_addr = lsa->header->id;
+  node = route_node_get (ospf6->external_id_table, &prefix_id);
+  route = node->info;
 
-#define ZROUTE_ABNAME(x) \
-  (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \
-   zroute_abname[(x)] : zroute_abname[ZEBRA_ROUTE_MAX])
+  if (route)
+    ospf6_as_external_lsa_originate_sub (route, 1);
+  else
+    ospf6_lsa_premature_aging (lsa);
 
+  return 0;
+}
+
+
+
+void
+ospf6_asbr_lsa_add (struct ospf6_lsa *lsa)
+{
+  struct ospf6_as_external_lsa *external;
+  struct prefix asbr_id;
+  struct ospf6_route *asbr_entry, *route;
+  char buf[64];
+  int i;
+
+  external = (struct ospf6_as_external_lsa *)
+    OSPF6_LSA_HEADER_END (lsa->header);
+
+  if (IS_OSPF6_DEBUG_ASBR)
+    zlog_info ("Calculate AS-External route for %s", lsa->name);
+
+  if (lsa->header->adv_router == ospf6->router_id)
+    {
+      if (IS_OSPF6_DEBUG_ASBR)
+        zlog_info ("Ignore self-originated AS-External-LSA");
+      return;
+    }
+
+  if (OSPF6_ASBR_METRIC (external) == LS_INFINITY)
+    {
+      if (IS_OSPF6_DEBUG_ASBR)
+        zlog_info ("Ignore LSA with LSInfinity Metric");
+      return;
+    }
+
+  asbr_id.family = AF_INET;
+  asbr_id.prefixlen = 32;
+  asbr_id.u.prefix4.s_addr = lsa->header->adv_router;
+  asbr_entry = ospf6_route_lookup (&asbr_id, ospf6->asbr_table);
+
+  if (asbr_entry == NULL)
+    {
+      if (IS_OSPF6_DEBUG_ASBR)
+        {
+          prefix2str (&asbr_id, buf, sizeof (buf));
+          zlog_info ("ASBR entry not found: %s", buf);
+        }
+      return;
+    }
+
+  route = ospf6_route_create ();
+  route->type = OSPF6_DEST_TYPE_NETWORK;
+  route->prefix.family = AF_INET6;
+  route->prefix.prefixlen = external->prefix.prefix_length;
+  ospf6_prefix_in6_addr (&route->prefix.u.prefix6, &external->prefix);
+
+  route->path.area_id = asbr_entry->path.area_id;
+  route->path.origin.type = lsa->header->type;
+  route->path.origin.id = lsa->header->id;
+  route->path.origin.adv_router = lsa->header->adv_router;
+
+  route->path.prefix_options = external->prefix.prefix_options;
+  if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E))
+    {
+      route->path.type = OSPF6_PATH_TYPE_EXTERNAL2;
+      route->path.metric_type = 2;
+      route->path.cost = asbr_entry->path.cost;
+      route->path.cost_e2 = OSPF6_ASBR_METRIC (external);
+    }
+  else
+    {
+      route->path.type = OSPF6_PATH_TYPE_EXTERNAL1;
+      route->path.metric_type = 1;
+      route->path.cost = asbr_entry->path.cost + OSPF6_ASBR_METRIC (external);
+      route->path.cost_e2 = 0;
+    }
+
+  for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
+    ospf6_nexthop_copy (&route->nexthop[i], &asbr_entry->nexthop[i]);
+
+  if (IS_OSPF6_DEBUG_ASBR)
+    {
+      prefix2str (&route->prefix, buf, sizeof (buf));
+      zlog_info ("AS-External route add: %s", buf);
+    }
+
+  ospf6_route_add (route, ospf6->route_table);
+}
+
+void
+ospf6_asbr_lsa_remove (struct ospf6_lsa *lsa)
+{
+  struct ospf6_as_external_lsa *external;
+  struct prefix prefix;
+  struct ospf6_route *route;
+  char buf[64];
+
+  external = (struct ospf6_as_external_lsa *)
+    OSPF6_LSA_HEADER_END (lsa->header);
+
+  if (IS_OSPF6_DEBUG_ASBR)
+    zlog_info ("Withdraw AS-External route for %s", lsa->name);
+
+  if (lsa->header->adv_router == ospf6->router_id)
+    {
+      if (IS_OSPF6_DEBUG_ASBR)
+        zlog_info ("Ignore self-originated AS-External-LSA");
+      return;
+    }
+
+  memset (&prefix, 0, sizeof (struct prefix));
+  prefix.family = AF_INET6;
+  prefix.prefixlen = external->prefix.prefix_length;
+  ospf6_prefix_in6_addr (&prefix.u.prefix6, &external->prefix);
+
+  route = ospf6_route_lookup (&prefix, ospf6->route_table);
+  if (route == NULL)
+    {
+      if (IS_OSPF6_DEBUG_ASBR)
+        {
+          prefix2str (&prefix, buf, sizeof (buf));
+          zlog_info ("AS-External route %s not found", buf);
+        }
+      return;
+    }
+
+  for (ospf6_route_lock (route);
+       route && ospf6_route_is_prefix (&prefix, route);
+       route = ospf6_route_next (route))
+    {
+      if (route->type != OSPF6_DEST_TYPE_NETWORK)
+        continue;
+      if (route->path.origin.type != lsa->header->type)
+        continue;
+      if (route->path.origin.id != lsa->header->id)
+        continue;
+      if (route->path.origin.adv_router != lsa->header->adv_router)
+        continue;
+
+      if (IS_OSPF6_DEBUG_ASBR)
+        {
+          prefix2str (&route->prefix, buf, sizeof (buf));
+          zlog_info ("AS-External route remove: %s", buf);
+        }
+      ospf6_route_remove (route, ospf6->route_table);
+    }
+}
+
+void
+ospf6_asbr_lsentry_add (struct ospf6_route *asbr_entry)
+{
+  char buf[64];
+  struct ospf6_lsa *lsa;
+  u_int16_t type;
+  u_int32_t router;
+
+  if (IS_OSPF6_DEBUG_ASBR)
+    {
+      ospf6_linkstate_prefix2str (&asbr_entry->prefix, buf, sizeof (buf));
+      zlog_info ("New ASBR %s found", buf);
+    }
+
+  type = htons (OSPF6_LSTYPE_AS_EXTERNAL);
+  router = ospf6_linkstate_prefix_adv_router (&asbr_entry->prefix);
+  for (lsa = ospf6_lsdb_type_router_head (type, router, ospf6->lsdb);
+       lsa; lsa = ospf6_lsdb_type_router_next (type, router, lsa))
+    {
+      if (! OSPF6_LSA_IS_MAXAGE (lsa))
+        ospf6_asbr_lsa_add (lsa);
+    }
+
+  if (IS_OSPF6_DEBUG_ASBR)
+    {
+      ospf6_linkstate_prefix2str (&asbr_entry->prefix, buf, sizeof (buf));
+      zlog_info ("Calculation for new ASBR %s done", buf);
+    }
+}
+
+void
+ospf6_asbr_lsentry_remove (struct ospf6_route *asbr_entry)
+{
+  char buf[64];
+  struct ospf6_lsa *lsa;
+  u_int16_t type;
+  u_int32_t router;
+
+  if (IS_OSPF6_DEBUG_ASBR)
+    {
+      ospf6_linkstate_prefix2str (&asbr_entry->prefix, buf, sizeof (buf));
+      zlog_info ("ASBR %s disappeared", buf);
+    }
+
+  type = htons (OSPF6_LSTYPE_AS_EXTERNAL);
+  router = ospf6_linkstate_prefix_adv_router (&asbr_entry->prefix);
+  for (lsa = ospf6_lsdb_type_router_head (type, router, ospf6->lsdb);
+       lsa; lsa = ospf6_lsdb_type_router_next (type, router, lsa))
+    ospf6_asbr_lsa_remove (lsa);
+
+  if (IS_OSPF6_DEBUG_ASBR)
+    {
+      ospf6_linkstate_prefix2str (&asbr_entry->prefix, buf, sizeof (buf));
+      zlog_info ("Calculation for old ASBR %s done", buf);
+    }
+}
+
+
+
 /* 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);
+  if (ospf6->rmap[type].name)
+    free (ospf6->rmap[type].name);
+  ospf6->rmap[type].name = strdup (mapname);
+  ospf6->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;
+  if (ospf6->rmap[type].name)
+    free (ospf6->rmap[type].name);
+  ospf6->rmap[type].name = NULL;
+  ospf6->rmap[type].map = NULL;
 }
 
 void
 ospf6_asbr_routemap_update ()
 {
-  int i;
-  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+  int type;
+
+  if (ospf6 == NULL)
+    return;
+
+  for (type = 0; type < ZEBRA_ROUTE_MAX; type++)
     {
-      if (rmap[i].name)
-        rmap[i].map = route_map_lookup_by_name (rmap[i].name);
+      if (ospf6->rmap[type].name)
+        ospf6->rmap[type].map =
+          route_map_lookup_by_name (ospf6->rmap[type].name);
       else
-        rmap[i].map = NULL;
+        ospf6->rmap[type].map = NULL;
+    }
+}
+
+int
+ospf6_asbr_is_asbr (struct ospf6 *o)
+{
+  return o->external_table->count;
+}
+
+void
+ospf6_asbr_redistribute_set (int type)
+{
+  ospf6_zebra_redistribute (type);
+}
+
+void
+ospf6_asbr_redistribute_unset (int type)
+{
+  struct ospf6_route *route;
+  struct ospf6_external_info *info;
+
+  ospf6_zebra_no_redistribute (type);
+
+  for (route = ospf6_route_head (ospf6->external_table); route;
+       route = ospf6_route_next (route))
+    {
+      info = route->route_option;
+      if (info->type != type)
+        continue;
+
+      ospf6_asbr_redistribute_remove (info->type, route->nexthop[0].ifindex,
+                                      &route->prefix);
+    }
+}
+
+void
+ospf6_asbr_redistribute_add (int type, int ifindex, struct prefix *prefix,
+                             u_int nexthop_num, struct in6_addr *nexthop)
+{
+  int ret;
+  struct ospf6_route troute;
+  struct ospf6_external_info tinfo;
+  struct ospf6_route *route, *match;
+  struct ospf6_external_info *info;
+  struct prefix prefix_id;
+  struct route_node *node;
+  char pbuf[64], ibuf[16];
+  listnode lnode;
+  struct ospf6_area *oa;
+
+  if (! ospf6_zebra_is_redistribute (type))
+    return;
+
+  if (IS_OSPF6_DEBUG_ASBR)
+    {
+      prefix2str (prefix, pbuf, sizeof (pbuf));
+      zlog_info ("Redistribute %s (%s)", pbuf, ZROUTE_NAME (type));
+    }
+
+  /* if route-map was specified but not found, do not advertise */
+  if (ospf6->rmap[type].name)
+    {
+      if (ospf6->rmap[type].map == NULL)
+        ospf6_asbr_routemap_update ();
+      if (ospf6->rmap[type].map == NULL)
+        {
+          zlog_warn ("route-map \"%s\" not found, suppress redistributing",
+                     ospf6->rmap[type].name);
+          return;
+        }
+    }
+
+  /* apply route-map */
+  if (ospf6->rmap[type].map)
+    {
+      memset (&troute, 0, sizeof (troute));
+      memset (&tinfo, 0, sizeof (tinfo));
+      troute.route_option = &tinfo;
+
+      ret = route_map_apply (ospf6->rmap[type].map, prefix,
+                             RMAP_OSPF6, &troute);
+      if (ret != RMAP_MATCH)
+        {
+          if (IS_OSPF6_DEBUG_ASBR)
+            zlog_info ("Denied by route-map \"%s\"", ospf6->rmap[type].name);
+          return;
+        }
+    }
+
+  match = ospf6_route_lookup (prefix, ospf6->external_table);
+  if (match)
+    {
+      info = match->route_option;
+
+      /* copy result of route-map */
+      if (ospf6->rmap[type].map)
+        {
+          if (troute.path.metric_type)
+            match->path.metric_type = troute.path.metric_type;
+          if (troute.path.cost)
+            match->path.cost = troute.path.cost;
+          if (! IN6_IS_ADDR_UNSPECIFIED (&tinfo.forwarding))
+            memcpy (&info->forwarding, &tinfo.forwarding,
+                    sizeof (struct in6_addr));
+        }
+
+      info->type = type;
+      match->nexthop[0].ifindex = ifindex;
+      if (nexthop_num && nexthop)
+        memcpy (&match->nexthop[0].address, nexthop, sizeof (struct in6_addr));
+
+      /* create/update binding in external_id_table */
+      prefix_id.family = AF_INET;
+      prefix_id.prefixlen = 32;
+      prefix_id.u.prefix4.s_addr = htonl (info->id);
+      node = route_node_get (ospf6->external_id_table, &prefix_id);
+      node->info = match;
+
+      if (IS_OSPF6_DEBUG_ASBR)
+        {
+          inet_ntop (AF_INET, &prefix_id.u.prefix4, ibuf, sizeof (ibuf));
+          zlog_info ("Advertise as AS-External Id:%s", ibuf);
+        }
+
+      ospf6_as_external_lsa_originate_sub (match, 0);
+      return;
+    }
+
+  /* create new entry */
+  route = ospf6_route_create ();
+  route->type = OSPF6_DEST_TYPE_NETWORK;
+  memcpy (&route->prefix, prefix, sizeof (struct prefix));
+
+  info = (struct ospf6_external_info *)
+    XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO, sizeof (struct ospf6_external_info));
+  memset (info, 0, sizeof (struct ospf6_external_info));
+  route->route_option = info;
+  info->id = ospf6->external_id++;
+
+  /* copy result of route-map */
+  if (ospf6->rmap[type].map)
+    {
+      if (troute.path.metric_type)
+        route->path.metric_type = troute.path.metric_type;
+      if (troute.path.cost)
+        route->path.cost = troute.path.cost;
+      if (! IN6_IS_ADDR_UNSPECIFIED (&tinfo.forwarding))
+        memcpy (&info->forwarding, &tinfo.forwarding,
+                sizeof (struct in6_addr));
+    }
+
+  info->type = type;
+  route->nexthop[0].ifindex = ifindex;
+  if (nexthop_num && nexthop)
+    memcpy (&route->nexthop[0].address, nexthop, sizeof (struct in6_addr));
+
+  /* create/update binding in external_id_table */
+  prefix_id.family = AF_INET;
+  prefix_id.prefixlen = 32;
+  prefix_id.u.prefix4.s_addr = htonl (info->id);
+  node = route_node_get (ospf6->external_id_table, &prefix_id);
+  node->info = route;
+
+  route = ospf6_route_add (route, ospf6->external_table);
+  route->route_option = info;
+
+  if (IS_OSPF6_DEBUG_ASBR)
+    {
+      inet_ntop (AF_INET, &prefix_id.u.prefix4, ibuf, sizeof (ibuf));
+      zlog_info ("Advertise as AS-External Id:%s", ibuf);
+    }
+
+  ospf6_as_external_lsa_originate_sub (route, 0);
+
+  /* Router-Bit (ASBR Flag) may have to be updated */
+  for (lnode = listhead (ospf6->area_list); lnode; nextnode (lnode))
+    {
+      oa = (struct ospf6_area *) getdata (lnode);
+      OSPF6_ROUTER_LSA_SCHEDULE (oa);
+    }
+}
+
+void
+ospf6_asbr_redistribute_remove (int type, int ifindex, struct prefix *prefix)
+{
+  struct ospf6_route *match;
+  struct ospf6_external_info *info = NULL;
+  struct route_node *node;
+  struct ospf6_lsa *lsa;
+  struct prefix prefix_id;
+  char pbuf[64], ibuf[16];
+  listnode lnode;
+  struct ospf6_area *oa;
+
+  match = ospf6_route_lookup (prefix, ospf6->external_table);
+  if (match == NULL)
+    {
+      if (IS_OSPF6_DEBUG_ASBR)
+        {
+          prefix2str (prefix, pbuf, sizeof (pbuf));
+          zlog_info ("No such route %s to withdraw", pbuf);
+        }
+      return;
+    }
+
+  info = match->route_option;
+  assert (info);
+
+  if (info->type != type)
+    {
+      if (IS_OSPF6_DEBUG_ASBR)
+        {
+          prefix2str (prefix, pbuf, sizeof (pbuf));
+          zlog_info ("Original protocol mismatch: %s", pbuf);
+        }
+      return;
+    }
+
+  if (IS_OSPF6_DEBUG_ASBR)
+    {
+      prefix2str (prefix, pbuf, sizeof (pbuf));
+      inet_ntop (AF_INET, &prefix_id.u.prefix4, ibuf, sizeof (ibuf));
+      zlog_info ("Withdraw %s (AS-External Id:%s)", pbuf, ibuf);
+    }
+
+  lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_AS_EXTERNAL),
+                           htonl (info->id), ospf6->router_id, ospf6->lsdb);
+  if (lsa)
+    ospf6_lsa_premature_aging (lsa);
+
+  /* remove binding in external_id_table */
+  prefix_id.family = AF_INET;
+  prefix_id.prefixlen = 32;
+  prefix_id.u.prefix4.s_addr = htonl (info->id);
+  node = route_node_lookup (ospf6->external_id_table, &prefix_id);
+  assert (node);
+  node->info = NULL;
+  route_unlock_node (node);
+
+  ospf6_route_remove (match, ospf6->external_table);
+  XFREE (MTYPE_OSPF6_EXTERNAL_INFO, info);
+
+  /* Router-Bit (ASBR Flag) may have to be updated */
+  for (lnode = listhead (ospf6->area_list); lnode; nextnode (lnode))
+    {
+      oa = (struct ospf6_area *) getdata (lnode);
+      OSPF6_ROUTER_LSA_SCHEDULE (oa);
     }
 }
 
@@ -129,9 +695,9 @@
   else if (strncmp (argv[0], "bgp", 3) == 0)
     type = ZEBRA_ROUTE_BGP;
 
-  ospf6_zebra_no_redistribute (type);
+  ospf6_asbr_redistribute_unset (type);
   ospf6_asbr_routemap_unset (type);
-  ospf6_zebra_redistribute (type);
+  ospf6_asbr_redistribute_set (type);
   return CMD_SUCCESS;
 }
 
@@ -161,9 +727,9 @@
   else if (strncmp (argv[0], "bgp", 3) == 0)
     type = ZEBRA_ROUTE_BGP;
 
-  ospf6_zebra_no_redistribute (type);
+  ospf6_asbr_redistribute_unset (type);
   ospf6_asbr_routemap_set (type, argv[1]);
-  ospf6_zebra_redistribute (type);
+  ospf6_asbr_redistribute_set (type);
   return CMD_SUCCESS;
 }
 
@@ -180,9 +746,6 @@
       )
 {
   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;
@@ -195,48 +758,30 @@
   else if (strncmp (argv[0], "bgp", 3) == 0)
     type = ZEBRA_ROUTE_BGP;
 
-  ospf6_zebra_no_redistribute (type);
+  ospf6_asbr_redistribute_unset (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;
+  int type;
 
-  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+  for (type = 0; type < ZEBRA_ROUTE_MAX; type++)
     {
-      if (i == ZEBRA_ROUTE_OSPF6)
+      if (type == ZEBRA_ROUTE_OSPF6)
+        continue;
+      if (! ospf6_zebra_is_redistribute (type))
         continue;
 
-      if (! ospf6_zebra_is_redistribute (i))
-        continue;
-
-      if (rmap[i].map)
+      if (ospf6->rmap[type].name)
         vty_out (vty, " redistribute %s route-map %s%s",
-                 ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE);
+                 ZROUTE_NAME (type), ospf6->rmap[type].name, VTY_NEWLINE);
       else
         vty_out (vty, " redistribute %s%s",
-                 ZROUTE_NAME(i), VTY_NEWLINE);
+                 ZROUTE_NAME (type), VTY_NEWLINE);
     }
 
   return 0;
@@ -245,748 +790,420 @@
 void
 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)
-{
+  int type;
+  int nroute[ZEBRA_ROUTE_MAX];
+  int total;
+  struct ospf6_route *route;
   struct ospf6_external_info *info;
-  char buffer [MAXLSASIZE];
-  struct ospf6_lsa_as_external *e;
-  char *p;
 
-  info = THREAD_ARG (thread);
-
-  /* clear thread */
-  info->thread_originate = NULL;
-
-  if (info->is_removed)
+  total = 0;
+  for (type = 0; type < ZEBRA_ROUTE_MAX; type++)
+    nroute[type] = 0;
+  for (route = ospf6_route_head (ospf6->external_table); route;
+       route = ospf6_route_next (route))
     {
-      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;
+      info = route->route_option;
+      nroute[info->type]++;
+      total++;
     }
 
-  /* prepare buffer */
-  memset (buffer, 0, sizeof (buffer));
-  e = (struct ospf6_lsa_as_external *) buffer;
-  p = (char *) (e + 1);
-
-  if (info->metric_type == 2)
-    SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E);   /* type2 */
-  else
-    UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_E); /* type1, default */
-
-  /* forwarding address */
-  if (! IN6_IS_ADDR_UNSPECIFIED (&info->forwarding))
-    SET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F);
-  else
-    UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_F);
-
-  /* external route tag */
-  UNSET_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T);
-
-  /* set metric. note: related to E bit */
-  OSPF6_ASBR_METRIC_SET (e, info->metric);
-
-  /* prefixlen */
-  e->prefix.prefix_length = info->route->prefix.prefixlen;
-
-  /* PrefixOptions */
-  e->prefix.prefix_options = info->prefix_options;
-
-  /* don't use refer LS-type */
-  e->prefix.prefix_refer_lstype = htons (0);
-
-  /* set Prefix */
-  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 (e->bits_metric, OSPF6_ASBR_BIT_F))
+  vty_out (vty, "Redistributing External Routes from:%s", VTY_NEWLINE);
+  for (type = 0; type < ZEBRA_ROUTE_MAX; type++)
     {
-      memcpy (p, &info->forwarding, sizeof (struct in6_addr));
-      p += sizeof (struct in6_addr);
-    }
-
-  /* External Route Tag */
-  if (CHECK_FLAG (e->bits_metric, OSPF6_ASBR_BIT_T))
-    {
-      /* xxx */
-    }
-
-  ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
-                       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)
+      if (type == ZEBRA_ROUTE_OSPF6)
+        continue;
+      if (! ospf6_zebra_is_redistribute (type))
         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_route_add (int type, int ifindex, struct prefix *prefix,
-                      u_int nexthop_num, struct in6_addr *nexthop)
-{
-  int ret;
-  struct route_node *node;
-  struct ospf6_external_route *route;
-  struct ospf6_external_info *info, tinfo;
-
-#if defined (MUSICA) || defined (LINUX)
-  /* XXX As long as the OSPFv3 redistribution is applied to all the connected
-   *     routes, one needs to filter the ::/96 prefixes.
-   *     However it could be a wanted case, it will be removed soon.
-   */
-  struct prefix_ipv6 *p = (prefix_ipv6 *)prefix;
-
-  if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) ||
-      (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96))) 
-    return;
-#endif /* MUSICA or LINUX */
-
-  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;
+      if (ospf6->rmap[type].name)
+        vty_out (vty, "    %d: %s with route-map \"%s\"%s%s", nroute[type],
+                 ZROUTE_NAME (type), ospf6->rmap[type].name,
+                 (ospf6->rmap[type].map ? "" : " (not found !)"),
+                 VTY_NEWLINE);
       else
-        route->info_head = info;
-      route->info_tail = info;
-
-      info->id = link_state_id++;
+        vty_out (vty, "    %d: %s%s", nroute[type],
+                 ZROUTE_NAME (type), VTY_NEWLINE);
     }
+  vty_out (vty, "Total %d routes%s", total, VTY_NEWLINE);
+}
 
-  /* 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;
+
+/* Routemap Functions */
+route_map_result_t
+ospf6_routemap_rule_match_address_prefixlist (void *rule,
+                                              struct prefix *prefix,
+                                              route_map_object_t type,
+                                              void *object)
+{
+  struct prefix_list *plist;
 
-  if (nexthop_num && nexthop)
-    {
-      info->nexthop_num = nexthop_num;
+  if (type != RMAP_OSPF6)
+    return RMAP_NOMATCH;
 
-      if (info->nexthop)
-        XFREE (MTYPE_OSPF6_EXTERNAL_INFO, info->nexthop);
+  plist = prefix_list_lookup (AFI_IP6, (char *) rule);
+  if (plist == NULL)
+    return RMAP_NOMATCH;
 
-      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));
-    }
+  return (prefix_list_apply (plist, prefix) == PREFIX_DENY ?
+          RMAP_NOMATCH : RMAP_MATCH);
+}
 
-  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_routemap_rule_match_address_prefixlist_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
 }
 
 void
-ospf6_asbr_route_remove (int type, int ifindex, struct prefix *prefix)
+ospf6_routemap_rule_match_address_prefixlist_free (void *rule)
 {
-  struct route_node *node;
-  struct ospf6_external_route *route;
-  struct ospf6_external_info *info;
-  struct ospf6_lsa *lsa;
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
 
-#if defined (MUSICA) || defined (LINUX)
-  /* XXX As long as the OSPFv3 redistribution is applied to all the connected
-   *     routes, one needs to filter the ::/96 prefixes.
-   *     However it could be a wanted case, it will be removed soon.
-   */
-  struct prefix_ipv6 *p = (prefix_ipv6 *)prefix;
+struct route_map_rule_cmd
+ospf6_routemap_rule_match_address_prefixlist_cmd =
+{
+  "ipv6 address prefix-list",
+  ospf6_routemap_rule_match_address_prefixlist,
+  ospf6_routemap_rule_match_address_prefixlist_compile,
+  ospf6_routemap_rule_match_address_prefixlist_free,
+};
 
-  if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) ||
-      (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96))) 
-    return;
-#endif /* MUSICA or LINUX */
+route_map_result_t
+ospf6_routemap_rule_set_metric_type (void *rule, struct prefix *prefix,
+                                     route_map_object_t type, void *object)
+{
+  char *metric_type = rule;
+  struct ospf6_route *route = object;
 
-  node = route_node_get (external_table, prefix);
-  route = node->info;
+  if (type != RMAP_OSPF6)
+    return RMAP_OKAY;
 
-  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;
+  if (strcmp (metric_type, "type-2") == 0)
+    route->path.metric_type = 2;
   else
-    info->route->info_head = info->next;
-  if (info->next)
-    info->next->prev = info->prev;
-  else
-    info->route->info_tail = info->prev;
+    route->path.metric_type = 1;
 
-  /* if no info, free route */
-  if (! info->route->info_head && ! info->route->info_tail)
-    {
-      info->route->node->info = NULL;
-      free (info->route);
-    }
+  return RMAP_OKAY;
+}
 
-  if (info->nexthop)
-    free (info->nexthop);
-  free (info);
-#endif /*0*/
+void *
+ospf6_routemap_rule_set_metric_type_compile (char *arg)
+{
+  if (strcmp (arg, "type-2") && strcmp (arg, "type-1"))
+    return NULL;
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
 }
 
 void
-ospf6_asbr_external_lsa_add (struct ospf6_lsa *lsa)
+ospf6_routemap_rule_set_metric_type_free (void *rule)
 {
-  struct ospf6_lsa_as_external *external;
-  struct prefix_ls asbr_id;
-  struct ospf6_route_req asbr_entry;
-  struct ospf6_route_req request;
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
 
-  external = OSPF6_LSA_HEADER_END (lsa->header);
+struct route_map_rule_cmd
+ospf6_routemap_rule_set_metric_type_cmd =
+{
+  "metric-type",
+  ospf6_routemap_rule_set_metric_type,
+  ospf6_routemap_rule_set_metric_type_compile,
+  ospf6_routemap_rule_set_metric_type_free,
+};
 
-  if (IS_LSA_MAXAGE (lsa))
-    {
-      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;
-    }
+route_map_result_t
+ospf6_routemap_rule_set_metric (void *rule, struct prefix *prefix,
+                                route_map_object_t type, void *object)
+{
+  char *metric = rule;
+  struct ospf6_route *route = object;
 
-  if (IS_OSPF6_DUMP_ASBR)
-    zlog_info ("ASBR: new external lsa: %s seq: %lx",
-               lsa->str, (u_long)ntohl (lsa->header->seqnum));
+  if (type != RMAP_OSPF6)
+    return RMAP_OKAY;
 
-  if (lsa->header->adv_router == ospf6->router_id)
-    {
-      if (IS_OSPF6_DUMP_ASBR)
-        zlog_info ("ASBR: my external LSA, ignore");
-      return;
-    }
+  route->path.cost = atoi (metric);
+  return RMAP_OKAY;
+}
 
-  if (OSPF6_ASBR_METRIC (external) == LS_INFINITY)
-    {
-      if (IS_OSPF6_DUMP_ASBR)
-        zlog_info ("ASBR: metric is infinity, ignore");
-      return;
-    }
-
-  memset (&asbr_id, 0, sizeof (asbr_id));
-  asbr_id.family = AF_UNSPEC;
-  asbr_id.prefixlen = 64; /* xxx */
-  asbr_id.adv_router.s_addr = lsa->header->adv_router;
-
-  ospf6_route_lookup (&asbr_entry, (struct prefix *) &asbr_id,
-                      ospf6->topology_table);
-
-  if (ospf6_route_end (&asbr_entry))
-    {
-      if (IS_OSPF6_DUMP_ASBR)
-        {
-          char buf[64];
-          inet_ntop (AF_INET, &asbr_id.adv_router, buf, sizeof (buf));
-          zlog_info ("ASBR: router %s not found, ignore", buf);
-        }
-      return;
-    }
-
-  memset (&request, 0, sizeof (request));
-  request.route.type = OSPF6_DEST_TYPE_NETWORK;
-  request.route.prefix.family = AF_INET6;
-  request.route.prefix.prefixlen = external->prefix.prefix_length;
-  memcpy (&request.route.prefix.u.prefix6, (char *)(external + 1),
-          OSPF6_PREFIX_SPACE (request.route.prefix.prefixlen));
-
-  request.path.area_id = asbr_entry.path.area_id;
-  request.path.origin.type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL);
-  request.path.origin.id = lsa->header->id;
-  request.path.origin.adv_router = lsa->header->adv_router;
-  if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E))
-    {
-      request.path.type = OSPF6_PATH_TYPE_EXTERNAL2;
-      request.path.metric_type = 2;
-      request.path.cost = asbr_entry.path.cost;
-      request.path.cost_e2 = OSPF6_ASBR_METRIC (external);
-    }
-  else
-    {
-      request.path.type = OSPF6_PATH_TYPE_EXTERNAL1;
-      request.path.metric_type = 1;
-      request.path.cost = asbr_entry.path.cost
-                          + OSPF6_ASBR_METRIC (external);
-      request.path.cost_e2 = 0;
-    }
-  request.path.prefix_options = external->prefix.prefix_options;
-
-  while (((struct prefix_ls *)&asbr_entry.route.prefix)->adv_router.s_addr ==
-         asbr_id.adv_router.s_addr &&
-         asbr_entry.route.type == OSPF6_DEST_TYPE_ROUTER)
-    {
-      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);
-    }
+void *
+ospf6_routemap_rule_set_metric_compile (char *arg)
+{
+  u_int32_t metric;
+  char *endp;
+  metric = strtoul (arg, &endp, 0);
+  if (metric > LS_INFINITY || *endp != '\0')
+    return NULL;
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
 }
 
 void
-ospf6_asbr_external_lsa_remove (struct ospf6_lsa *lsa)
+ospf6_routemap_rule_set_metric_free (void *rule)
 {
-  struct ospf6_lsa_as_external *external;
-  struct prefix dest;
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd
+ospf6_routemap_rule_set_metric_cmd =
+{
+  "metric",
+  ospf6_routemap_rule_set_metric,
+  ospf6_routemap_rule_set_metric_compile,
+  ospf6_routemap_rule_set_metric_free,
+};
+
+route_map_result_t
+ospf6_routemap_rule_set_forwarding (void *rule, struct prefix *prefix,
+                                    route_map_object_t type, void *object)
+{
+  char *forwarding = rule;
+  struct ospf6_route *route = object;
+  struct ospf6_external_info *info = route->route_option;
+
+  if (type != RMAP_OSPF6)
+    return RMAP_OKAY;
+
+  if (inet_pton (AF_INET6, forwarding, &info->forwarding) != 1)
+    {
+      memset (&info->forwarding, 0, sizeof (struct in6_addr));
+      return RMAP_ERROR;
+    }
+
+  return RMAP_OKAY;
+}
+
+void *
+ospf6_routemap_rule_set_forwarding_compile (char *arg)
+{
+  struct in6_addr a;
+  if (inet_pton (AF_INET6, arg, &a) != 1)
+    return NULL;
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+ospf6_routemap_rule_set_forwarding_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd
+ospf6_routemap_rule_set_forwarding_cmd =
+{
+  "forwarding-address",
+  ospf6_routemap_rule_set_forwarding,
+  ospf6_routemap_rule_set_forwarding_compile,
+  ospf6_routemap_rule_set_forwarding_free,
+};
+
+int
+route_map_command_status (struct vty *vty, int ret)
+{
+  if (! ret)
+    return CMD_SUCCESS;
+
+  switch (ret)
+    {
+    case RMAP_RULE_MISSING:
+      vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
+      break;
+    case RMAP_COMPILE_ERROR:
+      vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
+      break;
+    default:
+      vty_out (vty, "route-map add set failed.%s", VTY_NEWLINE);
+      break;
+    }
+  return CMD_WARNING;
+}
+
+/* add "match address" */
+DEFUN (ospf6_routemap_match_address_prefixlist,
+       ospf6_routemap_match_address_prefixlist_cmd,
+       "match ipv6 address prefix-list WORD",
+       "Match values\n"
+       IPV6_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IPv6 prefix-list name\n")
+{
+  int ret = route_map_add_match ((struct route_map_index *) vty->index,
+                                 "ipv6 address prefix-list", argv[0]);
+  return route_map_command_status (vty, ret);
+}
+
+/* delete "match address" */
+DEFUN (ospf6_routemap_no_match_address_prefixlist,
+       ospf6_routemap_no_match_address_prefixlist_cmd,
+       "no match ipv6 address prefix-list WORD",
+       NO_STR
+       "Match values\n"
+       IPV6_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IPv6 prefix-list name\n")
+{
+  int ret = route_map_delete_match ((struct route_map_index *) vty->index,
+                                    "ipv6 address prefix-list", argv[0]);
+  return route_map_command_status (vty, ret);
+}
+
+/* add "set metric-type" */
+DEFUN (ospf6_routemap_set_metric_type,
+       ospf6_routemap_set_metric_type_cmd,
+       "set metric-type (type-1|type-2)",
+       "Set value\n"
+       "Type of metric\n"
+       "OSPF6 external type 1 metric\n"
+       "OSPF6 external type 2 metric\n")
+{
+  int ret = route_map_add_set ((struct route_map_index *) vty->index,
+                               "metric-type", argv[0]);
+  return route_map_command_status (vty, ret);
+}
+
+/* delete "set metric-type" */
+DEFUN (ospf6_routemap_no_set_metric_type,
+       ospf6_routemap_no_set_metric_type_cmd,
+       "no set metric-type (type-1|type-2)",
+       NO_STR
+       "Set value\n"
+       "Type of metric\n"
+       "OSPF6 external type 1 metric\n"
+       "OSPF6 external type 2 metric\n")
+{
+  int ret = route_map_delete_set ((struct route_map_index *) vty->index,
+                                  "metric-type", argv[0]);
+  return route_map_command_status (vty, ret);
+}
+
+/* add "set metric" */
+DEFUN (set_metric,
+       set_metric_cmd,
+       "set metric <0-4294967295>",
+       "Set value\n"
+       "Metric value\n"
+       "Metric value\n")
+{
+  int ret = route_map_add_set ((struct route_map_index *) vty->index,
+                               "metric", argv[0]);
+  return route_map_command_status (vty, ret);
+}
+
+/* delete "set metric" */
+DEFUN (no_set_metric,
+       no_set_metric_cmd,
+       "no set metric <0-4294967295>",
+       NO_STR
+       "Set value\n"
+       "Metric\n"
+       "METRIC value\n")
+{
+  int ret = route_map_delete_set ((struct route_map_index *) vty->index,
+                                  "metric", argv[0]);
+  return route_map_command_status (vty, ret);
+}
+
+/* add "set forwarding-address" */
+DEFUN (ospf6_routemap_set_forwarding,
+       ospf6_routemap_set_forwarding_cmd,
+       "set forwarding-address X:X::X:X",
+       "Set value\n"
+       "Forwarding Address\n"
+       "IPv6 Address\n")
+{
+  int ret = route_map_add_set ((struct route_map_index *) vty->index,
+                               "forwarding-address", argv[0]);
+  return route_map_command_status (vty, ret);
+}
+
+/* delete "set forwarding-address" */
+DEFUN (ospf6_routemap_no_set_forwarding,
+       ospf6_routemap_no_set_forwarding_cmd,
+       "no set forwarding-address X:X::X:X",
+       NO_STR
+       "Set value\n"
+       "Forwarding Address\n"
+       "IPv6 Address\n")
+{
+  int ret = route_map_delete_set ((struct route_map_index *) vty->index,
+                                  "forwarding-address", argv[0]);
+  return route_map_command_status (vty, ret);
+}
+
+void
+ospf6_routemap_init ()
+{
+  route_map_init ();
+  route_map_init_vty ();
+  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);
+  route_map_install_set (&ospf6_routemap_rule_set_metric_cmd);
+  route_map_install_set (&ospf6_routemap_rule_set_forwarding_cmd);
+
+  /* Match address prefix-list */
+  install_element (RMAP_NODE, &ospf6_routemap_match_address_prefixlist_cmd);
+  install_element (RMAP_NODE, &ospf6_routemap_no_match_address_prefixlist_cmd);
+
+  /* ASE Metric Type (e.g. Type-1/Type-2) */
+  install_element (RMAP_NODE, &ospf6_routemap_set_metric_type_cmd);
+  install_element (RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd);
+
+  /* ASE Metric */
+  install_element (RMAP_NODE, &set_metric_cmd);
+  install_element (RMAP_NODE, &no_set_metric_cmd);
+
+  /* ASE Metric */
+  install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd);
+  install_element (RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd);
+}
+
+
+/* Display functions */
+int
+ospf6_as_external_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+  struct ospf6_as_external_lsa *external;
   char buf[64];
-  struct ospf6_route_req request;
-
-  if (IS_OSPF6_DUMP_ASBR)
-    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: my external LSA, ignore");
-      return;
-    }
-
-  external = OSPF6_LSA_HEADER_END (lsa->header);
-  memset (&dest, 0, sizeof (dest));
-  dest.family = AF_INET6;
-  dest.prefixlen = external->prefix.prefix_length;
-  memcpy (&dest.u.prefix6, (char *)(external + 1),
-          OSPF6_PREFIX_SPACE (dest.prefixlen));
-
-  ospf6_route_lookup (&request, &dest, ospf6->route_table);
-  if (ospf6_route_end (&request))
-    {
-      if (IS_OSPF6_DUMP_ASBR)
-        {
-          prefix2str (&dest, buf, sizeof (buf));
-          zlog_info ("ASBR: %s not found", buf);
-        }
-      return;
-    }
-
-  while (request.path.origin.id != lsa->header->id ||
-         request.path.origin.adv_router != lsa->header->adv_router)
-    {
-      if (prefix_same (&request.route.prefix, &dest) != 1)
-        {
-          if (IS_OSPF6_DUMP_ASBR)
-            zlog_info ("ASBR:   Can't find the entry matches the origin");
-          return;
-        }
-      ospf6_route_next (&request);
-    }
-  assert (request.path.origin.id == lsa->header->id);
-  assert (request.path.origin.adv_router == request.path.origin.adv_router);
-
-  while (request.path.origin.id == lsa->header->id &&
-         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);
-    }
-}
-
-void
-ospf6_asbr_external_lsa_change (struct ospf6_lsa *old, struct ospf6_lsa *new)
-{
-  assert (old || new);
-
-  if (old == NULL)
-    ospf6_asbr_external_lsa_add (new);
-  else if (new == NULL)
-    ospf6_asbr_external_lsa_remove (old);
-  else
-    {
-      ospf6_route_table_freeze (ospf6->route_table);
-      ospf6_asbr_external_lsa_remove (old);
-      ospf6_asbr_external_lsa_add (new);
-      ospf6_route_table_thaw (ospf6->route_table);
-    }
-}
-
-void
-ospf6_asbr_asbr_entry_add (struct ospf6_route_req *topo_entry)
-{
-  struct ospf6_lsdb_node node;
-
-  struct prefix_ls *inter_router;
-  u_int32_t id, adv_router;
-
-  inter_router = (struct prefix_ls *) &topo_entry->route.prefix;
-  id = inter_router->id.s_addr;
-  adv_router = inter_router->adv_router.s_addr;
-
-  if (IS_OSPF6_DUMP_ASBR)
-    {
-      char buf[64];
-      inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf));
-      zlog_info ("ASBR: new router found: %s", buf);
-    }
-
-  if (ntohl (id) != 0 ||
-      ! OSPF6_OPT_ISSET (topo_entry->path.capability, OSPF6_OPT_E))
-    {
-      zlog_warn ("ASBR: Inter topology table malformed");
-      return;
-    }
-
-  for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
-                               adv_router, ospf6->lsdb);
-       ! ospf6_lsdb_is_end (&node);
-       ospf6_lsdb_next (&node))
-    ospf6_asbr_external_lsa_add (node.lsa);
-}
-
-void
-ospf6_asbr_asbr_entry_remove (struct ospf6_route_req *topo_entry)
-{
-  struct prefix_ls *inter_router;
-  u_int32_t id, adv_router;
-  struct ospf6_route_req request;
-
-  inter_router = (struct prefix_ls *) &topo_entry->route.prefix;
-  id = inter_router->id.s_addr;
-  adv_router = inter_router->adv_router.s_addr;
-
-  if (IS_OSPF6_DUMP_ASBR)
-    {
-      char buf[64];
-      inet_ntop (AF_INET, &inter_router->adv_router, buf, sizeof (buf));
-      zlog_info ("ASBR: router disappearing: %s", buf);
-    }
-
-  if (ntohl (id) != 0 ||
-      ! OSPF6_OPT_ISSET (topo_entry->path.capability, OSPF6_OPT_E))
-    {
-      zlog_warn ("ASBR: Inter topology table malformed");
-    }
-
-  for (ospf6_route_head (&request, ospf6->route_table);
-       ! ospf6_route_end (&request);
-       ospf6_route_next (&request))
-    {
-      if (request.path.type != OSPF6_PATH_TYPE_EXTERNAL1 &&
-          request.path.type != OSPF6_PATH_TYPE_EXTERNAL2)
-        continue;
-      if (request.path.area_id != topo_entry->path.area_id)
-        continue;
-      if (request.path.origin.adv_router != topo_entry->path.origin.adv_router)
-        continue;
-      if (memcmp (&topo_entry->nexthop, &request.nexthop,
-                  sizeof (struct ospf6_nexthop)))
-        continue;
-
-      ospf6_route_remove (&request, ospf6->route_table);
-    }
-}
-
-int
-ospf6_asbr_external_show (struct vty *vty, struct ospf6_lsa *lsa)
-{
-  struct ospf6_lsa_as_external *external;
-  char buf[128], *ptr;
-  struct in6_addr in6;
+  struct in6_addr in6, *forwarding;
 
   assert (lsa->header);
-  external = (struct ospf6_lsa_as_external *)(lsa->header + 1);
+  external = (struct ospf6_as_external_lsa *)
+    OSPF6_LSA_HEADER_END (lsa->header);
   
   /* bits */
-  snprintf (buf, sizeof (buf), "%s%s%s",
-            (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E) ?
-             "E" : "-"),
-            (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F) ?
-             "F" : "-"),
-            (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T) ?
-             "T" : "-"));
+  snprintf (buf, sizeof (buf), "%c%c%c",
+    (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E) ? 'E' : '-'),
+    (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F) ? 'F' : '-'),
+    (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T) ? 'T' : '-'));
 
   vty_out (vty, "     Bits: %s%s", buf, VTY_NEWLINE);
-  vty_out (vty, "     Metric: %5lu%s", (u_long)OSPF6_ASBR_METRIC (external),
+  vty_out (vty, "     Metric: %5lu%s", (u_long) OSPF6_ASBR_METRIC (external),
            VTY_NEWLINE);
 
-  ospf6_prefix_options_str (external->prefix.prefix_options,
-                            buf, sizeof (buf));
-  vty_out (vty, "     Prefix Options: %s%s", buf, VTY_NEWLINE);
+  ospf6_prefix_options_printbuf (external->prefix.prefix_options,
+                                 buf, sizeof (buf));
+  vty_out (vty, "     Prefix Options: %s%s", buf,
+           VTY_NEWLINE);
 
   vty_out (vty, "     Referenced LSType: %d%s",
-           ntohs (external->prefix.prefix_refer_lstype), VTY_NEWLINE);
+           ntohs (external->prefix.prefix_refer_lstype),
+           VTY_NEWLINE);
 
-  ospf6_prefix_in6_addr (&external->prefix, &in6);
+  ospf6_prefix_in6_addr (&in6, &external->prefix);
   inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
-  vty_out (vty, "     Prefix: %s/%d%s",
-           buf, external->prefix.prefix_length, VTY_NEWLINE);
+  vty_out (vty, "     Prefix: %s/%d%s", buf,
+           external->prefix.prefix_length, VTY_NEWLINE);
 
   /* Forwarding-Address */
   if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F))
     {
-      ptr = ((char *)(external + 1))
-            + OSPF6_PREFIX_SPACE (external->prefix.prefix_length);
-      inet_ntop (AF_INET6, (struct in6_addr *) ptr, buf, sizeof (buf));
+      forwarding = (struct in6_addr *)
+        ((caddr_t) external + sizeof (struct ospf6_as_external_lsa) +
+         OSPF6_PREFIX_SPACE (external->prefix.prefix_length));
+      inet_ntop (AF_INET6, forwarding, buf, sizeof (buf));
       vty_out (vty, "     Forwarding-Address: %s%s", buf, VTY_NEWLINE);
     }
 
@@ -994,96 +1211,184 @@
 }
 
 void
-ospf6_asbr_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new)
+ospf6_asbr_external_route_show (struct vty *vty, struct ospf6_route *route)
 {
-  if (old)
-    ospf6_asbr_external_lsa_remove (old);
-  if (new && ! IS_LSA_MAXAGE (new))
-    ospf6_asbr_external_lsa_add (new);
+  struct ospf6_external_info *info = route->route_option;
+  char prefix[64], id[16], forwarding[64];
+  u_int32_t tmp_id;
+
+  prefix2str (&route->prefix, prefix, sizeof (prefix));
+  tmp_id = ntohl (info->id);
+  inet_ntop (AF_INET, &tmp_id, id, sizeof (id));
+  if (! IN6_IS_ADDR_UNSPECIFIED (&info->forwarding))
+    inet_ntop (AF_INET6, &info->forwarding, forwarding, sizeof (forwarding));
+  else
+    snprintf (forwarding, sizeof (forwarding), ":: (ifindex %d)",
+              route->nexthop[0].ifindex);
+
+  vty_out (vty, "%s %-32s %-15s type-%d %5lu %s%s",
+           ZROUTE_ABNAME (info->type),
+           prefix, id, route->path.metric_type,
+           (u_long) (route->path.metric_type == 2 ?
+                     route->path.cost_e2 : route->path.cost),
+           forwarding, VTY_NEWLINE);
 }
 
-void
-ospf6_asbr_register_as_external ()
-{
-  struct ospf6_lsa_slot slot;
-
-  memset (&slot, 0, sizeof (slot));
-  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_lsa_refresh;
-  ospf6_lsa_slot_register (&slot);
-
-  ospf6_lsdb_hook[OSPF6_LSA_TYPE_AS_EXTERNAL & OSPF6_LSTYPE_CODE_MASK].hook = 
-    ospf6_asbr_database_hook;
-}
-
-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",
+DEFUN (show_ipv6_ospf6_redistribute,
+       show_ipv6_ospf6_redistribute_cmd,
+       "show ipv6 ospf6 redistribute",
        SHOW_STR
        IP6_STR
-       ROUTE_STR
        OSPF6_STR
        "redistributing External information\n"
        )
 {
-  struct route_node *node;
-  struct ospf6_external_route *route;
+  struct ospf6_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);
-    }
+  ospf6_redistribute_show_config (vty);
+
+  for (route = ospf6_route_head (ospf6->external_table); route;
+       route = ospf6_route_next (route))
+    ospf6_asbr_external_route_show (vty, route);
+
   return CMD_SUCCESS;
 }
 
+DEFUN (show_ipv6_ospf6_asbr,
+       show_ipv6_ospf6_asbr_cmd,
+       "show ipv6 ospf6 asbr",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Show AS Boundary Router table\n"
+      )
+{
+  ospf6_lsentry_table_show (vty, argc, argv, ospf6->asbr_table);
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_asbr,
+       show_ipv6_ospf6_asbr_1_cmd,
+       "show ipv6 ospf6 asbr (A.B.C.D|A.B.C.D/M|detail)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Show AS Boundary Router table\n"
+       "Specify Router-ID\n"
+       "Display multiple entry by specifying match-prefix of Router-ID\n"
+       "Display Detail\n"
+      );
+
+ALIAS (show_ipv6_ospf6_asbr,
+       show_ipv6_ospf6_asbr_2_cmd,
+       "show ipv6 ospf6 asbr (A.B.C.D|A.B.C.D/M|*) (A.B.C.D|A.B.C.D/M|detail)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Show AS Boundary Router table\n"
+       "Specify Router-ID\n"
+       "Display multiple entry by specifying match-prefix of Router-ID\n"
+       "Wildcard Router-ID\n"
+       "Specify Link State ID\n"
+       "Display multiple entry by specifying match-prefix of Link State ID\n"
+       "Display Detail\n"
+      );
+
+DEFUN (show_ipv6_ospf6_asbr_3,
+       show_ipv6_ospf6_asbr_3_cmd,
+       "show ipv6 ospf6 asbr (A.B.C.D|*) A.B.C.D/M detail",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Show AS Boundary Router table\n"
+       "Specify Router-ID\n"
+       "Wildcard Router-ID\n"
+       "Display multiple entry by specifying match-prefix of Link State ID\n"
+       "Display Detail\n"
+      )
+{
+  char *sargv[CMD_ARGC_MAX];
+  int i, sargc;
+
+  /* copy argv to sargv and then append "detail" */
+  for (i = 0; i < argc; i++)
+    sargv[i] = argv[i];
+  sargc = argc;
+  sargv[sargc++] = "detail";
+  sargv[sargc] = NULL;
+
+  ospf6_lsentry_table_show (vty, sargc, sargv, ospf6->asbr_table);
+  return CMD_SUCCESS;
+}
+
+
 void
 ospf6_asbr_init ()
 {
-  external_table = route_table_init ();
-  link_state_id = 0;
+  ospf6_routemap_init ();
 
-  ospf6_asbr_register_as_external ();
+  ospf6_lstype[5].name = "AS-External";
+  ospf6_lstype[5].reoriginate = ospf6_as_external_lsa_reoriginate;
+  ospf6_lstype[5].show = ospf6_as_external_lsa_show;
 
-  install_element (VIEW_NODE, &show_ipv6_route_ospf6_external_cmd);
-  install_element (ENABLE_NODE, &show_ipv6_route_ospf6_external_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_redistribute_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_redistribute_cmd);
+
+  install_element (VIEW_NODE, &show_ipv6_ospf6_asbr_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_asbr_1_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_asbr_2_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_asbr_3_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_asbr_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_asbr_1_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_asbr_2_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_asbr_3_cmd);
+
   install_element (OSPF6_NODE, &ospf6_redistribute_cmd);
   install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd);
   install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd);
 }
 
 
+DEFUN (debug_ospf6_asbr,
+       debug_ospf6_asbr_cmd,
+       "debug ospf6 asbr",
+       DEBUG_STR
+       OSPF6_STR
+       "Debug OSPFv3 ASBR function\n"
+      )
+{
+  OSPF6_DEBUG_ASBR_ON ();
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ospf6_asbr,
+       no_debug_ospf6_asbr_cmd,
+       "no debug ospf6 asbr",
+       NO_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Debug OSPFv3 ASBR function\n"
+      )
+{
+  OSPF6_DEBUG_ASBR_OFF ();
+  return CMD_SUCCESS;
+}
+
+int
+config_write_ospf6_debug_asbr (struct vty *vty)
+{
+  if (IS_OSPF6_DEBUG_ASBR)
+    vty_out (vty, "debug ospf6 asbr%s", VTY_NEWLINE);
+  return 0;
+}
+
+void
+install_element_ospf6_debug_asbr ()
+{
+  install_element (ENABLE_NODE, &debug_ospf6_asbr_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf6_asbr_cmd);
+  install_element (CONFIG_NODE, &debug_ospf6_asbr_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf6_asbr_cmd);
+}
+
+
diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h
index 153ed21..f3aabc8 100644
--- a/ospf6d/ospf6_asbr.h
+++ b/ospf6d/ospf6_asbr.h
@@ -22,53 +22,29 @@
 #ifndef OSPF6_ASBR_H
 #define OSPF6_ASBR_H
 
-#include "thread.h"
+/* Debug option */
+extern unsigned char conf_debug_ospf6_asbr;
+#define OSPF6_DEBUG_ASBR_ON() \
+  (conf_debug_ospf6_asbr = 1)
+#define OSPF6_DEBUG_ASBR_OFF() \
+  (conf_debug_ospf6_asbr = 0)
+#define IS_OSPF6_DEBUG_ASBR \
+  (conf_debug_ospf6_asbr)
 
 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 */
+  /* External route type */
   int type;
 
-  /* external route ifindex */
-  int ifindex;
-
-  /* LS-ID */
+  /* Originating Link State 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
+struct ospf6_as_external_lsa
 {
   u_int32_t bits_metric;
 
@@ -87,26 +63,24 @@
   { (E)->bits_metric &= htonl (0xff000000); \
     (E)->bits_metric |= htonl (0x00ffffff) & htonl (C); }
 
-void ospf6_asbr_routemap_update ();
+void ospf6_asbr_lsa_add (struct ospf6_lsa *lsa);
+void ospf6_asbr_lsa_remove (struct ospf6_lsa *lsa);
+void ospf6_asbr_lsentry_add (struct ospf6_route *asbr_entry);
+void ospf6_asbr_lsentry_remove (struct ospf6_route *asbr_entry);
+
+int ospf6_asbr_is_asbr (struct ospf6 *o);
+void
+ospf6_asbr_redistribute_add (int type, int ifindex, struct prefix *prefix,
+                             u_int nexthop_num, struct in6_addr *nexthop);
+void
+ospf6_asbr_redistribute_remove (int type, int ifindex, struct prefix *prefix);
 
 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);
-void ospf6_asbr_external_lsa_change (struct ospf6_lsa *old,
-                                     struct ospf6_lsa *new);
-
-void ospf6_asbr_asbr_entry_add (struct ospf6_route_req *topo_entry);
-void ospf6_asbr_asbr_entry_remove (struct ospf6_route_req *topo_entry);
 
 void ospf6_asbr_init ();
 
+int config_write_ospf6_debug_asbr (struct vty *vty);
+void install_element_ospf6_debug_asbr ();
+
 #endif /* OSPF6_ASBR_H */
 
diff --git a/ospf6d/ospf6_bintree.c b/ospf6d/ospf6_bintree.c
deleted file mode 100644
index c1e9e55..0000000
--- a/ospf6d/ospf6_bintree.c
+++ /dev/null
@@ -1,436 +0,0 @@
-
-#include <zebra.h>
-#include "ospf6_bintree.h"
-
-static struct bintree_node *
-bintree_lookup_node_min (struct bintree_node *subroot)
-{
-  struct bintree_node *node;
-
-  if (subroot == NULL)
-    return NULL;
-
-  node = subroot;
-  while (node->bl_left)
-    node = node->bl_left;
-  return node;
-}
-
-static struct bintree_node *
-bintree_lookup_node_max (struct bintree_node *subroot)
-{
-  struct bintree_node *node;
-
-  assert (subroot != NULL);
-  node = subroot;
-  while (node->bl_right)
-    node = node->bl_right;
-  return node;
-}
-
-void *
-bintree_lookup (void *data, struct bintree *tree)
-{
-  int cmp;
-  struct bintree_node *node;
-
-  node = tree->root;
-
-  while (node)
-    {
-      if (tree->cmp)
-        cmp = (*tree->cmp) (node->data, data);
-      else
-        cmp = (node->data - data);
-
-      if (cmp == 0)
-        break;
-
-      if (cmp > 0)
-        node = node->bl_left;
-      else /* if (cmp < 0) */
-        node = node->bl_right;
-    }
-
-  if (node)
-    return node->data;
-
-  return NULL;
-}
-
-void *
-bintree_lookup_min (struct bintree *tree)
-{
-  struct bintree_node *node;
-  node = bintree_lookup_node_min (tree->root);
-  if (node == NULL)
-    return NULL;
-  return node->data;
-}
-
-void *
-bintree_lookup_max (struct bintree *tree)
-{
-  struct bintree_node *node;
-  node = bintree_lookup_node_max (tree->root);
-  if (node == NULL)
-    return NULL;
-  return node->data;
-}
-
-int
-bintree_add (void *data, struct bintree *tree)
-{
-  int cmp = 0;
-  struct bintree_node *node, *parent;
-
-  node = tree->root;
-  parent = NULL;
-
-  while (node)
-    {
-      if (tree->cmp)
-        cmp = (*tree->cmp) (node->data, data);
-      else
-        cmp = (node->data - data);
-
-      if (cmp == 0)
-        break;
-
-      parent = node;
-      if (cmp > 0)
-        node = node->bl_left;
-      else /* if (cmp < 0) */
-        node = node->bl_right;
-    }
-
-  if (node)
-    return -1;
-
-  node = malloc (sizeof (struct bintree_node));
-  memset (node, 0, sizeof (struct bintree_node));
-  node->tree = tree;
-  node->data = data;
-
-  if (parent)
-    {
-      node->parent = parent;
-
-      assert (cmp != 0);
-      if (cmp > 0)
-        {
-          node->parent_link = BL_LEFT;
-          parent->bl_left = node;
-        }
-      else /* if (cmp < 0) */
-        {
-          node->parent_link = BL_RIGHT;
-          parent->bl_right = node;
-        }
-    }
-  else
-    tree->root = node;
-
-  tree->count++;
-  return 0;
-}
-
-static void
-bintree_remove_nochild (struct bintree_node *node)
-{
-  assert (node->bl_left == NULL && node->bl_right == NULL);
-
-  if (node->parent == NULL)
-    node->tree->root = NULL;
-  else
-    node->parent->link[node->parent_link] = NULL;
-}
-
-static void
-bintree_remove_onechild (struct bintree_node *node)
-{
-  assert ((node->bl_left == NULL && node->bl_right != NULL) ||
-          (node->bl_left != NULL && node->bl_right == NULL));
-
-  if (node->bl_left)
-    {
-      if (node->parent == NULL)
-        {
-          node->tree->root = node->bl_left;
-          node->bl_left->parent = NULL;
-        }
-      else
-        {
-          node->parent->link[node->parent_link] = node->bl_left;
-          node->bl_left->parent = node->parent;
-          node->bl_left->parent_link = node->parent_link;
-        }
-    }
-  else if (node->bl_right)
-    {
-      if (node->parent == NULL)
-        {
-          node->tree->root = node->bl_right;
-          node->bl_right->parent = NULL;
-        }
-      else
-        {
-          node->parent->link[node->parent_link] = node->bl_right;
-          node->bl_right->parent = node->parent;
-          node->bl_right->parent_link = node->parent_link;
-        }
-    }
-  else
-    assert (0);
-}
-
-int
-bintree_remove (void *data, struct bintree *tree)
-{
-  int cmp;
-  struct bintree_node *node;
-
-  node = tree->root;
-
-  while (node)
-    {
-      if (tree->cmp)
-        cmp = (*tree->cmp) (node->data, data);
-      else
-        cmp = (node->data - data);
-
-      if (cmp == 0)
-        break;
-
-      if (cmp > 0)
-        node = node->bl_left;
-      else /* if (cmp < 0) */
-        node = node->bl_right;
-    }
-
-  if (node == NULL)
-    return -1;
-
-  if (node->bl_left == NULL && node->bl_right == NULL)
-    {
-      bintree_remove_nochild (node);
-      free (node);
-      tree->count--;
-      return 0;
-    }
-
-  if ((node->bl_left == NULL && node->bl_right != NULL) ||
-      (node->bl_left != NULL && node->bl_right == NULL))
-    {
-      bintree_remove_onechild (node);
-      free (node);
-      tree->count--;
-      return 0;
-    }
-
-  if (node->bl_left != NULL && node->bl_right != NULL)
-    {
-      struct bintree_node *successor;
-
-      /* find successor of the removing node */
-      successor = bintree_lookup_node_min (node->bl_right);
-
-      /* remove successor from tree */
-      if (successor->bl_right)
-        bintree_remove_onechild (successor);
-      else
-        bintree_remove_nochild (successor);
-
-      /* swap removing node with successor */
-      successor->parent = node->parent;
-      successor->parent_link = node->parent_link;
-      successor->bl_left = node->bl_left;
-      successor->bl_right = node->bl_right;
-
-      /* if the successor was the node->bl_right itself,
-         bintree_remove_**child may touch node->bl_right,
-         so only the successor->bl_right may be NULL
-         by above assignment */
-      successor->bl_left->parent = successor;
-      if (successor->bl_right)
-        successor->bl_right->parent = successor;
-
-      if (successor->parent == NULL)
-        tree->root = successor;
-      else
-        successor->parent->link[successor->parent_link] = successor;
-
-      free (node);
-      tree->count--;
-      return 0;
-    }
-
-  /* not reached */
-  return -1;
-}
-
-/* in-order traversal */
-
-void
-bintree_head (struct bintree *tree, struct bintree_node *node)
-{
-  struct bintree_node *head;
-
-  head = bintree_lookup_node_min (tree->root);
-  if (head == NULL)
-    {
-      node->parent = NULL;
-      node->bl_left = NULL;
-      node->bl_right = NULL;
-      node->data = NULL;
-      return;
-    }
-
-  node->tree = head->tree;
-  node->parent = head->parent;
-  node->parent_link = head->parent_link;
-  node->bl_left = head->bl_left;
-  node->bl_right = head->bl_right;
-  node->data = head->data;
-}
-
-int
-bintree_end (struct bintree_node *node)
-{
-  if (node->parent || node->bl_left || node->bl_right || node->data)
-    return 0;
-  return 1;
-}
-
-#define GOTO_PROCED_SUBTREE_TOP(node) \
-  while (node->parent && node->parent->bl_right && \
-         node->parent->bl_right->data == node->data) \
-    { \
-      node->data = node->parent->data; \
-      node->bl_left = node->parent->bl_left; \
-      node->bl_right = node->parent->bl_right; \
-      node->parent_link = node->parent->parent_link; \
-      node->parent = node->parent->parent; \
-    }
-
-void
-bintree_next (struct bintree_node *node)
-{
-  struct bintree_node *next = NULL;
-
-  /* if node have just been removed, current point should have just been
-     replaced with its successor. that certainly  will not be processed
-     yet, so process it */
-  if (node->parent == NULL)
-    {
-      if (node->tree->root == NULL)
-        {
-          assert (node->tree->count == 0);
-          node->parent = NULL;
-          node->bl_left = NULL;
-          node->bl_right = NULL;
-          node->data = NULL;
-          return;
-        }
-      else if (node->tree->root->data != node->data)
-        next = node->tree->root;
-    }
-  else if (node->parent->link[node->parent_link] == NULL)
-    {
-      if (node->parent_link == BL_LEFT)
-        next = node->parent;
-      else
-        {
-          GOTO_PROCED_SUBTREE_TOP (node);
-          next = node->parent;
-        }
-    }
-  else if (node->parent->link[node->parent_link]->data != node->data)
-    next = node->parent->link[node->parent_link];
-
-  if (next == NULL)
-    {
-      if (node->bl_right)
-        next = bintree_lookup_node_min (node->bl_right);
-      else
-        {
-          GOTO_PROCED_SUBTREE_TOP (node);
-          next = node->parent;
-        }
-    }
-
-  if (next)
-    {
-      node->tree = next->tree;
-      node->parent = next->parent;
-      node->parent_link = next->parent_link;
-      node->bl_left = next->bl_left;
-      node->bl_right = next->bl_right;
-      node->data = next->data;
-    }
-  else
-    {
-      node->parent = NULL;
-      node->bl_left = NULL;
-      node->bl_right = NULL;
-      node->data = NULL;
-    }
-}
-
-struct bintree *
-bintree_create ()
-{
-  struct bintree *tree;
-
-  tree = malloc (sizeof (struct bintree));
-  memset (tree, 0, sizeof (struct bintree));
-
-  return tree;
-}
-
-void
-bintree_delete (struct bintree *tree)
-{
-  struct bintree_node node;
-
-  for (bintree_head (tree, &node); ! bintree_end (&node);
-       bintree_next (&node))
-    bintree_remove (node.data, tree);
-
-  assert (tree->count == 0);
-  free (tree);
-}
-
-int indent_num = 0;
-
-void
-bintree_print_sub (void (*print) (int, void *), struct bintree_node *subroot)
-{
-  if (subroot == NULL)
-    return;
-
-  if (subroot->bl_right)
-    {
-      indent_num++;
-      bintree_print_sub (print, subroot->bl_right);
-      indent_num--;
-    }
-
-  (*print) (indent_num, subroot->data);
-
-  if (subroot->bl_left)
-    {
-      indent_num++;
-      bintree_print_sub (print, subroot->bl_left);
-      indent_num--;
-    }
-}
-
-void
-bintree_print (void (*print) (int, void *), struct bintree *tree)
-{
-  indent_num = 0;
-  bintree_print_sub (print, tree->root);
-}
-
-
diff --git a/ospf6d/ospf6_bintree.h b/ospf6d/ospf6_bintree.h
deleted file mode 100644
index fad8bbd..0000000
--- a/ospf6d/ospf6_bintree.h
+++ /dev/null
@@ -1,47 +0,0 @@
-
-#ifndef _BINTREE_H_
-#define _BINTREE_H_
-
-struct bintree_node
-{
-  struct bintree *tree;
-
-  struct bintree_node *parent;
-  int parent_link;
-
-#define BL_LEFT  0
-#define BL_RIGHT 1
-#define BL_MAX   2
-  struct bintree_node *link[BL_MAX];
-#define bl_left  link[BL_LEFT]
-#define bl_right link[BL_RIGHT]
-
-  void *data;
-};
-
-struct bintree
-{
-  int count;
-  struct bintree_node *root;
-
-  int  (*cmp)   (void *, void *);
-};
-
-void *bintree_lookup (void *data, struct bintree *tree);
-void *bintree_lookup_min (struct bintree *tree);
-void *bintree_lookup_max (struct bintree *tree);
-
-int   bintree_add (void *data, struct bintree *tree);
-int   bintree_remove (void *data, struct bintree *tree);
-
-void bintree_head (struct bintree *tree, struct bintree_node *node);
-int  bintree_end (struct bintree_node *node);
-void bintree_next (struct bintree_node *node);
-
-struct bintree *bintree_create ();
-void bintree_delete (struct bintree *);
-
-void bintree_print (void (*print) (int, void *), struct bintree *);
-
-#endif /*_BINTREE_H_*/
-
diff --git a/ospf6d/ospf6_damp.c b/ospf6d/ospf6_damp.c
deleted file mode 100644
index 40cf798..0000000
--- a/ospf6d/ospf6_damp.c
+++ /dev/null
@@ -1,748 +0,0 @@
-/*
- * 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,
-                 (long)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,
-                     (long)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,
-                     (long)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,
-                    (long) 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 (ospf6_flap_damping_route,
-       ospf6_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, &ospf6_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 --git a/ospf6d/ospf6_damp.h b/ospf6d/ospf6_damp.h
deleted file mode 100644
index 19bdbc7..0000000
--- a/ospf6d/ospf6_damp.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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 --git a/ospf6d/ospf6_dbex.c b/ospf6d/ospf6_dbex.c
deleted file mode 100644
index b10d9ae..0000000
--- a/ospf6d/ospf6_dbex.c
+++ /dev/null
@@ -1,704 +0,0 @@
-/*
- * Copyright (C) 1999 Yasuhiro Ohara
- *
- * 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 "ospf6d.h"
-
-/* check validity and put lsa in reqestlist if needed. */
-/* returns -1 if SeqNumMismatch required. */
-int
-ospf6_dbex_check_dbdesc_lsa_header (struct ospf6_lsa_header *lsa_header,
-                                    struct ospf6_neighbor *from)
-{
-  struct ospf6_lsa *received = NULL;
-  struct ospf6_lsa *have = NULL;
-
-  received = ospf6_lsa_summary_create
-    ((struct ospf6_lsa_header__ *) lsa_header);
-
-  /* case when received is AS-External though neighbor belongs stub area */
-  if (lsa_header->type == htons (OSPF6_LSA_TYPE_AS_EXTERNAL) &&
-      ospf6_area_is_stub (from->ospf6_interface->area))
-    {
-      zlog_err ("DbDesc %s receive from %s", from->str, received->str);
-      zlog_err ("    E-bit mismatch: %s", received->str);
-      ospf6_lsa_delete (received);
-      return -1;
-    }
-
-  /* if already have newer database copy, check next LSA */
-  have = ospf6_lsdb_lookup (lsa_header->type, lsa_header->ls_id,
-                            lsa_header->advrtr,
-                            ospf6_lsa_get_scope (lsa_header->type,
-                                                 from->ospf6_interface));
-  if (! have)
-    {
-      /* if we don't have database copy, add request */
-      if (IS_OSPF6_DUMP_DBEX)
-        zlog_info ("Have no database copy, Request");
-      ospf6_neighbor_request_add (received, from);
-    }
-  else if (have)
-    {
-      /* if database copy is less recent, add request */
-      if (ospf6_lsa_check_recent (received, have) < 0)
-        {
-          if (IS_OSPF6_DUMP_DBEX)
-            zlog_info ("Database copy less recent, Request");
-          ospf6_neighbor_request_add (received, from);
-        }
-    }
-
-  return 0;
-}
-
-/* Direct acknowledgement */
-static void
-ospf6_dbex_acknowledge_direct (struct ospf6_lsa *lsa,
-                               struct ospf6_neighbor *o6n)
-{
-  struct iovec directack[MAXIOVLIST];
-  assert (lsa);
-
-  if (IS_OSPF6_DUMP_DBEX)
-    zlog_info ("DBEX: [%s:%s] direct ack %s ",
-               o6n->str, o6n->ospf6_interface->interface->name,
-               lsa->str);
-
-  /* clear pointers to fragments of packet for direct acknowledgement */
-  iov_clear (directack, MAXIOVLIST);
-
-  /* set pointer of LSA to send */
-  OSPF6_MESSAGE_ATTACH (directack, lsa->header,
-                        sizeof (struct ospf6_lsa_header));
-
-  /* age update and add InfTransDelay */
-  ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay);
-
-  /* send unicast packet to neighbor's ipaddress */
-  ospf6_message_send (OSPF6_MESSAGE_TYPE_LSACK, directack, &o6n->hisaddr,
-                      o6n->ospf6_interface->if_id);
-}
-
-/* Delayed  acknowledgement */
-void
-ospf6_dbex_acknowledge_delayed (struct ospf6_lsa *lsa,
-                                struct ospf6_interface *o6i)
-{
-  assert (o6i);
-
-  if (IS_OSPF6_DUMP_DBEX)
-    zlog_info ("DBEX: [%s] delayed ack %s", o6i->interface->name, lsa->str);
-
-  /* attach delayed acknowledge list */
-  ospf6_lsa_age_current (lsa);
-  ospf6_interface_delayed_ack_add (lsa, o6i);
-
-  /* if not yet, schedule delayed acknowledge RxmtInterval later.
-     timers should be *less than* RxmtInterval
-     or needless retrans will ensue */
-  if (o6i->thread_send_lsack_delayed == NULL)
-    o6i->thread_send_lsack_delayed
-      = thread_add_timer (master, ospf6_send_lsack_delayed,
-                          o6i, o6i->rxmt_interval - 1);
-
-  return;
-}
-
-/* RFC2328 section 13 (4):
-   if MaxAge LSA and if we have no instance, and no neighbor
-   is in states Exchange or Loading */
-/* returns 1 if match this case, else returns 0 */
-static int
-ospf6_dbex_is_maxage_to_be_dropped (struct ospf6_lsa *received,
-                                    struct ospf6_neighbor *from)
-{
-  int count;
-
-  if (! IS_LSA_MAXAGE (received))
-    return 0;
-
-  if (ospf6_lsdb_lookup (received->header->type, received->header->id,
-                         received->header->adv_router,
-                         ospf6_lsa_get_scope (received->header->type,
-                                              from->ospf6_interface)))
-    return 0;
-
-  if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (ntohs (received->header->type)))
-    {
-      count = 0;
-      (*from->ospf6_interface->foreach_nei)
-        (from->ospf6_interface, &count, NBS_EXCHANGE, ospf6_count_state);
-      (*from->ospf6_interface->foreach_nei)
-        (from->ospf6_interface, &count, NBS_LOADING, ospf6_count_state);
-      if (count)
-        return 0;
-    }
-  else if (OSPF6_LSA_IS_SCOPE_AREA (ntohs (received->header->type)))
-    {
-      count = 0;
-      (*from->ospf6_interface->area->foreach_nei)
-         (from->ospf6_interface->area, &count, NBS_EXCHANGE, ospf6_count_state);
-      (*from->ospf6_interface->area->foreach_nei)
-         (from->ospf6_interface->area, &count, NBS_LOADING, ospf6_count_state);
-      if (count)
-        return 0;
-    }
-  else if (OSPF6_LSA_IS_SCOPE_AS (ntohs (received->header->type)))
-    {
-      count = 0;
-      (*from->ospf6_interface->area->ospf6->foreach_nei)
-         (from->ospf6_interface->area->ospf6, &count, NBS_EXCHANGE,
-          ospf6_count_state);
-      (*from->ospf6_interface->area->ospf6->foreach_nei)
-         (from->ospf6_interface->area->ospf6, &count, NBS_LOADING,
-          ospf6_count_state);
-      if (count)
-        return 0;
-    }
-
-  return 1;
-}
-
-static void
-ospf6_dbex_remove_retrans (void *arg, int val, void *obj)
-{
-  struct ospf6_lsa *rem;
-  struct ospf6_neighbor *nei = (struct ospf6_neighbor *) obj;
-  struct ospf6_lsa *lsa = (struct ospf6_lsa *) arg;
-
-  rem = ospf6_lsdb_lookup_lsdb (lsa->header->type, lsa->header->id,
-                                lsa->header->adv_router, nei->retrans_list);
-  if (rem)
-    {
-      ospf6_neighbor_retrans_remove (rem, nei);
-      ospf6_maxage_remover ();
-    }
-}
-
-void
-ospf6_dbex_remove_from_all_retrans_list (struct ospf6_lsa *lsa)
-{
-  struct ospf6_interface *o6i;
-  struct ospf6_area *o6a;
-
-  if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (htons (lsa->header->type)))
-    {
-      o6i = lsa->scope;
-      (*o6i->foreach_nei) (o6i, lsa, 0, ospf6_dbex_remove_retrans);
-    }
-  else if (OSPF6_LSA_IS_SCOPE_AREA (htons (lsa->header->type)))
-    {
-      o6a = lsa->scope;
-      (*o6a->foreach_nei) (o6a, lsa, 0, ospf6_dbex_remove_retrans);
-    }
-  else if (OSPF6_LSA_IS_SCOPE_AS (htons (lsa->header->type)))
-    {
-      (*ospf6->foreach_nei) (ospf6, lsa, 0, ospf6_dbex_remove_retrans);
-    }
-}
-
-/* RFC2328 section 13 */
-void
-ospf6_dbex_receive_lsa (struct ospf6_lsa_header *lsa_header,
-                        struct ospf6_neighbor *from)
-{
-  struct ospf6_lsa *received, *have, *rem;
-  struct timeval now;
-  int ismore_recent, acktype;
-  unsigned short cksum;
-  struct ospf6_lsa_slot *slot;
-
-  received = have = (struct ospf6_lsa *)NULL;
-  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);
-
-  /* set LSA scope */
-  if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (htons (lsa_header->type)))
-    received->scope = from->ospf6_interface;
-  else if (OSPF6_LSA_IS_SCOPE_AREA (htons (lsa_header->type)))
-    received->scope = from->ospf6_interface->area;
-  else if (OSPF6_LSA_IS_SCOPE_AS (htons (lsa_header->type)))
-    received->scope = from->ospf6_interface->area->ospf6;
-
-  /* (1) LSA Checksum */
-  cksum = ntohs (lsa_header->checksum);
-  if (ntohs (ospf6_lsa_checksum (lsa_header)) != cksum)
-    {
-      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;
-    }
-
-  /* (3) Ebit Missmatch: AS-External-LSA */
-  if (lsa_header->type == htons (OSPF6_LSA_TYPE_AS_EXTERNAL) &&
-      ospf6_area_is_stub (from->ospf6_interface->area))
-    {
-      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;
-    }
-
-  /* (4) if MaxAge LSA and if we have no instance, and no neighbor
-         is in states Exchange or Loading */
-  if (ospf6_dbex_is_maxage_to_be_dropped (received, from))
-    {
-      /* log */
-      if (IS_OSPF6_DUMP_DBEX)
-        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 */
-      ospf6_dbex_acknowledge_direct (received, from);
-
-      /* b) Discard */
-      ospf6_lsa_delete (received);
-      return;
-    }
-
-  /* (5) */
-  /* lookup the same database copy in lsdb */
-  have = ospf6_lsdb_lookup (lsa_header->type, lsa_header->ls_id,
-                            lsa_header->advrtr,
-                            ospf6_lsa_get_scope (lsa_header->type,
-                                                 from->ospf6_interface));
-  if (have)
-    {
-      ismore_recent = ospf6_lsa_check_recent (received, have);
-      if (ntohl (received->header->seqnum) == ntohl (have->header->seqnum))
-        SET_FLAG (received->flag, OSPF6_LSA_FLAG_DUPLICATE);
-    }
-
-  /* if no database copy or received is more recent */
-  if (!have || ismore_recent < 0)
-    {
-      /* in case we have no database copy */
-      ismore_recent = -1;
-
-      /* (a) MinLSArrival check */
-      gettimeofday (&now, (struct timezone *)NULL);
-      if (have && SEC_TVDIFF (&now, &have->installed) < OSPF6_MIN_LS_ARRIVAL)
-        {
-          //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);
-
-#if 0
-      /* Because New LSDB do not permit two LSA having the same identifier
-         exist in a LSDB list, above ospf6_dbex_flood() will remove
-         the old instance automatically. thus bellow is not needed. */
-      /* (c) remove database copy from all neighbor's retranslist */
-      if (have)
-        ospf6_dbex_remove_from_all_retrans_list (have);
-#endif
-
-      /* (d), installing lsdb, which may cause routing
-              table calculation (replacing database copy) */
-      ospf6_lsdb_install (received);
-
-      /* (e) possibly acknowledge */
-      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: No Ack to %s", from->str);
-        }
-
-      /* (f) */
-      /* Self Originated LSA, section 13.4 */
-      if (received->lsa_hdr->lsh_advrtr == ospf6->router_id
-          && (! have || ismore_recent < 0))
-        {
-          /* we're going to make new lsa or to flush this LSA. */
-          if (IS_OSPF6_DUMP_DBEX)
-            zlog_info ("DBEX: Self-originated LSA %s from %s:%s",
-                       received->str, from->str,
-                       from->ospf6_interface->interface->name);
-          if (IS_OSPF6_DUMP_DBEX)
-            zlog_info ("DBEX: %s: Make new one/Flush", received->str);
-
-          SET_FLAG (received->flag, OSPF6_LSA_FLAG_REFRESH);
-          slot = ospf6_lsa_slot_get (received->header->type);
-          if (slot && slot->func_refresh)
-            {
-              (*slot->func_refresh) (received);
-              return;
-            }
-
-          zlog_warn ("Can't Refresh LSA: Unknown type: %#x, Flush",
-                     ntohs (received->header->type));
-          ospf6_lsa_premature_aging (received);
-          return;
-        }
-    }
-  else if (ospf6_lsdb_lookup_lsdb (received->header->type,
-                                   received->header->id,
-                                   received->header->adv_router,
-                                   from->request_list))
-    /* (6) if there is instance on sending neighbor's request list */
-    {
-      /* if no database copy, should go above state (5) */
-      assert (have);
-
-      zlog_warn ("DBEX: [%s:%s] received LSA %s is not newer,"
-                 " and is on his requestlist: Generate BadLSReq",
-                 from->str, from->ospf6_interface->interface->name,
-                 received->str);
-
-      /* BadLSReq */
-      thread_add_event (master, bad_lsreq, from, 0);
-
-      ospf6_lsa_delete (received);
-    }
-  else if (ismore_recent == 0) /* (7) if neither is more recent */
-    {
-      /* (a) if on retranslist, Treat this LSA as an Ack: Implied Ack */
-      rem = ospf6_lsdb_lookup_lsdb (received->header->type,
-                                    received->header->id,
-                                    received->header->adv_router,
-                                    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);
-        }
-
-      /* (b) possibly acknowledge */
-      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: No Ack to %s", from->str);
-        }
-      ospf6_lsa_delete (received);
-    }
-  else /* (8) previous database copy is more recent */
-    {
-      /* If Seqnumber Wrapping, simply discard
-         Otherwise, Send database copy of this LSA to this neighbor */
-      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);
-    }
-}
-
-/* RFC2328: Table 19: Sending link state acknowledgements. */
-int 
-ack_type (struct ospf6_lsa *newp, int ismore_recent,
-          struct ospf6_neighbor *from)
-{
-  struct ospf6_interface *ospf6_interface;
-  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;
-    }
-
-  if (CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_DUPLICATE) &&
-      CHECK_FLAG (newp->flag, OSPF6_LSA_FLAG_IMPLIEDACK))
-    {
-      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;
-}
-
-static void
-ospf6_dbex_flood_linklocal (struct ospf6_lsa *lsa, struct ospf6_interface *o6i,
-                            struct ospf6_neighbor *from)
-{
-  struct ospf6_neighbor *o6n = (struct ospf6_neighbor *) NULL;
-  int ismore_recent, addretrans = 0;
-  listnode n;
-  struct ospf6_lsa *req;
-
-  /* (1) for each neighbor */
-  for (n = listhead (o6i->neighbor_list); n; nextnode (n))
-    {
-      o6n = (struct ospf6_neighbor *) getdata (n);
-
-      /* (a) */
-      if (o6n->state < NBS_EXCHANGE)
-        continue;  /* examin next neighbor */
-
-      /* (b) */
-      if (o6n->state == NBS_EXCHANGE
-          || o6n->state == NBS_LOADING)
-        {
-          req = ospf6_lsdb_lookup_lsdb (lsa->header->type,
-                                        lsa->header->id,
-                                        lsa->header->adv_router,
-                                        o6n->request_list);
-          if (req)
-            {
-              ismore_recent = ospf6_lsa_check_recent (lsa, req);
-              if (ismore_recent > 0)
-                {
-                  continue; /* examin next neighbor */
-                }
-              else if (ismore_recent == 0)
-                {
-                  ospf6_neighbor_request_remove (req, o6n);
-                  continue; /* examin next neighbor */
-                }
-              else /* ismore_recent < 0 (the new LSA is more recent) */
-                {
-                  ospf6_neighbor_request_remove (req, o6n);
-                }
-            }
-        }
-
-      /* (c) */
-      if (from && from->router_id == o6n->router_id)
-        continue; /* examin next neighbor */
-
-      /* (d) add retranslist */
-      if (IS_OSPF6_DUMP_DBEX)
-        zlog_info ("DBEX: schedule flooding [%s:%s]: %s",
-                   o6n->str, o6n->ospf6_interface->interface->name,
-                   lsa->str);
-      ospf6_neighbor_retrans_add (lsa, o6n);
-      addretrans++;
-      if (o6n->send_update == (struct thread *) NULL)
-        o6n->send_update =
-          thread_add_timer (master, ospf6_send_lsupdate_rxmt, o6n,
-                            o6n->ospf6_interface->rxmt_interval);
-    }
-
-  /* (2) */
-  if (addretrans == 0)
-    return; /* examin next interface */
-
-  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);
-    }
-
-  /* (3) */
-  if (from && from->ospf6_interface == o6i)
-    {
-      /* if from DR or BDR, don't need to flood this interface */
-      if (from->router_id == from->ospf6_interface->dr ||
-          from->router_id == from->ospf6_interface->bdr)
-        return; /* examin next interface */
-    }
-
-  /* (4) if I'm BDR, DR will flood this interface */
-  if (from && from->ospf6_interface == o6i
-      && o6i->state == IFS_BDR)
-    return; /* examin next interface */
-
-  if (IS_OSPF6_DUMP_DBEX)
-    zlog_info ("Flood to interface %s", o6i->interface->name);
-
-  /* (5) send LinkState Update */
-  ospf6_send_lsupdate_flood (lsa, o6i);
-
-  return;
-}
-
-/* RFC2328 section 13.3 */
-static void
-ospf6_dbex_flood_area (struct ospf6_lsa *lsa, struct ospf6_area *area,
-                       struct ospf6_neighbor *from)
-{
-  listnode n;
-  struct ospf6_interface *ospf6_interface;
-
-  assert (lsa && lsa->lsa_hdr && area);
-
-  /* for each eligible ospf_ifs */
-  for (n = listhead (area->if_list); n; nextnode (n))
-    {
-      ospf6_interface = (struct ospf6_interface *) getdata (n);
-      ospf6_dbex_flood_linklocal (lsa, ospf6_interface, from);
-    }
-}
-
-static void
-ospf6_dbex_flood_as (struct ospf6_lsa *lsa, struct ospf6 *ospf6,
-                     struct ospf6_neighbor *from)
-{
-  listnode n;
-  struct ospf6_area *o6a;
-
-  assert (lsa && lsa->lsa_hdr && ospf6);
-
-  /* for each attached area */
-  for (n = listhead (ospf6->area_list); n; nextnode (n))
-    {
-      o6a = (struct ospf6_area *) getdata (n);
-      ospf6_dbex_flood_area (lsa, o6a, from);
-    }
-}
-
-/* flood ospf6_lsa within appropriate scope */
-void
-ospf6_dbex_flood (struct ospf6_lsa *lsa, struct ospf6_neighbor *from)
-{
-  struct ospf6_area *o6a;
-  struct ospf6_interface *o6i;
-  struct ospf6 *o6;
-  struct ospf6_lsa_header *lsa_header;
-
-  lsa_header = (struct ospf6_lsa_header *) lsa->lsa_hdr;
-
-  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)))
-    {
-      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)))
-    {
-      o6 = (struct ospf6 *) lsa->scope;
-      assert (o6);
-
-      if (IS_OSPF6_DUMP_DBEX)
-        zlog_info ("Flood AS");
-      ospf6_dbex_flood_as (lsa, o6, from);
-    }
-  else
-    {
-      zlog_warn ("Can't Flood %s: scope unknown", lsa->str);
-    }
-}
-
-
diff --git a/ospf6d/ospf6_dbex.h b/ospf6d/ospf6_dbex.h
deleted file mode 100644
index fbb7dc5..0000000
--- a/ospf6d/ospf6_dbex.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 1999 Yasuhiro Ohara
- *
- * 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.  
- */
-
-#ifndef OSPF6_DBEX_H
-#define OSPF6_DBEX_H
-
-/* for ack_type() */
-#define NO_ACK       0
-#define DELAYED_ACK  1
-#define DIRECT_ACK   2
-
-/* Function Prototypes */
-void
-ospf6_add_delayed_ack (struct ospf6_lsa *, struct ospf6_interface *);
-void
-ospf6_remove_delayed_ack (struct ospf6_lsa *, struct ospf6_interface *);
-void ospf6_lsa_delayed_ack_remove_all (struct ospf6_lsa *lsa);
-
-void ospf6_dbex_prepare_summary (struct ospf6_neighbor *);
-
-int
-ospf6_dbex_check_dbdesc_lsa_header (struct ospf6_lsa_header *lsa_header,
-                                    struct ospf6_neighbor *from);
-
-void
-ospf6_dbex_acknowledge_delayed (struct ospf6_lsa *lsa,
-                                struct ospf6_interface *o6i);
-
-void
-ospf6_dbex_receive_lsa (struct ospf6_lsa_header *,
-                        struct ospf6_neighbor *);
-
-int ack_type (struct ospf6_lsa *, int, struct ospf6_neighbor *);
-
-void ospf6_dbex_flood (struct ospf6_lsa *, struct ospf6_neighbor *);
-
-void
-ospf6_dbex_remove_from_all_retrans_list (struct ospf6_lsa *lsa);
-
-#endif /* OSPF6_DBEX_H */
-
diff --git a/ospf6d/ospf6_dump.c b/ospf6d/ospf6_dump.c
deleted file mode 100644
index 1e3c0c4..0000000
--- a/ospf6d/ospf6_dump.c
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * Logging function
- * Copyright (C) 1999-2002 Yasuhiro Ohara
- *
- * 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 other stuffs */
-#include "log.h"
-#include "command.h"
-#include "ospf6_dump.h"
-
-#define CMD_SHOW    0
-#define CMD_ENABLE  1
-#define CMD_DISABLE 2
-#define CMD_MAX     3
-
-struct ospf6_dump
-{
-  struct cmd_element cmd[CMD_MAX];
-  char *name;
-  int config;
-};
-
-#define DUMP_MAX 512
-struct ospf6_dump *ospf6_dump[DUMP_MAX];
-unsigned int dump_size = 0;
-
-static int
-ospf6_dump_index (struct cmd_element *cmd, int command)
-{
-  int i;
-
-  for (i = 0; i < DUMP_MAX; i++)
-    {
-      if (cmd != &ospf6_dump[i]->cmd[command])
-        continue;
-      break;
-    }
-
-  if (i == DUMP_MAX)
-    return -1;
-  return i;
-}
-
-int
-ospf6_dump_is_on (int index)
-{
-  if (ospf6_dump[index] == NULL)
-    return 0;
-
-  return ospf6_dump[index]->config;
-}
-
-int
-ospf6_dump_show (struct cmd_element *cmd,
-                 struct vty *vty, int argc, char **argv)
-{
-  int index;
-
-  index = ospf6_dump_index (cmd, CMD_SHOW);
-  assert (index != -1);
-
-  vty_out (vty, "  %-16s: %s%s", ospf6_dump[index]->name,
-           (ospf6_dump[index]->config ? "on" : "off"),
-           VTY_NEWLINE);
-  return CMD_SUCCESS;
-}
-
-int
-ospf6_dump_enable (struct cmd_element *cmd,
-                   struct vty *vty, int argc, char **argv)
-{
-  int index;
-
-  index = ospf6_dump_index (cmd, CMD_ENABLE);
-  assert (index != -1);
-
-  ospf6_dump[index]->config = 1;
-  return CMD_SUCCESS;
-}
-
-int
-ospf6_dump_disable (struct cmd_element *cmd,
-                    struct vty *vty, int argc, char **argv)
-{
-  int index;
-
-  index = ospf6_dump_index (cmd, CMD_DISABLE);
-  assert (index != -1);
-
-  ospf6_dump[index]->config = 0;
-  return CMD_SUCCESS;
-}
-
-int
-ospf6_dump_install (char *name, char *help)
-{
-  struct cmd_element *cmd;
-  char string[256];
-  char helpstring[256];
-
-  if (dump_size + 1 >= DUMP_MAX)
-    return -1;
-
-  ospf6_dump[dump_size] = malloc (sizeof (struct ospf6_dump));
-  if (ospf6_dump[dump_size] == NULL)
-    return -1;
-  memset (ospf6_dump[dump_size], 0, sizeof (struct ospf6_dump));
-
-  ospf6_dump[dump_size]->name = strdup (name);
-
-  cmd = &ospf6_dump[dump_size]->cmd[CMD_SHOW];
-  snprintf (string, sizeof (string), "show debugging ospf6 %s", name);
-  snprintf (helpstring, sizeof (helpstring), "%s%s%s%s",
-            SHOW_STR, DEBUG_STR, OSPF6_STR, help);
-  memset (cmd, 0, sizeof (struct cmd_element));
-  cmd->string = strdup (string);
-  cmd->func = ospf6_dump_show;
-  cmd->doc = strdup (helpstring);
-  install_element (VIEW_NODE, cmd);
-  install_element (ENABLE_NODE, cmd);
-
-  cmd = &ospf6_dump[dump_size]->cmd[CMD_ENABLE];
-  snprintf (string, sizeof (string), "debug ospf6 %s", name);
-  snprintf (helpstring, sizeof (helpstring), "%s%s%s",
-            DEBUG_STR, OSPF6_STR, help);
-  memset (cmd, 0, sizeof (struct cmd_element));
-  cmd->string = strdup (string);
-  cmd->func = ospf6_dump_enable;
-  cmd->doc = strdup (helpstring);
-  install_element (CONFIG_NODE, cmd);
-
-  cmd = &ospf6_dump[dump_size]->cmd[CMD_DISABLE];
-  snprintf (string, sizeof (string), "no debug ospf6 %s", name);
-  snprintf (helpstring, sizeof (helpstring), "%s%s%s%s",
-            NO_STR, DEBUG_STR, OSPF6_STR, help);
-  memset (cmd, 0, sizeof (struct cmd_element));
-  cmd->string = strdup (string);
-  cmd->func = ospf6_dump_disable;
-  cmd->doc = strdup (helpstring);
-  install_element (CONFIG_NODE, cmd);
-
-  return dump_size++;
-}
-
-DEFUN(show_debug_ospf6,
-      show_debug_ospf6_cmd,
-      "show debugging ospf6",
-      SHOW_STR
-      DEBUG_STR
-      OSPF6_STR)
-{
-  int i;
-
-  vty_out (vty, "OSPF6 debugging status:%s", VTY_NEWLINE);
-
-  for (i = 0; i < DUMP_MAX; i++)
-    {
-      if (ospf6_dump[i] == NULL)
-        continue;
-      ospf6_dump_show (&ospf6_dump[i]->cmd[CMD_SHOW], vty, 0, NULL);
-    }
-
-  return CMD_SUCCESS;
-}
-
-DEFUN (debug_ospf6_all,
-       debug_ospf6_all_cmd,
-       "debug ospf6 all",
-       DEBUG_STR
-       OSPF6_STR
-       "Turn on ALL OSPFv3 debugging\n")
-{
-  int i;
-
-  for (i = 0; i < DUMP_MAX; i++)
-    {
-      if (ospf6_dump[i] == NULL)
-        continue;
-      ospf6_dump_enable (&ospf6_dump[i]->cmd[CMD_ENABLE], vty, 0, NULL);
-    }
-
-  return CMD_SUCCESS;
-}
-
-DEFUN (no_debug_ospf6_all,
-       no_debug_ospf6_all_cmd,
-       "no debug ospf6 all",
-       NO_STR
-       DEBUG_STR
-       OSPF6_STR
-       "Turn off ALL OSPFv3 debugging\n")
-{
-  int i;
-
-  for (i = 0; i < DUMP_MAX; i++)
-    {
-      if (ospf6_dump[i] == NULL)
-        continue;
-      ospf6_dump_disable (&ospf6_dump[i]->cmd[CMD_DISABLE], vty, 0, NULL);
-    }
-
-  return CMD_SUCCESS;
-}
-
-struct cmd_node debug_node =
-{
-  DEBUG_NODE,
-  "",
-  vtysh: 1
-};
-
-int
-ospf6_dump_config_write (struct vty *vty)
-{
-  int i;
-
-  for (i = 0; i < dump_size; i++)
-    {
-      if (ospf6_dump[i] == NULL)
-        continue;
-
-      if (ospf6_dump[i]->config == 0)
-        continue;
-
-      vty_out (vty, "debug ospf6 %s%s", ospf6_dump[i]->name, VTY_NEWLINE);
-    }
-
-  vty_out (vty, "!%s", VTY_NEWLINE);
-  return 0;
-}
-
-char dump_index[OSPF6_DUMP_MAX];
-
-void
-ospf6_dump_init ()
-{
-  memset (ospf6_dump, 0, sizeof (ospf6_dump));
-
-  install_node (&debug_node, ospf6_dump_config_write);
-
-  install_element (VIEW_NODE,   &show_debug_ospf6_cmd);
-  install_element (ENABLE_NODE, &show_debug_ospf6_cmd);
-
-  install_element (CONFIG_NODE, &debug_ospf6_all_cmd);
-  install_element (CONFIG_NODE, &no_debug_ospf6_all_cmd);
-
-  /* bellow is for backward compatibility
-     should be moved to each modules */
-
-#define MESSAGE_STR "OSPFv3 Messages\n"
-
-  dump_index[OSPF6_DUMP_HELLO] =
-    ospf6_dump_install ("message hello",
-                        MESSAGE_STR "Hello\n");
-  dump_index[OSPF6_DUMP_DBDESC] =
-    ospf6_dump_install ("message dbdesc",
-                        MESSAGE_STR "Database Description\n");
-  dump_index[OSPF6_DUMP_LSREQ] =
-    ospf6_dump_install ("message lsreq",
-                        MESSAGE_STR "Link State Request\n");
-  dump_index[OSPF6_DUMP_LSUPDATE] =
-    ospf6_dump_install ("message lsupdate",
-                        MESSAGE_STR "Link State Update\n");
-  dump_index[OSPF6_DUMP_LSACK] =
-    ospf6_dump_install ("message lsack",
-                        MESSAGE_STR "Link State Acknowledge\n");
-  dump_index[OSPF6_DUMP_NEIGHBOR] =
-    ospf6_dump_install ("neighbor", "Neighbors\n");
-  dump_index[OSPF6_DUMP_INTERFACE] =
-    ospf6_dump_install ("interface", "Interfaces\n");
-  dump_index[OSPF6_DUMP_LSA] =
-    ospf6_dump_install ("lsa", "Link State Advertisement\n");
-  dump_index[OSPF6_DUMP_ZEBRA] =
-    ospf6_dump_install ("zebra", "Communication with zebra\n");
-  dump_index[OSPF6_DUMP_CONFIG] =
-    ospf6_dump_install ("config", "Configuration Changes\n");
-  dump_index[OSPF6_DUMP_DBEX] =
-    ospf6_dump_install ("dbex", "Database Exchange/Flooding\n");
-  dump_index[OSPF6_DUMP_SPF] =
-    ospf6_dump_install ("spf", "SPF Calculation\n");
-  dump_index[OSPF6_DUMP_ROUTE] =
-    ospf6_dump_install ("route", "Route Calculation\n");
-  dump_index[OSPF6_DUMP_LSDB] =
-    ospf6_dump_install ("lsdb", "Link State Database\n");
-  dump_index[OSPF6_DUMP_REDISTRIBUTE] =
-    ospf6_dump_install ("redistribute",
-                        "Route Exchange with other protocols\n");
-  dump_index[OSPF6_DUMP_HOOK] =
-    ospf6_dump_install ("hook", "Hooks\n");
-  dump_index[OSPF6_DUMP_ASBR] =
-    ospf6_dump_install ("asbr", "AS Boundary Router function\n");
-  dump_index[OSPF6_DUMP_PREFIX] =
-    ospf6_dump_install ("prefix", "Prefix\n");
-}
-
-
diff --git a/ospf6d/ospf6_dump.h b/ospf6d/ospf6_dump.h
deleted file mode 100644
index 18a6e46..0000000
--- a/ospf6d/ospf6_dump.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Logging function
- * Copyright (C) 1999-2002 Yasuhiro Ohara
- *
- * 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.  
- */
-
-#ifndef OSPF6_DUMP_H
-#define OSPF6_DUMP_H
-
-enum ospf6_dump_type
-{
-  OSPF6_DUMP_HELLO,
-  OSPF6_DUMP_DBDESC,
-  OSPF6_DUMP_LSREQ,
-  OSPF6_DUMP_LSUPDATE,
-  OSPF6_DUMP_LSACK,
-  OSPF6_DUMP_NEIGHBOR,
-  OSPF6_DUMP_INTERFACE,
-  OSPF6_DUMP_AREA,
-  OSPF6_DUMP_LSA,
-  OSPF6_DUMP_ZEBRA,
-  OSPF6_DUMP_CONFIG,
-  OSPF6_DUMP_DBEX,
-  OSPF6_DUMP_SPF,
-  OSPF6_DUMP_ROUTE,
-  OSPF6_DUMP_LSDB,
-  OSPF6_DUMP_REDISTRIBUTE,
-  OSPF6_DUMP_HOOK,
-  OSPF6_DUMP_ASBR,
-  OSPF6_DUMP_PREFIX,
-  OSPF6_DUMP_ABR,
-  OSPF6_DUMP_MAX
-};
-
-#define IS_OSPF6_DUMP_HELLO \
-  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_HELLO]))
-#define IS_OSPF6_DUMP_DBDESC \
-  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_DBDESC]))
-#define IS_OSPF6_DUMP_LSREQ \
-  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_LSREQ]))
-#define IS_OSPF6_DUMP_LSUPDATE \
-  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_LSUPDATE]))
-#define IS_OSPF6_DUMP_LSACK \
-  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_LSACK]))
-#define IS_OSPF6_DUMP_NEIGHBOR \
-  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_NEIGHBOR]))
-#define IS_OSPF6_DUMP_INTERFACE \
-  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_INTERFACE]))
-#define IS_OSPF6_DUMP_LSA \
-  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_LSA]))
-#define IS_OSPF6_DUMP_ZEBRA \
-  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_ZEBRA]))
-#define IS_OSPF6_DUMP_CONFIG \
-  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_CONFIG]))
-#define IS_OSPF6_DUMP_DBEX \
-  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_DBEX]))
-#define IS_OSPF6_DUMP_SPF \
-  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_SPF]))
-#define IS_OSPF6_DUMP_ROUTE \
-  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_ROUTE]))
-#define IS_OSPF6_DUMP_LSDB \
-  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_LSDB]))
-#define IS_OSPF6_DUMP_REDISTRIBUTE \
-  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_REDISTRIBUTE]))
-#define IS_OSPF6_DUMP_HOOK \
-  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_HOOK]))
-#define IS_OSPF6_DUMP_ASBR \
-  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_ASBR]))
-#define IS_OSPF6_DUMP_PREFIX \
-  (ospf6_dump_is_on (dump_index[OSPF6_DUMP_PREFIX]))
-
-extern char dump_index[OSPF6_DUMP_MAX];
-
-void ospf6_dump_init ();
-int ospf6_dump_is_on (int index);
-int ospf6_dump_install (char *name, char *help);
-
-#endif /* OSPF6_DUMP_H */
-
diff --git a/ospf6d/ospf6_hook.c b/ospf6d/ospf6_hook.c
deleted file mode 100644
index fc9e185..0000000
--- a/ospf6d/ospf6_hook.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2001 Yasuhiro Ohara
- *
- * 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 "log.h"
-#include "memory.h"
-
-#include "ospf6_hook.h"
-
-struct ospf6_hook_master neighbor_hook;
-struct ospf6_hook_master interface_hook;
-struct ospf6_hook_master area_hook;
-struct ospf6_hook_master top_hook;
-struct ospf6_hook_master database_hook;
-struct ospf6_hook_master intra_topology_hook;
-struct ospf6_hook_master inter_topology_hook;
-struct ospf6_hook_master route_hook;
-struct ospf6_hook_master redistribute_hook;
-
-static struct ospf6_hook *
-ospf6_hook_create ()
-{
-  struct ospf6_hook *new;
-  new = XMALLOC (MTYPE_OSPF6_OTHER, sizeof (struct ospf6_hook));
-  if (new == NULL)
-    return NULL;
-  memset (new, 0, sizeof (struct ospf6_hook));
-  return new;
-}
-
-static void
-ospf6_hook_delete (struct ospf6_hook *hook)
-{
-  XFREE (MTYPE_OSPF6_OTHER, hook);
-}
-
-static int
-ospf6_hook_issame (struct ospf6_hook *hook1, struct ospf6_hook *hook2)
-{
-  if (hook1->name && hook2->name &&
-      strcmp (hook1->name, hook2->name) != 0)
-    return 0;
-  if (hook1->hook_add != hook2->hook_add)
-    return 0;
-  if (hook1->hook_change != hook2->hook_change)
-    return 0;
-  if (hook1->hook_remove != hook2->hook_remove)
-    return 0;
-  return 1;
-}
-
-void
-ospf6_hook_register (struct ospf6_hook *hook,
-                     struct ospf6_hook_master *master)
-{
-  struct ospf6_hook *new;
-
-  new = ospf6_hook_create ();
-
-  if (hook->name)
-    new->name = strdup (hook->name);
-  new->hook_add = hook->hook_add;
-  new->hook_change = hook->hook_change;
-  new->hook_remove = hook->hook_remove;
-
-  new->prev = master->tail;
-  if (master->tail)
-    master->tail->next = new;
-
-  master->tail = new;
-  if (! master->head)
-    master->head = new;
-
-  master->count++;
-
-  if (IS_OSPF6_DUMP_HOOK)
-    {
-      zlog_info ("HOOK: Register hook%s%s%s%s",
-                 (hook->name ? " " : ""),
-                 (hook->name ? hook->name : ""),
-                 (master->name ? " to " : ""),
-                 (master->name ? master->name : ""));
-    }
-}
-
-void
-ospf6_hook_unregister (struct ospf6_hook *req,
-                       struct ospf6_hook_master *master)
-{
-  struct ospf6_hook *hook;
-
-  for (hook = master->head; hook; hook = hook->next)
-    {
-      if (ospf6_hook_issame (hook, req))
-        break;
-    }
-  if (! hook)
-    return;
-
-  if (hook->prev)
-    hook->prev->next = hook->next;
-  if (hook->next)
-    hook->next->prev = hook->prev;
-  if (master->head == hook)
-    master->head = hook->next;
-  if (master->tail == hook)
-    master->tail = hook->prev;
-
-  master->count--;
-
-  if (IS_OSPF6_DUMP_HOOK)
-    {
-      zlog_info ("HOOK: Unregister hook%s%s%s%s",
-                 (hook->name ? " " : ""),
-                 (hook->name ? hook->name : ""),
-                 (master->name ? " to " : ""),
-                 (master->name ? master->name : ""));
-    }
-
-  if (hook->name)
-    free (hook->name);
-  ospf6_hook_delete (hook);
-}
-
-void
-ospf6_hook_unregister_all (struct ospf6_hook_master *master)
-{
-  struct ospf6_hook *hook, *next;
-
-  for (hook = master->head; hook; hook = next)
-    {
-      next = hook->next;
-      ospf6_hook_delete (hook);
-    }
-
-  master->head = NULL;
-  master->tail = NULL;
-  master->count = 0;
-}
-
-
-void
-ospf6_hook_init ()
-{
-  neighbor_hook.name       =      "Neighbor Hooklist";
-  interface_hook.name      =     "Interface Hooklist";
-  area_hook.name           =          "Area Hooklist";
-  top_hook.name            =           "Top Hooklist";
-  database_hook.name       =      "Database Hooklist";
-  intra_topology_hook.name = "IntraTopology Hooklist";
-  inter_topology_hook.name = "InterTopology Hooklist";
-  route_hook.name          =         "Route Hooklist";
-}
-
-
diff --git a/ospf6d/ospf6_hook.h b/ospf6d/ospf6_hook.h
deleted file mode 100644
index fa882a5..0000000
--- a/ospf6d/ospf6_hook.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2001 Yasuhiro Ohara
- *
- * 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.  
- */
-
-#ifndef OSPF6_HOOK_H
-#define OSPF6_HOOK_H
-
-#include "ospf6_dump.h"
-
-struct ospf6_hook
-{
-  struct ospf6_hook *prev;
-  struct ospf6_hook *next;
-
-  char *name;
-  int (*hook_add) (void *);
-  int (*hook_change) (void *);
-  int (*hook_remove) (void *);
-};
-
-struct ospf6_hook_master
-{
-  char *name;
-  struct ospf6_hook *head;
-  struct ospf6_hook *tail;
-  int count;
-};
-
-#define CALL_HOOKS(master,hookname,hookstr,data) \
-  {\
-    struct ospf6_hook *hook;\
-    for (hook = (master)->head; hook; hook = hook->next)\
-      {\
-        if (hook->hookname)\
-          {\
-            if (IS_OSPF6_DUMP_HOOK)\
-              zlog_info ("HOOK: Call %s hook: %s", (hookstr), hook->name);\
-            (*(hook->hookname)) (data);\
-          }\
-      }\
-  }
-#define CALL_ADD_HOOK(master,data) \
-  { CALL_HOOKS ((master), hook_add, "ADD", (data)) }
-#define CALL_CHANGE_HOOK(master,data) \
-  { CALL_HOOKS ((master), hook_change, "CHANGE", (data)) }
-#define CALL_REMOVE_HOOK(master,data) \
-  { CALL_HOOKS ((master), hook_remove, "REMOVE", (data)) }
-
-#define IS_HOOK_SET(hook) \
-  ((hook)->hook_add || (hook)->hook_change || (hook)->hook_remove)
-
-extern struct ospf6_hook_master neighbor_hook;
-extern struct ospf6_hook_master interface_hook;
-extern struct ospf6_hook_master area_hook;
-extern struct ospf6_hook_master top_hook;
-extern struct ospf6_hook_master database_hook;
-extern struct ospf6_hook_master intra_topology_hook;
-extern struct ospf6_hook_master inter_topology_hook;
-extern struct ospf6_hook_master route_hook;
-extern struct ospf6_hook_master redistribute_hook;
-
-void ospf6_hook_register (struct ospf6_hook *,
-                          struct ospf6_hook_master *);
-void ospf6_hook_unregister (struct ospf6_hook *,
-                            struct ospf6_hook_master *);
-void ospf6_hook_unregister_all (struct ospf6_hook_master *);
-void ospf6_hook_init ();
-
-#endif /*OSPF6_HOOK_H*/
-
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index 4d632b2..8f01e7d 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -19,161 +19,215 @@
  * Boston, MA 02111-1307, USA.  
  */
 
-#include "ospf6d.h"
+#include <zebra.h>
 
+#include "memory.h"
 #include "if.h"
 #include "log.h"
 #include "command.h"
+#include "thread.h"
+#include "prefix.h"
+#include "plist.h"
 
+#include "ospf6d.h"
+#include "ospf6_lsa.h"
 #include "ospf6_lsdb.h"
-
+#include "ospf6_network.h"
+#include "ospf6_message.h"
+#include "ospf6_route.h"
 #include "ospf6_top.h"
 #include "ospf6_area.h"
 #include "ospf6_interface.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_intra.h"
+#include "ospf6_spf.h"
 
-char *ospf6_interface_state_string[] =
+unsigned char conf_debug_ospf6_interface = 0;
+
+char *ospf6_interface_state_str[] =
 {
-  "None", "Down", "Loopback", "Waiting", "PointToPoint",
-  "DROther", "BDR", "DR", NULL
+  "None",
+  "Down",
+  "Loopback",
+  "Waiting",
+  "PointToPoint",
+  "DROther",
+  "BDR",
+  "DR",
+  NULL
 };
 
-static void
-ospf6_interface_foreach_neighbor (struct ospf6_interface *o6i,
-                                  void *arg, int val,
-                                  void (*func) (void *, int, void *))
+struct ospf6_interface *
+ospf6_interface_lookup_by_ifindex (int ifindex)
 {
-  listnode node;
-  struct ospf6_neighbor *nei;
+  struct ospf6_interface *oi;
+  struct interface *ifp;
 
-  for (node = listhead (o6i->neighbor_list); node; nextnode (node))
-    {
-      nei = (struct ospf6_neighbor *) getdata (node);
-      (*func) (arg, val, nei);
-    }
+  ifp = if_lookup_by_index (ifindex);
+  if (ifp == NULL)
+    return (struct ospf6_interface *) NULL;
+
+  oi = (struct ospf6_interface *) ifp->info;
+  return oi;
 }
 
-static int
-ospf6_interface_maxage_remover (struct thread *t)
+struct ospf6_interface *
+ospf6_interface_lookup_by_name (char *ifname)
 {
-  int count;
-  struct ospf6_interface *o6i = (struct ospf6_interface *) THREAD_ARG (t);
+  struct ospf6_interface *oi;
+  struct interface *ifp;
 
-  o6i->maxage_remover = (struct thread *) NULL;
+  ifp = if_lookup_by_name (ifname);
+  if (ifp == NULL)
+    return (struct ospf6_interface *) NULL;
 
-  count = 0;
-  o6i->foreach_nei (o6i, &count, NBS_EXCHANGE, ospf6_count_state);
-  o6i->foreach_nei (o6i, &count, NBS_LOADING, ospf6_count_state);
-  if (count != 0)
-    return 0;
-
-  ospf6_lsdb_remove_maxage (o6i->lsdb);
-  return 0;
+  oi = (struct ospf6_interface *) ifp->info;
+  return oi;
 }
 
+/* schedule routing table recalculation */
 void
-ospf6_interface_schedule_maxage_remover (void *arg, int val, void *obj)
+ospf6_interface_lsdb_hook (struct ospf6_lsa *lsa)
 {
-  struct ospf6_interface *o6i = (struct ospf6_interface *) obj;
+  struct ospf6_interface *oi;
 
-  if (o6i->maxage_remover != NULL)
-    return;
+  oi = (struct ospf6_interface *) lsa->scope;
+  switch (ntohs (lsa->header->type))
+    {
+      case OSPF6_LSTYPE_LINK:
+        if (oi->state == OSPF6_INTERFACE_DR)
+          OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi);
+        ospf6_spf_schedule (oi->area);
+        break;
 
-  o6i->maxage_remover =
-    thread_add_event (master, ospf6_interface_maxage_remover, o6i, 0);
+      default:
+        if (IS_OSPF6_DEBUG_LSA (RECV))
+          zlog_info ("Unknown LSA in Interface %s's lsdb",
+                     oi->interface->name);
+        break;
+    }
 }
 
 /* Create new ospf6 interface structure */
 struct ospf6_interface *
 ospf6_interface_create (struct interface *ifp)
 {
-  struct ospf6_interface *o6i;
+  struct ospf6_interface *oi;
 
-  o6i = (struct ospf6_interface *)
+  oi = (struct ospf6_interface *)
     XMALLOC (MTYPE_OSPF6_IF, sizeof (struct ospf6_interface));
 
-  if (o6i)
-    memset (o6i, 0, sizeof (struct ospf6_interface));
+  if (oi)
+    memset (oi, 0, sizeof (struct ospf6_interface));
   else
     {
       zlog_err ("Can't malloc ospf6_interface for ifindex %d", ifp->ifindex);
       return (struct ospf6_interface *) NULL;
     }
 
-  o6i->instance_id = 0;
-  o6i->if_id = ifp->ifindex;
-  o6i->lladdr = (struct in6_addr *) NULL;
-  o6i->area = (struct ospf6_area *) NULL;
-  o6i->state = IFS_DOWN;
-  o6i->flag = 0;
-  o6i->neighbor_list = list_new ();
+  oi->area = (struct ospf6_area *) NULL;
+  oi->neighbor_list = list_new ();
+  oi->neighbor_list->cmp = ospf6_neighbor_cmp;
+  oi->linklocal_addr = (struct in6_addr *) NULL;
+  oi->instance_id = 0;
+  oi->transdelay = 1;
+  oi->priority = 1;
 
-  o6i->ack_list = ospf6_lsdb_create ();
-  o6i->lsdb = ospf6_lsdb_create ();
+  oi->hello_interval = 10;
+  oi->dead_interval = 40;
+  oi->rxmt_interval = 5;
+  oi->cost = 1;
+  oi->ifmtu = ifp->mtu;
+  oi->state = OSPF6_INTERFACE_DOWN;
+  oi->flag = 0;
 
-  o6i->transdelay = 1;
-  o6i->priority = 1;
-  o6i->hello_interval = 10;
-  o6i->dead_interval = 40;
-  o6i->rxmt_interval = 5;
-  o6i->cost = 1;
-  o6i->ifmtu = 1280;
+  oi->lsupdate_list = ospf6_lsdb_create ();
+  oi->lsack_list = ospf6_lsdb_create ();
+  oi->lsdb = ospf6_lsdb_create ();
+  oi->lsdb->hook_add = ospf6_interface_lsdb_hook;
+  oi->lsdb->hook_remove = ospf6_interface_lsdb_hook;
 
-  o6i->foreach_nei = ospf6_interface_foreach_neighbor;
+  oi->route_connected = ospf6_route_table_create ();
 
   /* link both */
-  o6i->interface = ifp;
-  ifp->info = o6i;
+  oi->interface = ifp;
+  ifp->info = oi;
 
-  CALL_ADD_HOOK (&interface_hook, o6i);
-
-  /* Get the interface's link-local if any */
-  ospf6_interface_address_update(ifp);
-
-  return o6i;
+  return oi;
 }
 
 void
-ospf6_interface_delete (struct ospf6_interface *o6i)
+ospf6_interface_delete (struct ospf6_interface *oi)
 {
   listnode n;
-  struct ospf6_neighbor *o6n;
+  struct ospf6_neighbor *on;
 
-  CALL_REMOVE_HOOK (&interface_hook, o6i);
-
-  for (n = listhead (o6i->neighbor_list); n; nextnode (n))
+  for (n = listhead (oi->neighbor_list); n; nextnode (n))
     {
-      o6n = (struct ospf6_neighbor *) getdata (n);
-      ospf6_neighbor_delete (o6n);
+      on = (struct ospf6_neighbor *) getdata (n);
+      ospf6_neighbor_delete (on);
     }
-  list_delete (o6i->neighbor_list);
+  list_delete (oi->neighbor_list);
 
-  if (o6i->thread_send_hello)
-    {
-      thread_cancel (o6i->thread_send_hello);
-      o6i->thread_send_hello = NULL;
-    }
-  if (o6i->thread_send_lsack_delayed)
-    {
-      thread_cancel (o6i->thread_send_lsack_delayed);
-      o6i->thread_send_lsack_delayed = NULL;
-    }
+  THREAD_OFF (oi->thread_send_hello);
+  THREAD_OFF (oi->thread_send_lsupdate);
+  THREAD_OFF (oi->thread_send_lsack);
 
-  ospf6_lsdb_delete (o6i->ack_list);
-  ospf6_lsdb_remove_all (o6i->lsdb);
-  ospf6_lsdb_delete (o6i->lsdb);
+  ospf6_lsdb_remove_all (oi->lsdb);
+  ospf6_lsdb_remove_all (oi->lsupdate_list);
+  ospf6_lsdb_remove_all (oi->lsack_list);
+
+  ospf6_lsdb_delete (oi->lsdb);
+  ospf6_lsdb_delete (oi->lsupdate_list);
+  ospf6_lsdb_delete (oi->lsack_list);
+
+  ospf6_route_table_delete (oi->route_connected);
 
   /* cut link */
-  o6i->interface->info = NULL;
+  oi->interface->info = NULL;
 
   /* plist_name */
-  if (o6i->plist_name)
-    XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name);
+  if (oi->plist_name)
+    XFREE (MTYPE_PREFIX_LIST_STR, oi->plist_name);
 
-  XFREE (MTYPE_OSPF6_IF, o6i);
+  XFREE (MTYPE_OSPF6_IF, oi);
+}
+
+void
+ospf6_interface_enable (struct ospf6_interface *oi)
+{
+  UNSET_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE);
+
+  oi->thread_send_hello =
+    thread_add_event (master, ospf6_hello_send, oi, 0);
+}
+
+void
+ospf6_interface_disable (struct ospf6_interface *oi)
+{
+  listnode i;
+  struct ospf6_neighbor *on;
+
+  SET_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE);
+
+  for (i = listhead (oi->neighbor_list); i; nextnode (i))
+    {
+      on = (struct ospf6_neighbor *) getdata (i);
+      ospf6_neighbor_delete (on);
+    }
+  list_delete_all_node (oi->neighbor_list);
+
+  ospf6_lsdb_remove_all (oi->lsdb);
+  ospf6_lsdb_remove_all (oi->lsupdate_list);
+  ospf6_lsdb_remove_all (oi->lsack_list);
+
+  THREAD_OFF (oi->thread_send_hello);
+  THREAD_OFF (oi->thread_send_lsupdate);
+  THREAD_OFF (oi->thread_send_lsack);
 }
 
 static struct in6_addr *
-ospf6_interface_update_linklocal_address (struct interface *ifp)
+ospf6_interface_get_linklocal_address (struct interface *ifp)
 {
   listnode n;
   struct connected *c;
@@ -198,222 +252,532 @@
 void
 ospf6_interface_if_add (struct interface *ifp)
 {
-  struct ospf6_interface *o6i;
+  struct ospf6_interface *oi;
 
-  o6i = (struct ospf6_interface *) ifp->info;
-  if (!o6i)
+  oi = (struct ospf6_interface *) ifp->info;
+  if (oi == NULL)
     return;
 
-  o6i->if_id = ifp->ifindex;
-
-  ospf6_interface_address_update (ifp);
+  oi->ifmtu = ifp->mtu;
 
   /* interface start */
-  if (o6i->area)
-    thread_add_event (master, interface_up, o6i, 0);
+  if (oi->area)
+    thread_add_event (master, interface_up, oi, 0);
 }
 
 void
 ospf6_interface_if_del (struct interface *ifp)
 {
-  struct ospf6_interface *o6i;
+  struct ospf6_interface *oi;
 
-  o6i = (struct ospf6_interface *) ifp->info;
-  if (!o6i)
+  oi = (struct ospf6_interface *) ifp->info;
+  if (oi == NULL)
     return;
 
   /* interface stop */
-  if (o6i->area)
-    thread_execute (master, interface_down, o6i, 0);
+  if (oi->area)
+    thread_execute (master, interface_down, oi, 0);
 
-  listnode_delete (o6i->area->if_list, o6i);
-  o6i->area = (struct ospf6_area *) NULL;
+  listnode_delete (oi->area->if_list, oi);
+  oi->area = (struct ospf6_area *) NULL;
 
   /* cut link */
-  o6i->interface = NULL;
+  oi->interface = NULL;
   ifp->info = NULL;
 
-  ospf6_interface_delete (o6i);
+  ospf6_interface_delete (oi);
 }
 
 void
 ospf6_interface_state_update (struct interface *ifp)
 {
-  struct ospf6_interface *o6i;
+  struct ospf6_interface *oi;
 
-  o6i = (struct ospf6_interface *) ifp->info;
-  if (! o6i)
+  oi = (struct ospf6_interface *) ifp->info;
+  if (oi == NULL)
     return;
-  if (! o6i->area)
+  if (oi->area == NULL)
     return;
 
   if (if_is_up (ifp))
-    thread_add_event (master, interface_up, o6i, 0);
+    thread_add_event (master, interface_up, oi, 0);
   else
-    thread_add_event (master, interface_down, o6i, 0);
+    thread_add_event (master, interface_down, oi, 0);
 
   return;
 }
 
 void
-ospf6_interface_address_update (struct interface *ifp)
+ospf6_interface_connected_route_update (struct interface *ifp)
 {
-  struct ospf6_interface *o6i;
+  struct ospf6_interface *oi;
+  struct ospf6_route *route;
+  struct connected *c;
+  listnode i;
 
-  o6i = (struct ospf6_interface *) ifp->info;
-  if (! o6i)
+  oi = (struct ospf6_interface *) ifp->info;
+  if (oi == NULL)
     return;
 
   /* reset linklocal pointer */
-  o6i->lladdr = ospf6_interface_update_linklocal_address (ifp);
+  oi->linklocal_addr = ospf6_interface_get_linklocal_address (ifp);
 
-  /* if area is null, can't make link-lsa */
-  if (! o6i->area)
+  /* if area is null, do not make connected-route list */
+  if (oi->area == NULL)
     return;
 
+  /* update "route to advertise" interface route table */
+  ospf6_route_remove_all (oi->route_connected);
+  for (i = listhead (oi->interface->connected); i; nextnode (i))
+    {
+      c = (struct connected *) getdata (i);
+
+      if (c->address->family != AF_INET6)
+        continue;
+
+      CONTINUE_IF_ADDRESS_LINKLOCAL (c->address);
+      CONTINUE_IF_ADDRESS_UNSPECIFIED (c->address);
+      CONTINUE_IF_ADDRESS_LOOPBACK (c->address);
+      CONTINUE_IF_ADDRESS_V4COMPAT (c->address);
+      CONTINUE_IF_ADDRESS_V4MAPPED (c->address);
+
+      /* apply filter */
+      if (oi->plist_name)
+        {
+          struct prefix_list *plist;
+          enum prefix_list_type ret;
+          char buf[128];
+
+          prefix2str (c->address, buf, sizeof (buf));
+          plist = prefix_list_lookup (AFI_IP6, oi->plist_name);
+          ret = prefix_list_apply (plist, (void *) c->address);
+          if (ret == PREFIX_DENY)
+            {
+              zlog_info ("%s on %s filtered by prefix-list %s ",
+                         buf, oi->interface->name, oi->plist_name);
+              continue;
+            }
+        }
+
+      route = ospf6_route_create ();
+      memcpy (&route->prefix, c->address, sizeof (struct prefix));
+      apply_mask (&route->prefix);
+      route->type = OSPF6_DEST_TYPE_NETWORK;
+      route->path.area_id = oi->area->area_id;
+      route->path.type = OSPF6_PATH_TYPE_INTRA;
+      route->path.cost = oi->cost;
+      route->nexthop[0].ifindex = oi->interface->ifindex;
+      inet_pton (AF_INET6, "::1", &route->nexthop[0].address);
+      ospf6_route_add (route, oi->route_connected);
+    }
+
   /* create new Link-LSA */
-  CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
-
-  CALL_CHANGE_HOOK (&interface_hook, o6i);
+  OSPF6_LINK_LSA_SCHEDULE (oi);
+  OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi);
+  OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area);
 }
 
-struct ospf6_interface *
-ospf6_interface_lookup_by_index (int ifindex)
+static void
+ospf6_interface_state_change (u_char next_state, struct ospf6_interface *oi)
 {
-  struct ospf6_interface *o6i;
-  struct interface *ifp;
+  u_char prev_state;
 
-  ifp = if_lookup_by_index (ifindex);
+  prev_state = oi->state;
+  oi->state = next_state;
 
-  if (! ifp)
-    return (struct ospf6_interface *) NULL;
+  if (prev_state == next_state)
+    return;
 
-  o6i = (struct ospf6_interface *) ifp->info;
-  return o6i;
-}
-
-struct ospf6_interface *
-ospf6_interface_lookup_by_name (char *ifname)
-{
-  struct ospf6_interface *o6i;
-  struct interface *ifp;
-
-  ifp = if_lookup_by_name (ifname);
-
-  if (! ifp)
-    return (struct ospf6_interface *) NULL;
-
-  o6i = (struct ospf6_interface *) ifp->info;
-  return o6i;
-}
-
-int
-ospf6_interface_count_neighbor_in_state (u_char state,
-                                         struct ospf6_interface *o6i)
-{
-  listnode n;
-  struct ospf6_neighbor *o6n;
-  int count = 0;
-
-  for (n = listhead (o6i->neighbor_list); n; nextnode (n))
+  /* log */
+  if (IS_OSPF6_DEBUG_INTERFACE)
     {
-      o6n = (struct ospf6_neighbor *) getdata (n);
-      if (o6n->state == state)
-        count++;
+      zlog_info ("Interface state change %s: %s -> %s", oi->interface->name,
+                 ospf6_interface_state_str[prev_state],
+                 ospf6_interface_state_str[next_state]);
     }
-  return count;
-}
 
-int
-ospf6_interface_count_full_neighbor (struct ospf6_interface *o6i)
-{
-  listnode n;
-  struct ospf6_neighbor *o6n;
-  int count = 0;
+  if ((prev_state == OSPF6_INTERFACE_DR ||
+       prev_state == OSPF6_INTERFACE_BDR) &&
+      (next_state != OSPF6_INTERFACE_DR &&
+       next_state != OSPF6_INTERFACE_BDR))
+    ospf6_leave_alldrouters (oi->interface->ifindex);
+  if ((prev_state != OSPF6_INTERFACE_DR &&
+       prev_state != OSPF6_INTERFACE_BDR) &&
+      (next_state == OSPF6_INTERFACE_DR ||
+       next_state == OSPF6_INTERFACE_BDR))
+    ospf6_join_alldrouters (oi->interface->ifindex);
 
-  for (n = listhead (o6i->neighbor_list); n; nextnode (n))
+  OSPF6_ROUTER_LSA_SCHEDULE (oi->area);
+  if (prev_state == OSPF6_INTERFACE_DR || next_state == OSPF6_INTERFACE_DR)
     {
-      o6n = (struct ospf6_neighbor *) getdata (n);
-      if (o6n->state == NBS_FULL)
-        count++;
+      OSPF6_NETWORK_LSA_SCHEDULE (oi);
+      OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi);
+      OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area);
     }
-  return count;
+}
+
+
+/* DR Election, RFC2328 section 9.4 */
+
+#define IS_ELIGIBLE(n) \
+  ((n)->state >= OSPF6_NEIGHBOR_TWOWAY && (n)->priority != 0)
+
+static struct ospf6_neighbor *
+better_bdrouter (struct ospf6_neighbor *a, struct ospf6_neighbor *b)
+{
+  if ((a == NULL || ! IS_ELIGIBLE (a) || a->drouter == a->router_id) &&
+      (b == NULL || ! IS_ELIGIBLE (b) || b->drouter == b->router_id))
+    return NULL;
+  else if (a == NULL || ! IS_ELIGIBLE (a) || a->drouter == a->router_id)
+    return b;
+  else if (b == NULL || ! IS_ELIGIBLE (b) || b->drouter == b->router_id)
+    return a;
+
+  if (a->bdrouter == a->router_id && b->bdrouter != b->router_id)
+    return a;
+  if (a->bdrouter != a->router_id && b->bdrouter == b->router_id)
+    return b;
+
+  if (a->priority > b->priority)
+    return a;
+  if (a->priority < b->priority)
+    return b;
+
+  if (ntohl (a->router_id) > ntohl (b->router_id))
+    return a;
+  if (ntohl (a->router_id) < ntohl (b->router_id))
+    return b;
+
+  zlog_warn ("Router-ID duplicate ?");
+  return a;
+}
+
+static struct ospf6_neighbor *
+better_drouter (struct ospf6_neighbor *a, struct ospf6_neighbor *b)
+{
+  if ((a == NULL || ! IS_ELIGIBLE (a) || a->drouter != a->router_id) &&
+      (b == NULL || ! IS_ELIGIBLE (b) || b->drouter != b->router_id))
+    return NULL;
+  else if (a == NULL || ! IS_ELIGIBLE (a) || a->drouter != a->router_id)
+    return b;
+  else if (b == NULL || ! IS_ELIGIBLE (b) || b->drouter != b->router_id)
+    return a;
+
+  if (a->drouter == a->router_id && b->drouter != b->router_id)
+    return a;
+  if (a->drouter != a->router_id && b->drouter == b->router_id)
+    return b;
+
+  if (a->priority > b->priority)
+    return a;
+  if (a->priority < b->priority)
+    return b;
+
+  if (ntohl (a->router_id) > ntohl (b->router_id))
+    return a;
+  if (ntohl (a->router_id) < ntohl (b->router_id))
+    return b;
+
+  zlog_warn ("Router-ID duplicate ?");
+  return a;
+}
+
+static u_char
+dr_election (struct ospf6_interface *oi)
+{
+  listnode i;
+  struct ospf6_neighbor *on, *drouter, *bdrouter, myself;
+  struct ospf6_neighbor *best_drouter, *best_bdrouter;
+  u_char next_state = 0;
+
+  drouter = bdrouter = NULL;
+  best_drouter = best_bdrouter = NULL;
+
+  /* pseudo neighbor myself, including noting current DR/BDR (1) */
+  memset (&myself, 0, sizeof (myself));
+  inet_ntop (AF_INET, &oi->area->ospf6->router_id, myself.name,
+             sizeof (myself.name));
+  myself.state = OSPF6_NEIGHBOR_TWOWAY;
+  myself.drouter = oi->drouter;
+  myself.bdrouter = oi->bdrouter;
+  myself.priority = oi->priority;
+  myself.router_id = oi->area->ospf6->router_id;
+
+  /* Electing BDR (2) */
+  for (i = listhead (oi->neighbor_list); i; nextnode (i))
+    {
+      on = (struct ospf6_neighbor *) getdata (i);
+      bdrouter = better_bdrouter (bdrouter, on);
+    }
+  best_bdrouter = bdrouter;
+  bdrouter = better_bdrouter (best_bdrouter, &myself);
+
+  /* Electing DR (3) */
+  for (i = listhead (oi->neighbor_list); i; nextnode (i))
+    {
+      on = (struct ospf6_neighbor *) getdata (i);
+      drouter = better_drouter (drouter, on);
+    }
+  best_drouter = drouter;
+  drouter = better_drouter (best_drouter, &myself);
+  if (drouter == NULL)
+    drouter = bdrouter;
+
+  /* the router itself is newly/no longer DR/BDR (4) */
+  if ((drouter == &myself && myself.drouter != myself.router_id) ||
+      (drouter != &myself && myself.drouter == myself.router_id) ||
+      (bdrouter == &myself && myself.bdrouter != myself.router_id) ||
+      (bdrouter != &myself && myself.bdrouter == myself.router_id))
+    {
+      myself.drouter = (drouter ? drouter->router_id : htonl (0));
+      myself.bdrouter = (bdrouter ? bdrouter->router_id : htonl (0));
+
+      /* compatible to Electing BDR (2) */
+      bdrouter = better_bdrouter (best_bdrouter, &myself);
+
+      /* compatible to Electing DR (3) */
+      drouter = better_drouter (best_drouter, &myself);
+      if (drouter == NULL)
+        drouter = bdrouter;
+    }
+
+  /* Set interface state accordingly (5) */
+  if (drouter && drouter == &myself)
+    next_state = OSPF6_INTERFACE_DR;
+  else if (bdrouter && bdrouter == &myself)
+    next_state = OSPF6_INTERFACE_BDR;
+  else
+    next_state = OSPF6_INTERFACE_DROTHER;
+
+  /* If NBMA, schedule Start for each neighbor having priority of 0 (6) */
+  /* XXX */
+
+  /* If DR or BDR change, invoke AdjOK? for each neighbor (7) */
+  /* RFC 2328 section 12.4. Originating LSAs (3) will be handled
+     accordingly after AdjOK */
+  if (oi->drouter != (drouter ? drouter->router_id : htonl (0)) ||
+      oi->bdrouter != (bdrouter ? bdrouter->router_id : htonl (0)))
+    {
+      if (IS_OSPF6_DEBUG_INTERFACE)
+        zlog_info ("DR Election on %s: DR: %s BDR: %s", oi->interface->name,
+                   (drouter ? drouter->name : "0.0.0.0"),
+                   (bdrouter ? bdrouter->name : "0.0.0.0"));
+
+      for (i = listhead (oi->neighbor_list); i; nextnode (i))
+        {
+          on = (struct ospf6_neighbor *) getdata (i);
+          if (on->state < OSPF6_NEIGHBOR_TWOWAY)
+            continue;
+          /* Schedule AdjOK. */
+          thread_add_event (master, adj_ok, on, 0);
+        }
+    }
+
+  oi->drouter = (drouter ? drouter->router_id : htonl (0));
+  oi->bdrouter = (bdrouter ? bdrouter->router_id : htonl (0));
+  return next_state;
+}
+
+
+/* Interface State Machine */
+int
+interface_up (struct thread *thread)
+{
+  struct ospf6_interface *oi;
+
+  oi = (struct ospf6_interface *) THREAD_ARG (thread);
+  assert (oi && oi->interface);
+
+  if (IS_OSPF6_DEBUG_INTERFACE)
+    zlog_info ("Interface Event %s: [InterfaceUp]",
+               oi->interface->name);
+
+  /* check physical interface is up */
+  if (! if_is_up (oi->interface))
+    {
+      if (IS_OSPF6_DEBUG_INTERFACE)
+        zlog_info ("Interface %s is down, can't execute [InterfaceUp]",
+                   oi->interface->name);
+      return 0;
+    }
+
+  /* if already enabled, do nothing */
+  if (oi->state > OSPF6_INTERFACE_DOWN)
+    {
+      if (IS_OSPF6_DEBUG_INTERFACE)
+        zlog_info ("Interface %s already enabled",
+                   oi->interface->name);
+      return 0;
+    }
+
+  /* Join AllSPFRouters */
+  ospf6_join_allspfrouters (oi->interface->ifindex);
+
+  /* Update interface route */
+  ospf6_interface_connected_route_update (oi->interface);
+
+  /* Schedule Hello */
+  if (! CHECK_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE))
+    thread_add_event (master, ospf6_hello_send, oi, 0);
+
+  /* decide next interface state */
+  if (if_is_pointopoint (oi->interface))
+    ospf6_interface_state_change (OSPF6_INTERFACE_POINTTOPOINT, oi);
+  else if (oi->priority == 0)
+    ospf6_interface_state_change (OSPF6_INTERFACE_DROTHER, oi);
+  else
+    {
+      ospf6_interface_state_change (OSPF6_INTERFACE_WAITING, oi);
+      thread_add_timer (master, wait_timer, oi, oi->dead_interval);
+    }
+
+  return 0;
 }
 
 int
-ospf6_interface_is_enabled (unsigned int ifindex)
+wait_timer (struct thread *thread)
 {
-  struct ospf6_interface *o6i;
+  struct ospf6_interface *oi;
 
-  o6i = ospf6_interface_lookup_by_index (ifindex);
-  if (! o6i)
-    return 0;
+  oi = (struct ospf6_interface *) THREAD_ARG (thread);
+  assert (oi && oi->interface);
 
-  if (! o6i->area)
-    return 0;
+  if (IS_OSPF6_DEBUG_INTERFACE)
+    zlog_info ("Interface Event %s: [WaitTimer]",
+               oi->interface->name);
 
-  if (o6i->state <= IFS_DOWN)
-    return 0;
+  if (oi->state == OSPF6_INTERFACE_WAITING)
+    ospf6_interface_state_change (dr_election (oi), oi);
 
-  return 1;
+  return 0;
 }
 
-void
-ospf6_interface_delayed_ack_add (struct ospf6_lsa *lsa,
-                                 struct ospf6_interface *o6i)
+int
+backup_seen (struct thread *thread)
 {
-  struct ospf6_lsa *summary;
-  summary = ospf6_lsa_summary_create (lsa->header);
-  ospf6_lsdb_add (summary, o6i->ack_list);
+  struct ospf6_interface *oi;
+
+  oi = (struct ospf6_interface *) THREAD_ARG (thread);
+  assert (oi && oi->interface);
+
+  if (IS_OSPF6_DEBUG_INTERFACE)
+    zlog_info ("Interface Event %s: [BackupSeen]",
+               oi->interface->name);
+
+  if (oi->state == OSPF6_INTERFACE_WAITING)
+    ospf6_interface_state_change (dr_election (oi), oi);
+
+  return 0;
 }
 
-void
-ospf6_interface_delayed_ack_remove (struct ospf6_lsa *lsa,
-                                    struct ospf6_interface *o6i)
+int
+neighbor_change (struct thread *thread)
 {
-  struct ospf6_lsa *summary;
-  summary = ospf6_lsdb_lookup_lsdb (lsa->header->type, lsa->header->id,
-                                    lsa->header->adv_router, o6i->ack_list);
-  ospf6_lsdb_remove (summary, o6i->ack_list);
+  struct ospf6_interface *oi;
+
+  oi = (struct ospf6_interface *) THREAD_ARG (thread);
+  assert (oi && oi->interface);
+
+  if (IS_OSPF6_DEBUG_INTERFACE)
+    zlog_info ("Interface Event %s: [NeighborChange]",
+               oi->interface->name);
+
+  if (oi->state == OSPF6_INTERFACE_DROTHER ||
+      oi->state == OSPF6_INTERFACE_BDR ||
+      oi->state == OSPF6_INTERFACE_DR)
+    ospf6_interface_state_change (dr_election (oi), oi);
+
+  return 0;
 }
 
+int
+loopind (struct thread *thread)
+{
+  struct ospf6_interface *oi;
+
+  oi = (struct ospf6_interface *) THREAD_ARG (thread);
+  assert (oi && oi->interface);
+
+  if (IS_OSPF6_DEBUG_INTERFACE)
+    zlog_info ("Interface Event %s: [LoopInd]",
+               oi->interface->name);
+
+  /* XXX not yet */
+
+  return 0;
+}
+
+int
+interface_down (struct thread *thread)
+{
+  struct ospf6_interface *oi;
+  listnode n;
+  struct ospf6_neighbor *on;
+
+  oi = (struct ospf6_interface *) THREAD_ARG (thread);
+  assert (oi && oi->interface);
+
+  if (IS_OSPF6_DEBUG_INTERFACE)
+    zlog_info ("Interface Event %s: [InterfaceDown]",
+               oi->interface->name);
+
+  /* Leave AllSPFRouters */
+  if (oi->state > OSPF6_INTERFACE_DOWN)
+    ospf6_leave_allspfrouters (oi->interface->ifindex);
+
+  ospf6_interface_state_change (OSPF6_INTERFACE_DOWN, oi);
+
+  for (n = listhead (oi->neighbor_list); n; nextnode (n))
+    {
+      on = (struct ospf6_neighbor *) getdata (n);
+      ospf6_neighbor_delete (on);
+    }
+  list_delete_all_node (oi->neighbor_list);
+
+  return 0;
+}
+
+
 /* show specified interface structure */
 int
-ospf6_interface_show (struct vty *vty, struct interface *iface)
+ospf6_interface_show (struct vty *vty, struct interface *ifp)
 {
-  struct ospf6_interface *ospf6_interface;
+  struct ospf6_interface *oi;
   struct connected *c;
   struct prefix *p;
   listnode i;
-  char strbuf[64], dr[32], bdr[32];
+  char strbuf[64], drouter[32], bdrouter[32];
   char *updown[3] = {"down", "up", NULL};
   char *type;
+  struct timeval res, now;
+  char duration[32];
+  struct ospf6_lsa *lsa;
 
   /* check physical interface type */
-  if (if_is_loopback (iface))
+  if (if_is_loopback (ifp))
     type = "LOOPBACK";
-  else if (if_is_broadcast (iface))
+  else if (if_is_broadcast (ifp))
     type = "BROADCAST";
-  else if (if_is_pointopoint (iface))
+  else if (if_is_pointopoint (ifp))
     type = "POINTOPOINT";
   else
     type = "UNKNOWN";
 
   vty_out (vty, "%s is %s, type %s%s",
-           iface->name, updown[if_is_up (iface)], type,
+           ifp->name, updown[if_is_up (ifp)], type,
 	   VTY_NEWLINE);
-  vty_out (vty, "  Interface ID: %d%s", iface->ifindex, VTY_NEWLINE);
+  vty_out (vty, "  Interface ID: %d%s", ifp->ifindex, VTY_NEWLINE);
 
-  if (iface->info == NULL)
+  if (ifp->info == NULL)
     {
       vty_out (vty, "   OSPF not enabled on this interface%s", VTY_NEWLINE);
       return 0;
     }
   else
-    ospf6_interface = (struct ospf6_interface *) iface->info;
+    oi = (struct ospf6_interface *) ifp->info;
 
   vty_out (vty, "  Internet Address:%s", VTY_NEWLINE);
-  for (i = listhead (iface->connected); i; nextnode (i))
+  for (i = listhead (ifp->connected); i; nextnode (i))
     {
       c = (struct connected *)getdata (i);
       p = c->address;
@@ -421,103 +785,75 @@
       switch (p->family)
         {
         case AF_INET:
-          vty_out (vty, "   inet : %s%s", strbuf,
+          vty_out (vty, "    inet : %s%s", strbuf,
 		   VTY_NEWLINE);
           break;
         case AF_INET6:
-          vty_out (vty, "   inet6: %s%s", strbuf,
+          vty_out (vty, "    inet6: %s%s", strbuf,
 		   VTY_NEWLINE);
           break;
         default:
-          vty_out (vty, "   ???  : %s%s", strbuf,
+          vty_out (vty, "    ???  : %s%s", strbuf,
 		   VTY_NEWLINE);
           break;
         }
     }
 
-  if (ospf6_interface->area)
+  if (oi->area)
     {
-      inet_ntop (AF_INET, &ospf6_interface->area->ospf6->router_id,
+      vty_out (vty, "  Instance ID %d, Interface MTU %d (autodetect: %d)%s",
+	       oi->instance_id, oi->ifmtu, ifp->mtu, VTY_NEWLINE);
+      inet_ntop (AF_INET, &oi->area->area_id,
                  strbuf, sizeof (strbuf));
-      vty_out (vty, "  Instance ID %d, Router ID %s%s",
-	       ospf6_interface->instance_id, strbuf,
+      vty_out (vty, "  Area ID %s, Cost %hu%s", strbuf, oi->cost,
 	       VTY_NEWLINE);
-      inet_ntop (AF_INET, &ospf6_interface->area->area_id,
-                 strbuf, sizeof (strbuf));
-      vty_out (vty, "  Area ID %s, Cost %hu%s", strbuf,
-	       ospf6_interface->cost, VTY_NEWLINE);
     }
   else
     vty_out (vty, "  Not Attached to Area%s", VTY_NEWLINE);
 
   vty_out (vty, "  State %s, Transmit Delay %d sec, Priority %d%s",
-           ospf6_interface_state_string[ospf6_interface->state],
-           ospf6_interface->transdelay,
-           ospf6_interface->priority,
+           ospf6_interface_state_str[oi->state],
+           oi->transdelay, oi->priority,
 	   VTY_NEWLINE);
   vty_out (vty, "  Timer intervals configured:%s", VTY_NEWLINE);
   vty_out (vty, "   Hello %d, Dead %d, Retransmit %d%s",
-           ospf6_interface->hello_interval,
-           ospf6_interface->dead_interval,
-           ospf6_interface->rxmt_interval,
+           oi->hello_interval, oi->dead_interval, oi->rxmt_interval,
 	   VTY_NEWLINE);
 
-  inet_ntop (AF_INET, &ospf6_interface->dr, dr, sizeof (dr));
-  inet_ntop (AF_INET, &ospf6_interface->bdr, bdr, sizeof (bdr));
-  vty_out (vty, "  DR:%s BDR:%s%s", dr, bdr, VTY_NEWLINE);
+  inet_ntop (AF_INET, &oi->drouter, drouter, sizeof (drouter));
+  inet_ntop (AF_INET, &oi->bdrouter, bdrouter, sizeof (bdrouter));
+  vty_out (vty, "  DR: %s BDR: %s%s", drouter, bdrouter, VTY_NEWLINE);
 
   vty_out (vty, "  Number of I/F scoped LSAs is %u%s",
-                ospf6_interface->lsdb->count, VTY_NEWLINE);
-  vty_out (vty, "  %-16s %5d times, %-16s %5d times%s",
-                "DRElection", ospf6_interface->ospf6_stat_dr_election,
-                "DelayedLSAck", ospf6_interface->ospf6_stat_delayed_lsack,
-                VTY_NEWLINE);
-
-  return 0;
-}
-
-void
-ospf6_interface_statistics_show (struct vty *vty, struct ospf6_interface *o6i)
-{
-  struct timeval now, uptime;
-  u_long recv_total, send_total;
-  u_long bps_total_avg, bps_tx_avg, bps_rx_avg;
-  int i;
+           oi->lsdb->count, VTY_NEWLINE);
 
   gettimeofday (&now, (struct timezone *) NULL);
-  ospf6_timeval_sub (&now, &ospf6->starttime, &uptime);
 
-  recv_total = send_total = 0;
-  for (i = 0; i < OSPF6_MESSAGE_TYPE_MAX; i++)
-    {
-      recv_total += o6i->message_stat[i].recv_octet;
-      send_total += o6i->message_stat[i].send_octet;
-    }
-  bps_total_avg = (recv_total + send_total) * 8 / uptime.tv_sec;
-  bps_tx_avg = send_total * 8 / uptime.tv_sec;
-  bps_rx_avg = recv_total * 8 / uptime.tv_sec;
+  timerclear (&res);
+  if (oi->thread_send_lsupdate)
+    timersub (&oi->thread_send_lsupdate->u.sands, &now, &res);
+  timerstring (&res, duration, sizeof (duration));
+  vty_out (vty, "    %d Pending LSAs for LSUpdate in Time %s [thread %s]%s",
+           oi->lsupdate_list->count, duration,
+           (oi->thread_send_lsupdate ? "on" : "off"),
+           VTY_NEWLINE);
+  for (lsa = ospf6_lsdb_head (oi->lsupdate_list); lsa;
+       lsa = ospf6_lsdb_next (lsa))
+    vty_out (vty, "      %s%s", lsa->name, VTY_NEWLINE);
 
-  vty_out (vty, "     Statistics of interface %s%s",
-           o6i->interface->name, VTY_NEWLINE);
-  vty_out (vty, "         Number of Neighbor: %d%s",
-           listcount (o6i->neighbor_list), VTY_NEWLINE);
+  timerclear (&res);
+  if (oi->thread_send_lsack)
+    timersub (&oi->thread_send_lsack->u.sands, &now, &res);
+  timerstring (&res, duration, sizeof (duration));
+  vty_out (vty, "    %d Pending LSAs for LSAck in Time %s [thread %s]%s",
+           oi->lsack_list->count, duration,
+           (oi->thread_send_lsack ? "on" : "off"),
+           VTY_NEWLINE);
+  for (lsa = ospf6_lsdb_head (oi->lsack_list); lsa;
+       lsa = ospf6_lsdb_next (lsa))
+    vty_out (vty, "      %s%s", lsa->name, VTY_NEWLINE);
 
-  vty_out (vty, "         %-8s %6s %6s %8s %8s%s",
-           "Type", "tx", "rx", "tx-byte", "rx-byte", VTY_NEWLINE);
-  for (i = 0; i < OSPF6_MESSAGE_TYPE_MAX; i++)
-    {
-      vty_out (vty, "         %-8s %6d %6d %8d %8d%s",
-               ospf6_message_type_string[i],
-               o6i->message_stat[i].send,
-               o6i->message_stat[i].recv,
-               o6i->message_stat[i].send_octet,
-               o6i->message_stat[i].recv_octet,
-               VTY_NEWLINE);
-    }
-
-  vty_out (vty, "         Average Link bandwidth: %ldbps"
-                " (Tx: %ldbps Rx: %ldbps)%s",
-           bps_total_avg, bps_tx_avg, bps_rx_avg, VTY_NEWLINE);
+  return 0;
 }
 
 /* show interface */
@@ -537,10 +873,10 @@
   if (argc)
     {
       ifp = if_lookup_by_name (argv[0]);
-      if (!ifp)
+      if (ifp == NULL)
         {
           vty_out (vty, "No such Interface: %s%s", argv[0],
-		   VTY_NEWLINE);
+                   VTY_NEWLINE);
           return CMD_WARNING;
         }
       ospf6_interface_show (vty, ifp);
@@ -549,10 +885,11 @@
     {
       for (i = listhead (iflist); i; nextnode (i))
         {
-          ifp = (struct interface *)getdata (i);
+          ifp = (struct interface *) getdata (i);
           ospf6_interface_show (vty, ifp);
         }
     }
+
   return CMD_SUCCESS;
 }
 
@@ -563,188 +900,316 @@
        IP6_STR
        OSPF6_STR
        INTERFACE_STR
-       )
+       );
 
-/* interface variable set command */
-DEFUN (ipv6_ospf6_cost,
-       ipv6_ospf6_cost_cmd,
-       "ipv6 ospf6 cost COST",
+DEFUN (show_ipv6_ospf6_interface_ifname_prefix,
+       show_ipv6_ospf6_interface_ifname_prefix_cmd,
+       "show ipv6 ospf6 interface IFNAME prefix",
+       SHOW_STR
        IP6_STR
        OSPF6_STR
-       "Interface cost\n"
-       "<1-65535> Cost\n"
+       INTERFACE_STR
+       IFNAME_STR
+       "Display connected prefixes to advertise\n"
        )
 {
-  struct ospf6_interface *o6i;
   struct interface *ifp;
+  struct ospf6_interface *oi;
 
-  ifp = (struct interface *)vty->index;
-  assert (ifp);
+  ifp = if_lookup_by_name (argv[0]);
+  if (ifp == NULL)
+    {
+      vty_out (vty, "No such Interface: %s%s", argv[0], VTY_NEWLINE);
+      return CMD_WARNING;
+    }
 
-  o6i = (struct ospf6_interface *)ifp->info;
-  if (!o6i)
-    o6i = ospf6_interface_create (ifp);
-  assert (o6i);
+  oi = ifp->info;
+  if (oi == NULL)
+    {
+      vty_out (vty, "OSPFv3 is not enabled on %s%s", argv[0], VTY_NEWLINE);
+      return CMD_WARNING;
+    }
 
-  if (o6i->cost == strtol (argv[0], NULL, 10))
-    return CMD_SUCCESS;
-
-  o6i->cost = strtol (argv[0], NULL, 10);
-
-  /* execute LSA hooks */
-  CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
-
-  CALL_CHANGE_HOOK (&interface_hook, o6i);
+  argc--;
+  argv++;
+  ospf6_route_table_show (vty, argc, argv, oi->route_connected);
 
   return CMD_SUCCESS;
 }
 
-/* interface variable set command */
-DEFUN (ipv6_ospf6_hellointerval,
-       ipv6_ospf6_hellointerval_cmd,
-       "ipv6 ospf6 hello-interval HELLO_INTERVAL",
+ALIAS (show_ipv6_ospf6_interface_ifname_prefix,
+       show_ipv6_ospf6_interface_ifname_prefix_detail_cmd,
+       "show ipv6 ospf6 interface IFNAME prefix (X:X::X:X|X:X::X:X/M|detail)",
+       SHOW_STR
        IP6_STR
        OSPF6_STR
-       "Time between HELLO packets\n"
-       SECONDS_STR
+       INTERFACE_STR
+       IFNAME_STR
+       "Display connected prefixes to advertise\n"
+       OSPF6_ROUTE_ADDRESS_STR
+       OSPF6_ROUTE_PREFIX_STR
+       "Dispaly details of the prefixes\n"
+       );
+
+ALIAS (show_ipv6_ospf6_interface_ifname_prefix,
+       show_ipv6_ospf6_interface_ifname_prefix_match_cmd,
+       "show ipv6 ospf6 interface IFNAME prefix X:X::X:X/M (match|detail)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       INTERFACE_STR
+       IFNAME_STR
+       "Display connected prefixes to advertise\n"
+       OSPF6_ROUTE_PREFIX_STR
+       OSPF6_ROUTE_MATCH_STR
+       "Dispaly details of the prefixes\n"
+       );
+
+DEFUN (show_ipv6_ospf6_interface_prefix,
+       show_ipv6_ospf6_interface_prefix_cmd,
+       "show ipv6 ospf6 interface prefix",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       INTERFACE_STR
+       "Display connected prefixes to advertise\n"
        )
 {
-  struct ospf6_interface *ospf6_interface;
+  listnode i;
+  struct ospf6_interface *oi;
+  struct interface *ifp;
+
+  for (i = listhead (iflist); i; nextnode (i))
+    {
+      ifp = (struct interface *) getdata (i);
+      oi = (struct ospf6_interface *) ifp->info;
+      if (oi == NULL)
+        continue;
+
+      ospf6_route_table_show (vty, argc, argv, oi->route_connected);
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_interface_prefix,
+       show_ipv6_ospf6_interface_prefix_detail_cmd,
+       "show ipv6 ospf6 interface prefix (X:X::X:X|X:X::X:X/M|detail)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       INTERFACE_STR
+       "Display connected prefixes to advertise\n"
+       OSPF6_ROUTE_ADDRESS_STR
+       OSPF6_ROUTE_PREFIX_STR
+       "Dispaly details of the prefixes\n"
+       );
+
+ALIAS (show_ipv6_ospf6_interface_prefix,
+       show_ipv6_ospf6_interface_prefix_match_cmd,
+       "show ipv6 ospf6 interface prefix X:X::X:X/M (match|detail)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       INTERFACE_STR
+       "Display connected prefixes to advertise\n"
+       OSPF6_ROUTE_PREFIX_STR
+       OSPF6_ROUTE_MATCH_STR
+       "Dispaly details of the prefixes\n"
+       );
+
+
+/* interface variable set command */
+DEFUN (ipv6_ospf6_cost,
+       ipv6_ospf6_cost_cmd,
+       "ipv6 ospf6 cost <1-65535>",
+       IP6_STR
+       OSPF6_STR
+       "Interface cost\n"
+       "Outgoing metric of this interface\n"
+       )
+{
+  struct ospf6_interface *oi;
   struct interface *ifp;
 
   ifp = (struct interface *) vty->index;
   assert (ifp);
-  ospf6_interface = (struct ospf6_interface *) ifp->info;
-  if (!ospf6_interface)
-    ospf6_interface = ospf6_interface_create (ifp);
-  assert (ospf6_interface);
 
-  ospf6_interface->hello_interval = strtol (argv[0], NULL, 10);
+  oi = (struct ospf6_interface *) ifp->info;
+  if (oi == NULL)
+    oi = ospf6_interface_create (ifp);
+  assert (oi);
+
+  if (oi->cost == strtol (argv[0], NULL, 10))
+    return CMD_SUCCESS;
+
+  oi->cost = strtol (argv[0], NULL, 10);
+
+  /* update cost held in route_connected list in ospf6_interface */
+  ospf6_interface_connected_route_update (oi->interface);
+
+  /* execute LSA hooks */
+  if (oi->area)
+    {
+      OSPF6_LINK_LSA_SCHEDULE (oi);
+      OSPF6_ROUTER_LSA_SCHEDULE (oi->area);
+      OSPF6_NETWORK_LSA_SCHEDULE (oi);
+      OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi);
+      OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_ospf6_hellointerval,
+       ipv6_ospf6_hellointerval_cmd,
+       "ipv6 ospf6 hello-interval <1-65535>",
+       IP6_STR
+       OSPF6_STR
+       "Interval time of Hello packets\n"
+       SECONDS_STR
+       )
+{
+  struct ospf6_interface *oi;
+  struct interface *ifp;
+
+  ifp = (struct interface *) vty->index;
+  assert (ifp);
+
+  oi = (struct ospf6_interface *) ifp->info;
+  if (oi == NULL)
+    oi = ospf6_interface_create (ifp);
+  assert (oi);
+
+  oi->hello_interval = strtol (argv[0], NULL, 10);
   return CMD_SUCCESS;
 }
 
 /* interface variable set command */
 DEFUN (ipv6_ospf6_deadinterval,
        ipv6_ospf6_deadinterval_cmd,
-       "ipv6 ospf6 dead-interval ROUTER_DEAD_INTERVAL",
+       "ipv6 ospf6 dead-interval <1-65535>",
        IP6_STR
        OSPF6_STR
-       "Interval after which a neighbor is declared dead\n"
+       "Interval time after which a neighbor is declared down\n"
        SECONDS_STR
        )
 {
-  struct ospf6_interface *ospf6_interface;
+  struct ospf6_interface *oi;
   struct interface *ifp;
 
   ifp = (struct interface *) vty->index;
   assert (ifp);
-  ospf6_interface = (struct ospf6_interface *) ifp->info;
-  if (!ospf6_interface)
-    ospf6_interface = ospf6_interface_create (ifp);
-  assert (ospf6_interface);
 
-  ospf6_interface->dead_interval = strtol (argv[0], NULL, 10);
+  oi = (struct ospf6_interface *) ifp->info;
+  if (oi == NULL)
+    oi = ospf6_interface_create (ifp);
+  assert (oi);
+
+  oi->dead_interval = strtol (argv[0], NULL, 10);
   return CMD_SUCCESS;
 }
 
 /* interface variable set command */
 DEFUN (ipv6_ospf6_transmitdelay,
        ipv6_ospf6_transmitdelay_cmd,
-       "ipv6 ospf6 transmit-delay TRANSMITDELAY",
+       "ipv6 ospf6 transmit-delay <1-3600>",
        IP6_STR
        OSPF6_STR
-       "Link state transmit delay\n"
+       "Transmit delay of this interface\n"
        SECONDS_STR
        )
 {
-  struct ospf6_interface *ospf6_interface;
+  struct ospf6_interface *oi;
   struct interface *ifp;
 
   ifp = (struct interface *) vty->index;
   assert (ifp);
-  ospf6_interface = (struct ospf6_interface *) ifp->info;
-  if (!ospf6_interface)
-    ospf6_interface = ospf6_interface_create (ifp);
-  assert (ospf6_interface);
 
-  ospf6_interface->transdelay = strtol (argv[0], NULL, 10);
+  oi = (struct ospf6_interface *) ifp->info;
+  if (oi == NULL)
+    oi = ospf6_interface_create (ifp);
+  assert (oi);
+
+  oi->transdelay = strtol (argv[0], NULL, 10);
   return CMD_SUCCESS;
 }
 
 /* interface variable set command */
 DEFUN (ipv6_ospf6_retransmitinterval,
        ipv6_ospf6_retransmitinterval_cmd,
-       "ipv6 ospf6 retransmit-interval RXMTINTERVAL",
+       "ipv6 ospf6 retransmit-interval <1-65535>",
        IP6_STR
        OSPF6_STR
        "Time between retransmitting lost link state advertisements\n"
        SECONDS_STR
        )
 {
-  struct ospf6_interface *ospf6_interface;
+  struct ospf6_interface *oi;
   struct interface *ifp;
 
   ifp = (struct interface *) vty->index;
   assert (ifp);
-  ospf6_interface = (struct ospf6_interface *) ifp->info;
-  if (!ospf6_interface)
-    ospf6_interface = ospf6_interface_create (ifp);
-  assert (ospf6_interface);
 
-  ospf6_interface->rxmt_interval = strtol (argv[0], NULL, 10);
+  oi = (struct ospf6_interface *) ifp->info;
+  if (oi == NULL)
+    oi = ospf6_interface_create (ifp);
+  assert (oi);
+
+  oi->rxmt_interval = strtol (argv[0], NULL, 10);
   return CMD_SUCCESS;
 }
 
 /* interface variable set command */
 DEFUN (ipv6_ospf6_priority,
        ipv6_ospf6_priority_cmd,
-       "ipv6 ospf6 priority PRIORITY",
+       "ipv6 ospf6 priority <0-255>",
        IP6_STR
        OSPF6_STR
        "Router priority\n"
-       "<0-255> Priority\n"
+       "Priority value\n"
        )
 {
-  struct ospf6_interface *ospf6_interface;
+  struct ospf6_interface *oi;
   struct interface *ifp;
 
   ifp = (struct interface *) vty->index;
   assert (ifp);
-  ospf6_interface = (struct ospf6_interface *) ifp->info;
-  if (!ospf6_interface)
-    ospf6_interface = ospf6_interface_create (ifp);
-  assert (ospf6_interface);
 
-  ospf6_interface->priority = strtol (argv[0], NULL, 10);
+  oi = (struct ospf6_interface *) ifp->info;
+  if (oi == NULL)
+    oi = ospf6_interface_create (ifp);
+  assert (oi);
 
-  if (ospf6_interface->area)
-    ifs_change (dr_election (ospf6_interface), "Priority reconfigured",
-                ospf6_interface);
+  oi->priority = strtol (argv[0], NULL, 10);
+
+  if (oi->area)
+    ospf6_interface_state_change (dr_election (oi), oi);
 
   return CMD_SUCCESS;
 }
 
 DEFUN (ipv6_ospf6_instance,
        ipv6_ospf6_instance_cmd,
-       "ipv6 ospf6 instance-id INSTANCE",
+       "ipv6 ospf6 instance-id <0-255>",
        IP6_STR
        OSPF6_STR
-       "Instance ID\n"
-       "<0-255> Instance ID\n"
+       "Instance ID for this interface\n"
+       "Instance ID value\n"
        )
 {
-  struct ospf6_interface *ospf6_interface;
+  struct ospf6_interface *oi;
   struct interface *ifp;
 
   ifp = (struct interface *)vty->index;
   assert (ifp);
 
-  ospf6_interface = (struct ospf6_interface *)ifp->info;
-  if (!ospf6_interface)
-    ospf6_interface = ospf6_interface_create (ifp);
-  assert (ospf6_interface);
+  oi = (struct ospf6_interface *)ifp->info;
+  if (oi == NULL)
+    oi = ospf6_interface_create (ifp);
+  assert (oi);
 
-  ospf6_interface->instance_id = strtol (argv[0], NULL, 10);
+  oi->instance_id = strtol (argv[0], NULL, 10);
   return CMD_SUCCESS;
 }
 
@@ -753,34 +1218,30 @@
        "ipv6 ospf6 passive",
        IP6_STR
        OSPF6_STR
-       "passive interface: No Adjacency will be formed on this I/F\n"
+       "passive interface, No adjacency will be formed on this interface\n"
        )
 {
-  struct ospf6_interface *o6i;
+  struct ospf6_interface *oi;
   struct interface *ifp;
   listnode node;
-  struct ospf6_neighbor *o6n;
+  struct ospf6_neighbor *on;
 
   ifp = (struct interface *) vty->index;
   assert (ifp);
-  o6i = (struct ospf6_interface *) ifp->info;
-  if (! o6i)
-    o6i = ospf6_interface_create (ifp);
-  assert (o6i);
 
-  SET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
-  if (o6i->thread_send_hello)
-    {
-      thread_cancel (o6i->thread_send_hello);
-      o6i->thread_send_hello = (struct thread *) NULL;
-    }
+  oi = (struct ospf6_interface *) ifp->info;
+  if (oi == NULL)
+    oi = ospf6_interface_create (ifp);
+  assert (oi);
 
-  for (node = listhead (o6i->neighbor_list); node; nextnode (node))
+  SET_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE);
+  THREAD_OFF (oi->thread_send_hello);
+
+  for (node = listhead (oi->neighbor_list); node; nextnode (node))
     {
-      o6n = getdata (node);
-      if (o6n->inactivity_timer)
-        thread_cancel (o6n->inactivity_timer);
-      thread_execute (master, inactivity_timer, o6n, 0);
+      on = (struct ospf6_neighbor *) getdata (node);
+      THREAD_OFF (on->inactivity_timer);
+      thread_execute (master, inactivity_timer, on, 0);
     }
 
   return CMD_SUCCESS;
@@ -795,86 +1256,21 @@
        "passive interface: No Adjacency will be formed on this I/F\n"
        )
 {
-  struct ospf6_interface *o6i;
+  struct ospf6_interface *oi;
   struct interface *ifp;
 
   ifp = (struct interface *) vty->index;
   assert (ifp);
-  o6i = (struct ospf6_interface *) ifp->info;
-  if (! o6i)
-    o6i = ospf6_interface_create (ifp);
-  assert (o6i);
 
-  UNSET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
-  if (o6i->thread_send_hello == NULL)
-    thread_add_event (master, ospf6_send_hello, o6i, 0);
+  oi = (struct ospf6_interface *) ifp->info;
+  if (oi == NULL)
+    oi = ospf6_interface_create (ifp);
+  assert (oi);
 
-  return CMD_SUCCESS;
-}
-
-
-DEFUN (ipv6_ospf6_advertise_force_prefix,
-       ipv6_ospf6_advertise_force_prefix_cmd,
-       "ipv6 ospf6 advertise force-prefix",
-       IP6_STR
-       OSPF6_STR
-       "Advertising options\n"
-       "Force advertising prefix, applicable if Loopback or P-to-P\n"
-       )
-{
-  struct ospf6_interface *o6i;
-  struct interface *ifp;
-
-  ifp = (struct interface *) vty->index;
-  assert (ifp);
-  o6i = (struct ospf6_interface *) ifp->info;
-  if (! o6i)
-    o6i = ospf6_interface_create (ifp);
-  assert (o6i);
-
-  if (! if_is_loopback (ifp) && ! if_is_pointopoint (ifp))
-    {
-      vty_out (vty, "Interface not Loopback nor PointToPoint%s",
-               VTY_NEWLINE);
-      return CMD_ERR_NOTHING_TODO;
-    }
-
-  SET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_FORCE_PREFIX);
-
-  /* execute LSA hooks */
-  CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
-
-  CALL_CHANGE_HOOK (&interface_hook, o6i);
-
-  return CMD_SUCCESS;
-}
-
-DEFUN (no_ipv6_ospf6_advertise_force_prefix,
-       no_ipv6_ospf6_advertise_force_prefix_cmd,
-       "no ipv6 ospf6 advertise force-prefix",
-       NO_STR
-       IP6_STR
-       OSPF6_STR
-       "Advertising options\n"
-       "Force to advertise prefix, applicable if Loopback or P-to-P\n"
-       )
-{
-  struct ospf6_interface *o6i;
-  struct interface *ifp;
-
-  ifp = (struct interface *) vty->index;
-  assert (ifp);
-  o6i = (struct ospf6_interface *) ifp->info;
-  if (! o6i)
-    o6i = ospf6_interface_create (ifp);
-  assert (o6i);
-
-  UNSET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_FORCE_PREFIX);
-
-  /* execute LSA hooks */
-  CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
-
-  CALL_CHANGE_HOOK (&interface_hook, o6i);
+  UNSET_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE);
+  THREAD_OFF (oi->thread_send_hello);
+  oi->thread_send_hello =
+    thread_add_event (master, ospf6_hello_send, oi, 0);
 
   return CMD_SUCCESS;
 }
@@ -889,24 +1285,29 @@
        "Prefix list name\n"
        )
 {
-  struct ospf6_interface *o6i;
+  struct ospf6_interface *oi;
   struct interface *ifp;
 
   ifp = (struct interface *) vty->index;
   assert (ifp);
-  o6i = (struct ospf6_interface *) ifp->info;
-  if (! o6i)
-    o6i = ospf6_interface_create (ifp);
-  assert (o6i);
 
-  if (o6i->plist_name)
-    XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name);
-  o6i->plist_name = XSTRDUP (MTYPE_PREFIX_LIST_STR, argv[0]);
+  oi = (struct ospf6_interface *) ifp->info;
+  if (oi == NULL)
+    oi = ospf6_interface_create (ifp);
+  assert (oi);
 
-  /* execute LSA hooks */
-  CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
+  if (oi->plist_name)
+    XFREE (MTYPE_PREFIX_LIST_STR, oi->plist_name);
+  oi->plist_name = XSTRDUP (MTYPE_PREFIX_LIST_STR, argv[0]);
 
-  CALL_CHANGE_HOOK (&interface_hook, o6i);
+  ospf6_interface_connected_route_update (oi->interface);
+  OSPF6_LINK_LSA_SCHEDULE (oi);
+  if (oi->state == OSPF6_INTERFACE_DR)
+    {
+      OSPF6_NETWORK_LSA_SCHEDULE (oi);
+      OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi);
+    }
+  OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area);
 
   return CMD_SUCCESS;
 }
@@ -921,75 +1322,75 @@
        "Filter prefix using prefix-list\n"
        )
 {
-  struct ospf6_interface *o6i;
+  struct ospf6_interface *oi;
   struct interface *ifp;
 
   ifp = (struct interface *) vty->index;
   assert (ifp);
-  o6i = (struct ospf6_interface *) ifp->info;
-  if (! o6i)
-    o6i = ospf6_interface_create (ifp);
-  assert (o6i);
 
-  if (o6i->plist_name)
+  oi = (struct ospf6_interface *) ifp->info;
+  if (oi == NULL)
+    oi = ospf6_interface_create (ifp);
+  assert (oi);
+
+  if (oi->plist_name)
     {
-      XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name);
-      o6i->plist_name = NULL;
+      XFREE (MTYPE_PREFIX_LIST_STR, oi->plist_name);
+      oi->plist_name = NULL;
     }
 
-  /* execute LSA hooks */
-  CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
-
-  CALL_CHANGE_HOOK (&interface_hook, o6i);
+  ospf6_interface_connected_route_update (oi->interface);
+  OSPF6_LINK_LSA_SCHEDULE (oi);
+  if (oi->state == OSPF6_INTERFACE_DR)
+    {
+      OSPF6_NETWORK_LSA_SCHEDULE (oi);
+      OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi);
+    }
+  OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area);
 
   return CMD_SUCCESS;
 }
 
 int
-ospf6_interface_config_write (struct vty *vty)
+config_write_ospf6_interface (struct vty *vty)
 {
   listnode i;
-  struct ospf6_interface *o6i;
+  struct ospf6_interface *oi;
   struct interface *ifp;
 
   for (i = listhead (iflist); i; nextnode (i))
     {
       ifp = (struct interface *) getdata (i);
-      o6i = (struct ospf6_interface *) ifp->info;
-      if (! o6i)
+      oi = (struct ospf6_interface *) ifp->info;
+      if (oi == NULL)
         continue;
 
       vty_out (vty, "interface %s%s",
-               o6i->interface->name, VTY_NEWLINE);
-      if (o6i->cost != 1)
+               oi->interface->name, VTY_NEWLINE);
+
+      if (ifp->desc)
+        vty_out (vty, " description %s%s", ifp->desc, VTY_NEWLINE);
+
       vty_out (vty, " ipv6 ospf6 cost %d%s",
-               o6i->cost, VTY_NEWLINE);
-      if (o6i->hello_interval != 10)
+               oi->cost, VTY_NEWLINE);
       vty_out (vty, " ipv6 ospf6 hello-interval %d%s",
-               o6i->hello_interval, VTY_NEWLINE);
-      if (o6i->dead_interval != 40)
+               oi->hello_interval, VTY_NEWLINE);
       vty_out (vty, " ipv6 ospf6 dead-interval %d%s",
-               o6i->dead_interval, VTY_NEWLINE);
-      if (o6i->rxmt_interval != 5)
+               oi->dead_interval, VTY_NEWLINE);
       vty_out (vty, " ipv6 ospf6 retransmit-interval %d%s",
-               o6i->rxmt_interval, VTY_NEWLINE);
-      if (o6i->priority != 1)
+               oi->rxmt_interval, VTY_NEWLINE);
       vty_out (vty, " ipv6 ospf6 priority %d%s",
-               o6i->priority, VTY_NEWLINE);
-      if (o6i->transdelay != 1)
+               oi->priority, VTY_NEWLINE);
       vty_out (vty, " ipv6 ospf6 transmit-delay %d%s",
-               o6i->transdelay, VTY_NEWLINE);
-      if (o6i->instance_id != 0)
+               oi->transdelay, VTY_NEWLINE);
       vty_out (vty, " ipv6 ospf6 instance-id %d%s",
-               o6i->instance_id, VTY_NEWLINE);
+               oi->instance_id, VTY_NEWLINE);
 
-      if (CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_FORCE_PREFIX))
-        vty_out (vty, " ipv6 ospf6 advertise force-prefix%s", VTY_NEWLINE);
-      if (o6i->plist_name)
+      if (oi->plist_name)
         vty_out (vty, " ipv6 ospf6 advertise prefix-list %s%s",
-                 o6i->plist_name, VTY_NEWLINE);
+                 oi->plist_name, VTY_NEWLINE);
 
-      if (CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE))
+      if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE))
         vty_out (vty, " ipv6 ospf6 passive%s", VTY_NEWLINE);
 
       vty_out (vty, "!%s", VTY_NEWLINE);
@@ -1001,20 +1402,32 @@
 {
   INTERFACE_NODE,
   "%s(config-if)# ",
-  vtysh: 1
 };
 
 void
 ospf6_interface_init ()
 {
   /* Install interface node. */
-  install_node (&interface_node, ospf6_interface_config_write);
+  install_node (&interface_node, config_write_ospf6_interface);
 
   install_element (VIEW_NODE, &show_ipv6_ospf6_interface_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_interface_prefix_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_interface_prefix_detail_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_interface_prefix_match_cmd);
   install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_detail_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_match_cmd);
   install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_detail_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_match_cmd);
   install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_detail_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_match_cmd);
 
+  install_element (CONFIG_NODE, &interface_cmd);
   install_default (INTERFACE_NODE);
   install_element (INTERFACE_NODE, &interface_desc_cmd);
   install_element (INTERFACE_NODE, &no_interface_desc_cmd);
@@ -1025,12 +1438,54 @@
   install_element (INTERFACE_NODE, &ipv6_ospf6_retransmitinterval_cmd);
   install_element (INTERFACE_NODE, &ipv6_ospf6_transmitdelay_cmd);
   install_element (INTERFACE_NODE, &ipv6_ospf6_instance_cmd);
-  install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_force_prefix_cmd);
-  install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_force_prefix_cmd);
-  install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_prefix_list_cmd);
-  install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_prefix_list_cmd);
+
   install_element (INTERFACE_NODE, &ipv6_ospf6_passive_cmd);
   install_element (INTERFACE_NODE, &no_ipv6_ospf6_passive_cmd);
+
+  install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_prefix_list_cmd);
+  install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_prefix_list_cmd);
+}
+
+DEFUN (debug_ospf6_interface,
+       debug_ospf6_interface_cmd,
+       "debug ospf6 interface",
+       DEBUG_STR
+       OSPF6_STR
+       "Debug OSPFv3 Interface\n"
+      )
+{
+  OSPF6_DEBUG_INTERFACE_ON ();
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ospf6_interface,
+       no_debug_ospf6_interface_cmd,
+       "no debug ospf6 interface",
+       NO_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Debug OSPFv3 Interface\n"
+      )
+{
+  OSPF6_DEBUG_INTERFACE_ON ();
+  return CMD_SUCCESS;
+}
+
+int
+config_write_ospf6_debug_interface (struct vty *vty)
+{
+  if (IS_OSPF6_DEBUG_INTERFACE)
+    vty_out (vty, "debug ospf6 interface%s", VTY_NEWLINE);
+  return 0;
+}
+
+void
+install_element_ospf6_debug_interface ()
+{
+  install_element (ENABLE_NODE, &debug_ospf6_interface_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf6_interface_cmd);
+  install_element (CONFIG_NODE, &debug_ospf6_interface_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf6_interface_cmd);
 }
 
 
diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h
index a96ef25..48b56fc 100644
--- a/ospf6d/ospf6_interface.h
+++ b/ospf6d/ospf6_interface.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -22,10 +22,18 @@
 #ifndef OSPF6_INTERFACE_H
 #define OSPF6_INTERFACE_H
 
-#include "ospf6_message.h"
+#include "if.h"
 
-/* This file defines interface data structure. */
+/* Debug option */
+extern unsigned char conf_debug_ospf6_interface;
+#define OSPF6_DEBUG_INTERFACE_ON() \
+  (conf_debug_ospf6_interface = 1)
+#define OSPF6_DEBUG_INTERFACE_OFF() \
+  (conf_debug_ospf6_interface = 0)
+#define IS_OSPF6_DEBUG_INTERFACE \
+  (conf_debug_ospf6_interface)
 
+/* Interface structure */
 struct ospf6_interface
 {
   /* IF info from zebra */
@@ -38,10 +46,9 @@
   list neighbor_list;
 
   /* linklocal address of this I/F */
-  struct in6_addr *lladdr;
+  struct in6_addr *linklocal_addr;
 
-  /* Interface ID; same as ifindex */
-  u_int32_t if_id;
+  /* Interface ID; use interface->ifindex */
 
   /* ospf6 instance id */
   u_char instance_id;
@@ -52,7 +59,7 @@
   /* Router Priority */
   u_char priority;
 
-  /* Timers */
+  /* Time Interval */
   u_int16_t hello_interval;
   u_int16_t dead_interval;
   u_int32_t rxmt_interval;
@@ -70,84 +77,76 @@
   char flag;
 
   /* Decision of DR Election */
-  u_int32_t dr;
-  u_int32_t bdr;
-  u_int32_t prevdr;
-  u_int32_t prevbdr;
-
-  /* Ongoing Tasks */
-  struct thread *thread_send_hello;
-  struct thread *thread_send_lsack_delayed;
-
-  /* LSAs to Delayed Acknowledge */
-  struct ospf6_lsdb *ack_list;
+  u_int32_t drouter;
+  u_int32_t bdrouter;
+  u_int32_t prev_drouter;
+  u_int32_t prev_bdrouter;
 
   /* Linklocal LSA Database: includes Link-LSA */
   struct ospf6_lsdb *lsdb;
 
-  /* statistics */
-  u_int ospf6_stat_dr_election;
-  u_int ospf6_stat_delayed_lsack;
+  struct ospf6_lsdb *lsupdate_list;
+  struct ospf6_lsdb *lsack_list;
 
-  struct ospf6_message_stat message_stat[OSPF6_MESSAGE_TYPE_MAX];
+  /* Ongoing Tasks */
+  struct thread *thread_send_hello;
+  struct thread *thread_send_lsupdate;
+  struct thread *thread_send_lsack;
 
-  void (*foreach_nei) (struct ospf6_interface *, void *, int,
-                       void (*func) (void *, int, void *));
+  struct thread *thread_network_lsa;
+  struct thread *thread_link_lsa;
+  struct thread *thread_intra_prefix_lsa;
 
-  struct thread *maxage_remover;
+  struct ospf6_route_table *route_connected;
 
-  /* route-map to filter connected prefix */
+  /* prefix-list name to filter connected prefix */
   char *plist_name;
 };
 
-extern char *ospf6_interface_state_string[];
+/* interface state */
+#define OSPF6_INTERFACE_NONE             0
+#define OSPF6_INTERFACE_DOWN             1
+#define OSPF6_INTERFACE_LOOPBACK         2
+#define OSPF6_INTERFACE_WAITING          3
+#define OSPF6_INTERFACE_POINTTOPOINT     4
+#define OSPF6_INTERFACE_DROTHER          5
+#define OSPF6_INTERFACE_BDR              6
+#define OSPF6_INTERFACE_DR               7
+#define OSPF6_INTERFACE_MAX              8
 
-#define OSPF6_INTERFACE_FLAG_PASSIVE      0x01
-#define OSPF6_INTERFACE_FLAG_FORCE_PREFIX 0x02
+extern char *ospf6_interface_state_str[];
+
+/* flags */
+#define OSPF6_INTERFACE_DISABLE      0x01
+#define OSPF6_INTERFACE_PASSIVE      0x02
 
 
 /* Function Prototypes */
 
-void
-ospf6_interface_schedule_maxage_remover (void *arg, int val, void *obj);
+struct ospf6_interface *ospf6_interface_lookup_by_ifindex (int);
+struct ospf6_interface *ospf6_interface_lookup_by_name (char *);
+struct ospf6_interface *ospf6_interface_create (struct interface *);
+void ospf6_interface_delete (struct ospf6_interface *);
 
-struct ospf6_interface *
-ospf6_interface_create (struct interface *);
-void
-ospf6_interface_delete (struct ospf6_interface *);
-
-struct ospf6_interface *
-ospf6_interface_lookup_by_index (int);
-struct ospf6_interface *
-ospf6_interface_lookup_by_name (char *);
+void ospf6_interface_enable (struct ospf6_interface *);
+void ospf6_interface_disable (struct ospf6_interface *);
 
 void ospf6_interface_if_add (struct interface *);
 void ospf6_interface_if_del (struct interface *);
 void ospf6_interface_state_update (struct interface *);
-void ospf6_interface_address_update (struct interface *);
+void ospf6_interface_connected_route_update (struct interface *);
+
+/* interface event */
+int interface_up (struct thread *);
+int interface_down (struct thread *);
+int wait_timer (struct thread *);
+int backup_seen (struct thread *);
+int neighbor_change (struct thread *);
 
 void ospf6_interface_init ();
 
-#if 0
-int
-ospf6_interface_count_neighbor_in_state (u_char state,
-                                         struct ospf6_interface *o6i);
-int
-ospf6_interface_count_full_neighbor (struct ospf6_interface *);
-#endif
-
-int ospf6_interface_is_enabled (u_int32_t ifindex);
-
-void
-ospf6_interface_delayed_ack_add (struct ospf6_lsa *lsa,
-                                 struct ospf6_interface *o6i);
-void
-ospf6_interface_delayed_ack_remove (struct ospf6_lsa *lsa,
-                                    struct ospf6_interface *o6i);
-
-void
-ospf6_interface_statistics_show (struct vty *vty,
-                                 struct ospf6_interface *o6i);
+int config_write_ospf6_debug_interface (struct vty *vty);
+void install_element_ospf6_debug_interface ();
 
 #endif /* OSPF6_INTERFACE_H */
 
diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c
index b9c9ebd..47cbd39 100644
--- a/ospf6d/ospf6_intra.c
+++ b/ospf6d/ospf6_intra.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2002 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -19,356 +19,537 @@
  * Boston, MA 02111-1307, USA.  
  */
 
+#include <zebra.h>
+
+#include "log.h"
+#include "linklist.h"
+#include "thread.h"
+#include "memory.h"
+#include "if.h"
+#include "prefix.h"
+#include "table.h"
+#include "vty.h"
+#include "command.h"
+
 #include "ospf6d.h"
+#include "ospf6_proto.h"
+#include "ospf6_message.h"
+#include "ospf6_route.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
 
-static int intra_index;
-#define IS_OSPF6_DUMP_INTRA (ospf6_dump_is_on (intra_index))
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_interface.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_intra.h"
+#include "ospf6_asbr.h"
 
-#define ADD    0
-#define REMOVE 1
+/******************************/
+/* RFC2740 3.4.3.1 Router-LSA */
+/******************************/
 
-static void
-ospf6_intra_route_calculate (int type, struct ospf6_lsa *lsa,
-                             struct ospf6_route_req *topo_entry)
+int
+ospf6_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
 {
-  struct ospf6_intra_area_prefix_lsa *intra_prefix;
-  char *start, *end;
-  struct ospf6_prefix *ospf6_prefix;
-  struct ospf6_route_req request;
-  struct ospf6_area *area;
+  char *start, *end, *current;
+  char buf[32], name[32], bits[16], options[32];
+  struct ospf6_router_lsa *router_lsa;
+  struct ospf6_router_lsdesc *lsdesc;
 
-  if (IS_OSPF6_DUMP_INTRA)
-    {
-      char buf[64];
-      struct prefix_ls *p_ls;
-      p_ls = (struct prefix_ls *) &topo_entry->route.prefix;
-      inet_ntop (AF_INET, &p_ls->adv_router, buf, sizeof (buf));
-      zlog_info ("INTRA: Calculate [%s] %s and %s",
-                 (type == ADD ? "add" : "remove"), lsa->str, buf);
-    }
+  router_lsa = (struct ospf6_router_lsa *)
+    ((char *) lsa->header + sizeof (struct ospf6_lsa_header));
 
-  intra_prefix = OSPF6_LSA_HEADER_END (lsa->header);
+  ospf6_capability_printbuf (router_lsa->bits, bits, sizeof (bits));
+  ospf6_options_printbuf (router_lsa->options, options, sizeof (options));
+  vty_out (vty, "    Bits: %s Options: %s%s", bits, options, VTY_NEWLINE);
 
-  area = lsa->scope;
-  assert (area);
-
-  start = (char *) (intra_prefix + 1);
+  start = (char *) router_lsa + sizeof (struct ospf6_router_lsa);
   end = (char *) lsa->header + ntohs (lsa->header->length);
-  for (ospf6_prefix = (struct ospf6_prefix *) start;
-       (char *) ospf6_prefix < end;
-       ospf6_prefix = OSPF6_NEXT_PREFIX (ospf6_prefix))
+  for (current = start; current + sizeof (struct ospf6_router_lsdesc) <= end;
+       current += sizeof (struct ospf6_router_lsdesc))
     {
-      memset (&request, 0, sizeof (request));
+      lsdesc = (struct ospf6_router_lsdesc *) current;
 
-      request.route.type = OSPF6_DEST_TYPE_NETWORK;
-      request.route.prefix.family = AF_INET6;
-      request.route.prefix.prefixlen = ospf6_prefix->prefix_length;
-      ospf6_prefix_in6_addr (ospf6_prefix, &request.route.prefix.u.prefix6);
-
-      request.path.type = OSPF6_PATH_TYPE_INTRA;
-      request.path.area_id = area->area_id;
-      request.path.origin.type = lsa->header->type;
-      request.path.origin.id = lsa->header->id;
-      request.path.origin.adv_router = lsa->header->adv_router;
-      request.path.cost = topo_entry->path.cost +
-                          ntohs (ospf6_prefix->prefix_metric);
-      request.path.capability[0] = topo_entry->path.capability[0];
-      request.path.capability[1] = topo_entry->path.capability[1];
-      request.path.capability[2] = topo_entry->path.capability[2];
-
-      memcpy (&request.nexthop.address, &topo_entry->nexthop.address,
-              sizeof (request.nexthop.address));
-      request.nexthop.ifindex = topo_entry->nexthop.ifindex;
-
-      if (type == ADD)
-        ospf6_route_add (&request, area->route_table);
-      else if (type == REMOVE)
-        ospf6_route_remove (&request, area->route_table);
+      if (lsdesc->type == OSPF6_ROUTER_LSDESC_POINTTOPOINT)
+        snprintf (name, sizeof (name), "Point-To-Point");
+      else if (lsdesc->type == OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK)
+        snprintf (name, sizeof (name), "Transit-Network");
+      else if (lsdesc->type == OSPF6_ROUTER_LSDESC_STUB_NETWORK)
+        snprintf (name, sizeof (name), "Stub-Network");
+      else if (lsdesc->type == OSPF6_ROUTER_LSDESC_VIRTUAL_LINK)
+        snprintf (name, sizeof (name), "Virtual-Link");
       else
-        assert (0);
-    }
-}
+        snprintf (name, sizeof (name), "Unknown (%#x)", lsdesc->type);
 
-int
-ospf6_intra_prefix_database_hook_remove (void *data)
-{
-  struct ospf6_lsa *lsa = data;
-  struct ospf6_area *area;
-  struct ospf6_intra_area_prefix_lsa *iap;
-  struct prefix_ls prefix_ls;
-  struct ospf6_route_req topo_entry;
-
-  if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTRA_PREFIX))
-    return 0;
-
-  area = (struct ospf6_area *) lsa->scope;
-  assert (area);
-
-  if (IS_OSPF6_DUMP_INTRA)
-    zlog_info ("INTRA: area %s remove: %s", area->str, lsa->str);
-
-  iap = OSPF6_LSA_HEADER_END (lsa->header);
-  memset (&prefix_ls, 0, sizeof (prefix_ls));
-  prefix_ls.prefixlen = 64;
-  prefix_ls.adv_router.s_addr = iap->refer_advrtr;
-  prefix_ls.id.s_addr = iap->refer_lsid;
-
-  if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) &&
-      iap->refer_lsid != htonl (0))
-    {
-      zlog_warn ("SPF: Malformed ID %lu of Router reference in %s",
-                 (u_long) ntohl (iap->refer_lsid), lsa->str);
-      prefix_ls.id.s_addr = htonl (0);
-    }
-
-  ospf6_route_lookup (&topo_entry, (struct prefix *) &prefix_ls,
-                      area->table_topology);
-
-  while (iap->refer_lstype == topo_entry.path.origin.type &&
-         iap->refer_lsid == topo_entry.path.origin.id &&
-         iap->refer_advrtr == topo_entry.path.origin.adv_router)
-    {
-      ospf6_intra_route_calculate (REMOVE, lsa, &topo_entry);
-      ospf6_route_next (&topo_entry);
-    }
-  return 0;
-}
-
-int
-ospf6_intra_prefix_database_hook_add (void *data)
-{
-  struct ospf6_lsa *lsa = data;
-  struct ospf6_area *area;
-  struct ospf6_intra_area_prefix_lsa *iap;
-  struct prefix_ls prefix_ls;
-  struct ospf6_route_req topo_entry;
-
-  if (lsa->header->type != htons (OSPF6_LSA_TYPE_INTRA_PREFIX))
-    return 0;
-
-  area = (struct ospf6_area *) lsa->scope;
-  assert (area);
-
-  if (IS_LSA_MAXAGE (lsa))
-    {
-      ospf6_intra_prefix_database_hook_remove (lsa);
-      return 0;
-    }
-
-  if (IS_OSPF6_DUMP_INTRA)
-    zlog_info ("INTRA: area %s add: %s", area->str, lsa->str);
-
-  iap = OSPF6_LSA_HEADER_END (lsa->header);
-
-  memset (&prefix_ls, 0, sizeof (struct prefix_ls));
-  prefix_ls.prefixlen = 64;
-  prefix_ls.adv_router.s_addr = iap->refer_advrtr;
-  prefix_ls.id.s_addr = iap->refer_lsid;
-
-  if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) &&
-      iap->refer_lsid != htonl (0))
-    {
-      zlog_warn ("INTRA: Malformed ID %lu of Router reference in %s",
-                 (u_long) ntohl (iap->refer_lsid), lsa->str);
-      prefix_ls.id.s_addr = htonl (0);
-    }
-
-  ospf6_route_lookup (&topo_entry, (struct prefix *) &prefix_ls,
-                      area->table_topology);
-
-  while (iap->refer_lstype == topo_entry.path.origin.type &&
-         iap->refer_lsid == topo_entry.path.origin.id &&
-         iap->refer_advrtr == topo_entry.path.origin.adv_router)
-    {
-      ospf6_intra_route_calculate (ADD, lsa, &topo_entry);
-      ospf6_route_next (&topo_entry);
+      vty_out (vty, "    Type: %s Metric: %d%s",
+               name, ntohs (lsdesc->metric), VTY_NEWLINE);
+      vty_out (vty, "    Interface ID: %s%s",
+               inet_ntop (AF_INET, &lsdesc->interface_id,
+                          buf, sizeof (buf)), VTY_NEWLINE);
+      vty_out (vty, "    Neighbor Interface ID: %s%s",
+               inet_ntop (AF_INET, &lsdesc->neighbor_interface_id,
+                          buf, sizeof (buf)), VTY_NEWLINE);
+      vty_out (vty, "    Neighbor Router ID: %s%s",
+               inet_ntop (AF_INET, &lsdesc->neighbor_router_id,
+                          buf, sizeof (buf)), VTY_NEWLINE);
     }
   return 0;
 }
 
 void
-ospf6_intra_topology_add (void *data)
+ospf6_router_lsa_originate_sub (struct ospf6_area *oa, int force)
 {
-  struct ospf6_route_req *topo_entry = data;
-  struct ospf6_area *area;
-  struct ospf6_intra_area_prefix_lsa *iap;
-  struct ospf6_lsdb_node node;
+  char buffer [OSPF6_MAX_LSASIZE];
+  struct ospf6_lsa_header *lsa_header;
+  struct ospf6_lsa *lsa;
 
-  area = ospf6_area_lookup (topo_entry->path.area_id, ospf6);
-  if (! area)
-    return;
+  u_int32_t link_state_id = 0;
+  listnode i, j;
+  struct ospf6_interface *oi;
+  struct ospf6_neighbor *on, *drouter = NULL;
+  struct ospf6_router_lsa *router_lsa;
+  struct ospf6_router_lsdesc *lsdesc;
+  u_int16_t type;
+  u_int32_t router;
+  int count;
 
-  if (topo_entry->route.type == OSPF6_DEST_TYPE_ROUTER &&
-      (CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) ||
-       CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_E)))
-    ospf6_route_add (topo_entry, ospf6->topology_table);
+  if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+    zlog_info ("Originate Router-LSA for Area %s", oa->name);
 
-  for (ospf6_lsdb_type (&node, htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
-                        area->lsdb);
-       ! ospf6_lsdb_is_end (&node);
-       ospf6_lsdb_next (&node))
+  memset (buffer, 0, sizeof (buffer));
+  lsa_header = (struct ospf6_lsa_header *) buffer;
+  router_lsa = (struct ospf6_router_lsa *)
+    ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header));
+
+  OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_V6);
+  OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_E);
+  OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_MC);
+  OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_N);
+  OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_R);
+  OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_DC);
+
+  UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B);
+  if (ospf6_asbr_is_asbr (ospf6))
+    SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E);
+  else
+    UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E);
+  UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_V);
+  UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_W);
+
+  /* describe links for each interfaces */
+  lsdesc = (struct ospf6_router_lsdesc *)
+    ((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa));
+
+  for (i = listhead (oa->if_list); i; nextnode (i))
     {
-      if (IS_LSA_MAXAGE (node.lsa))
+      oi = (struct ospf6_interface *) getdata (i);
+
+      /* Interfaces in state Down or Loopback are not described */
+      if (oi->state == OSPF6_INTERFACE_DOWN ||
+          oi->state == OSPF6_INTERFACE_LOOPBACK)
         continue;
 
-      iap = OSPF6_LSA_HEADER_END (node.lsa->header);
-
-      if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) &&
-          iap->refer_lsid != htonl (0))
+      /* Nor are interfaces without any full adjacencies described */
+      count = 0;
+      for (j = listhead (oi->neighbor_list); j; nextnode (j))
         {
-          zlog_warn ("INTRA: Malformed ID %lu of Router reference in %s",
-                     (u_long) ntohl (iap->refer_lsid), node.lsa->str);
+          on = (struct ospf6_neighbor *) getdata (j);
+          if (on->state == OSPF6_NEIGHBOR_FULL)
+            count++;
+        }
+      if (count == 0)
+        continue;
+
+      /* Multiple Router-LSA instance according to size limit setting */
+      if (oa->router_lsa_size_limit != 0 &&
+          (caddr_t) lsdesc + sizeof (struct ospf6_router_lsdesc) -
+          (caddr_t) buffer > oa->router_lsa_size_limit)
+        {
+          if ((caddr_t) lsdesc == (caddr_t) router_lsa +
+                                  sizeof (struct ospf6_router_lsa))
+            {
+              if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+                zlog_info ("Size limit setting for Router-LSA too short");
+              return;
+            }
+
+          /* Fill LSA Header */
+          lsa_header->age = 0;
+          lsa_header->type = htons (OSPF6_LSTYPE_ROUTER);
+          lsa_header->id = htonl (link_state_id);
+          lsa_header->adv_router = oa->ospf6->router_id;
+          lsa_header->seqnum =
+            ospf6_lsa_new_seqnum (lsa_header->type, lsa_header->id,
+                                  lsa_header->adv_router, oa);
+          lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer);
+
+          /* LSA checksum */
+          ospf6_lsa_checksum (lsa_header);
+
+          /* create LSA */
+          lsa = ospf6_lsa_create (lsa_header);
+          lsa->scope = oa;
+          if (force)
+            SET_FLAG (lsa->flag, OSPF6_LSA_REFRESH);
+
+          /* Originate */
+          ospf6_lsa_originate (lsa);
+
+          /* Reset setting for consecutive origination */
+          memset ((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa),
+                  0, (caddr_t) lsdesc - (caddr_t) router_lsa);
+          lsdesc = (struct ospf6_router_lsdesc *)
+            ((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa));
+          link_state_id ++;
         }
 
-      if (iap->refer_lstype != topo_entry->path.origin.type ||
-          iap->refer_lsid != topo_entry->path.origin.id ||
-          iap->refer_advrtr != topo_entry->path.origin.adv_router)
-        continue;
+      /* Point-to-Point interfaces */
+      if (if_is_pointopoint (oi->interface))
+        {
+          for (j = listhead (oi->neighbor_list); j; nextnode (j))
+            {
+              on = (struct ospf6_neighbor *) getdata (j);
+              if (on->state != OSPF6_NEIGHBOR_FULL)
+                continue;
 
-      ospf6_intra_route_calculate (ADD, node.lsa, topo_entry);
+              lsdesc->type = OSPF6_ROUTER_LSDESC_POINTTOPOINT;
+              lsdesc->metric = htons (oi->cost);
+              lsdesc->interface_id = htonl (oi->interface->ifindex);
+              lsdesc->neighbor_interface_id = htonl (on->ifindex);
+              lsdesc->neighbor_router_id = on->router_id;
+
+              lsdesc++;
+            }
+        }
+
+      /* Broadcast and NBMA interfaces */
+      if (if_is_broadcast (oi->interface))
+        {
+          /* If this router is not DR,
+             and If this router not fully adjacent with DR,
+             this interface is not transit yet: ignore. */
+          if (oi->state != OSPF6_INTERFACE_DR)
+            {
+              drouter = ospf6_neighbor_lookup (oi->drouter, oi);
+              if (drouter == NULL || drouter->state != OSPF6_NEIGHBOR_FULL)
+                continue;
+            }
+
+          lsdesc->type = OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK;
+          lsdesc->metric = htons (oi->cost);
+          lsdesc->interface_id = htonl (oi->interface->ifindex);
+          if (oi->state != OSPF6_INTERFACE_DR)
+            {
+              lsdesc->neighbor_interface_id = htonl (drouter->ifindex);
+              lsdesc->neighbor_router_id = drouter->router_id;
+            }
+          else
+            {
+              lsdesc->neighbor_interface_id = htonl (oi->interface->ifindex);
+              lsdesc->neighbor_router_id = oi->area->ospf6->router_id;
+            }
+
+          lsdesc++;
+        }
+
+      /* Virtual links */
+        /* xxx */
+      /* Point-to-Multipoint interfaces */
+        /* xxx */
     }
+
+  if ((caddr_t) lsdesc != (caddr_t) router_lsa +
+                          sizeof (struct ospf6_router_lsa))
+    {
+      /* Fill LSA Header */
+      lsa_header->age = 0;
+      lsa_header->type = htons (OSPF6_LSTYPE_ROUTER);
+      lsa_header->id = htonl (link_state_id);
+      lsa_header->adv_router = oa->ospf6->router_id;
+      lsa_header->seqnum =
+        ospf6_lsa_new_seqnum (lsa_header->type, lsa_header->id,
+                              lsa_header->adv_router, oa);
+      lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer);
+
+      /* LSA checksum */
+      ospf6_lsa_checksum (lsa_header);
+
+      /* create LSA */
+      lsa = ospf6_lsa_create (lsa_header);
+      lsa->scope = oa;
+      if (force)
+        SET_FLAG (lsa->flag, OSPF6_LSA_REFRESH);
+
+      /* Originate */
+      ospf6_lsa_originate (lsa);
+
+      link_state_id ++;
+    }
+
+  /* Do premature-aging of rest, undesired Router-LSAs */
+  type = ntohs (OSPF6_LSTYPE_ROUTER);
+  router = oa->ospf6->router_id;
+  for (lsa = ospf6_lsdb_type_router_head (type, router, oa->lsdb); lsa;
+       lsa = ospf6_lsdb_type_router_next (type, router, lsa))
+    {
+      if (ntohl (lsa->header->id) < link_state_id)
+        continue;
+      ospf6_lsa_premature_aging (lsa);
+    }
+}
+
+int
+ospf6_router_lsa_originate (struct thread *thread)
+{
+  struct ospf6_area *oa;
+  int force = 0;
+
+  oa = (struct ospf6_area *) THREAD_ARG (thread);
+  oa->thread_router_lsa = NULL;
+  ospf6_router_lsa_originate_sub (oa, force);
+
+  return 0;
+}
+
+int
+ospf6_router_lsa_reoriginate (struct ospf6_lsa *lsa)
+{
+  struct ospf6_area *oa;
+  int force = 1;
+
+  oa = (struct ospf6_area *) lsa->scope;
+  ospf6_router_lsa_originate_sub (oa, force);
+
+  return 0;
+}
+
+
+/*******************************/
+/* RFC2740 3.4.3.2 Network-LSA */
+/*******************************/
+
+int
+ospf6_network_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+  char *start, *end, *current;
+  struct ospf6_network_lsa *network_lsa;
+  struct ospf6_network_lsdesc *lsdesc;
+  char buf[128], options[32];
+
+  network_lsa = (struct ospf6_network_lsa *)
+    ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header));
+
+  ospf6_options_printbuf (network_lsa->options, options, sizeof (options));
+  vty_out (vty, "     Options: %s%s", options, VTY_NEWLINE);
+
+  start = (char *) network_lsa + sizeof (struct ospf6_network_lsa);
+  end = (char *) lsa->header + ntohs (lsa->header->length);
+  for (current = start; current + sizeof (struct ospf6_network_lsdesc) <= end;
+       current += sizeof (struct ospf6_network_lsdesc))
+    {
+      lsdesc = (struct ospf6_network_lsdesc *) current;
+      inet_ntop (AF_INET, &lsdesc->router_id, buf, sizeof (buf));
+      vty_out (vty, "     Attached Router: %s%s", buf, VTY_NEWLINE);
+    }
+  return 0;
 }
 
 void
-ospf6_intra_topology_remove (void *data)
+ospf6_network_lsa_originate_sub (struct ospf6_interface *oi, int force)
 {
-  struct ospf6_route_req *topo_entry = data;
-  struct ospf6_area *area;
-  struct ospf6_intra_area_prefix_lsa *iap;
-  struct ospf6_lsdb_node node;
+  char buffer [OSPF6_MAX_LSASIZE];
+  struct ospf6_lsa_header *lsa_header;
 
-  area = ospf6_area_lookup (topo_entry->path.area_id, ospf6);
-  if (! area)
+  int count;
+  struct ospf6_lsa *old, *lsa;
+  struct ospf6_network_lsa *network_lsa;
+  struct ospf6_network_lsdesc *lsdesc;
+  struct ospf6_neighbor *on;
+  struct ospf6_link_lsa *link_lsa;
+  listnode i;
+  u_int16_t type;
+
+  /* If self-originated Network-LSA for currently unenabled I/F
+     (but was once enabled, so other routers send it to this router),
+     we can't find oi->area for ospf6_lsdb_lookup (), and so can't
+     do premature aging of the Network-LSA. Just let the LSA flow
+     in network (other routers LSDB) for maximum duration of
+     MaxAge. The contents of this router's Router-LSA will preclude
+     the stale Network-LSA to be involved in routing calculation. */
+  if (oi->area == NULL)
     return;
 
-  if (topo_entry->route.type == OSPF6_DEST_TYPE_ROUTER &&
-      (CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) ||
-       CHECK_FLAG (topo_entry->path.router_bits, OSPF6_ROUTER_LSA_BIT_E)))
-    ospf6_route_remove (topo_entry, ospf6->topology_table);
+  old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_NETWORK),
+                           htonl (oi->interface->ifindex),
+                           oi->area->ospf6->router_id, oi->area->lsdb);
 
-  for (ospf6_lsdb_type (&node, htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
-                        area->lsdb);
-       ! ospf6_lsdb_is_end (&node);
-       ospf6_lsdb_next (&node))
+  /* Do not originate Network-LSA if not DR */
+  if (oi->state != OSPF6_INTERFACE_DR)
     {
-      if (IS_LSA_MAXAGE (node.lsa))
-        continue;
-
-      iap = OSPF6_LSA_HEADER_END (node.lsa->header);
-
-      if (iap->refer_lstype == htons (OSPF6_LSA_TYPE_ROUTER) &&
-          iap->refer_lsid != htonl (0))
-        zlog_warn ("SPF: Malformed ID %lu of Router reference in %s",
-                   (u_long) ntohl (iap->refer_lsid), node.lsa->str);
-
-      if (iap->refer_lstype != topo_entry->path.origin.type ||
-          iap->refer_lsid != topo_entry->path.origin.id ||
-          iap->refer_advrtr != topo_entry->path.origin.adv_router)
-        continue;
-
-      ospf6_intra_route_calculate (REMOVE, node.lsa, topo_entry);
+      if (old)
+        ospf6_lsa_premature_aging (old);
+      return;
     }
+
+  if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+    zlog_info ("Originate Network-LSA for Interface %s", oi->interface->name);
+
+  /* If none of neighbor is adjacent to us */
+  count = 0;
+  for (i = listhead (oi->neighbor_list); i; nextnode (i))
+    {
+      on = (struct ospf6_neighbor *) getdata (i);
+      if (on->state == OSPF6_NEIGHBOR_FULL)
+        count++;
+    }
+  if (count == 0)
+    {
+      if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+        zlog_info ("Interface stub, ignore");
+      if (old)
+        ospf6_lsa_premature_aging (old);
+      return;
+    }
+
+  /* prepare buffer */
+  memset (buffer, 0, sizeof (buffer));
+  lsa_header = (struct ospf6_lsa_header *) buffer;
+  network_lsa = (struct ospf6_network_lsa *)
+    ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header));
+
+  /* Collect the interface's Link-LSAs to describe
+     network's optional capabilities */
+  type = htons (OSPF6_LSTYPE_LINK);
+  for (lsa = ospf6_lsdb_type_head (type, oi->lsdb); lsa;
+       lsa = ospf6_lsdb_type_next (type, lsa))
+    {
+      link_lsa = (struct ospf6_link_lsa *)
+        ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header));
+      network_lsa->options[0] |= link_lsa->options[0];
+      network_lsa->options[1] |= link_lsa->options[1];
+      network_lsa->options[2] |= link_lsa->options[2];
+    }
+
+  lsdesc = (struct ospf6_network_lsdesc *)
+    ((caddr_t) network_lsa + sizeof (struct ospf6_network_lsa));
+
+  /* set Link Description to the router itself */
+  lsdesc->router_id = oi->area->ospf6->router_id;
+  lsdesc++;
+
+  /* Walk through the neighbors */
+  for (i = listhead (oi->neighbor_list); i; nextnode (i))
+    {
+      on = (struct ospf6_neighbor *) getdata (i);
+
+      if (on->state != OSPF6_NEIGHBOR_FULL)
+        continue;
+
+      /* set this neighbor's Router-ID to LSA */
+      lsdesc->router_id = on->router_id;
+      lsdesc++;
+    }
+
+  /* Fill LSA Header */
+  lsa_header->age = 0;
+  lsa_header->type = htons (OSPF6_LSTYPE_NETWORK);
+  lsa_header->id = htonl (oi->interface->ifindex);
+  lsa_header->adv_router = oi->area->ospf6->router_id;
+  lsa_header->seqnum =
+    ospf6_lsa_new_seqnum (lsa_header->type, lsa_header->id,
+                          lsa_header->adv_router, oi->area);
+  lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer);
+
+  /* LSA checksum */
+  ospf6_lsa_checksum (lsa_header);
+
+  /* create LSA */
+  lsa = ospf6_lsa_create (lsa_header);
+  lsa->scope = oi->area;
+  if (force)
+    SET_FLAG (lsa->flag, OSPF6_LSA_REFRESH);
+
+  /* Originate */
+  ospf6_lsa_originate (lsa);
 }
 
-
-/*****************************************/
-/* RFC2740 3.4.3.7 Intra-Area-Prefix-LSA */
-/*****************************************/
+int
+ospf6_network_lsa_originate (struct thread *thread)
+{
+  struct ospf6_interface *oi;
+  int force = 0;
 
-#define CONTINUE_IF_ADDRESS_LINKLOCAL(addr)\
-  if (IN6_IS_ADDR_LINKLOCAL (&(addr)->u.prefix6))\
-    {\
-      char buf[64];\
-      prefix2str (addr, buf, sizeof (buf));\
-      if (IS_OSPF6_DUMP_PREFIX)\
-        zlog_info ("  Filter out Linklocal: %s", buf);\
-      continue;\
-    }
+  oi = (struct ospf6_interface *) THREAD_ARG (thread);
+  oi->thread_network_lsa = NULL;
+  ospf6_network_lsa_originate_sub (oi, force);
 
-#define CONTINUE_IF_ADDRESS_UNSPECIFIED(addr)\
-  if (IN6_IS_ADDR_UNSPECIFIED (&(addr)->u.prefix6))\
-    {\
-      char buf[64];\
-      prefix2str (addr, buf, sizeof (buf));\
-      if (IS_OSPF6_DUMP_PREFIX)\
-        zlog_info ("  Filter out Unspecified: %s", buf);\
-      continue;\
-    }
-
-#define CONTINUE_IF_ADDRESS_LOOPBACK(addr)\
-  if (IN6_IS_ADDR_LOOPBACK (&(addr)->u.prefix6))\
-    {\
-      char buf[64];\
-      prefix2str (addr, buf, sizeof (buf));\
-      if (IS_OSPF6_DUMP_PREFIX)\
-        zlog_info ("  Filter out Loopback: %s", buf);\
-      continue;\
-    }
-
-#define CONTINUE_IF_ADDRESS_V4COMPAT(addr)\
-  if (IN6_IS_ADDR_V4COMPAT (&(addr)->u.prefix6))\
-    {\
-      char buf[64];\
-      prefix2str (addr, buf, sizeof (buf));\
-      if (IS_OSPF6_DUMP_PREFIX)\
-        zlog_info ("  Filter out V4Compat: %s", buf);\
-      continue;\
-    }
-
-#define CONTINUE_IF_ADDRESS_V4MAPPED(addr)\
-  if (IN6_IS_ADDR_V4MAPPED (&(addr)->u.prefix6))\
-    {\
-      char buf[64];\
-      prefix2str (addr, buf, sizeof (buf));\
-      if (IS_OSPF6_DUMP_PREFIX)\
-        zlog_info ("  Filter out V4Mapped: %s", buf);\
-      continue;\
-    }
-
+  return 0;
+}
 
 int
-ospf6_lsa_intra_prefix_show (struct vty *vty, struct ospf6_lsa *lsa)
+ospf6_network_lsa_reoriginate (struct ospf6_lsa *lsa)
 {
-  struct ospf6_intra_area_prefix_lsa *iap_lsa;
-  struct ospf6_prefix *prefix;
-  unsigned short prefixnum;
-  char buf[128], type[32], id[32], adv_router[32];
-  struct in6_addr in6;
+  struct ospf6_interface *oi;
+  int force = 1;
+
+  oi = ospf6_interface_lookup_by_ifindex (ntohl (lsa->header->id));
+  ospf6_network_lsa_originate_sub (oi, force);
+
+  return 0;
+}
+
+
+/****************************/
+/* RFC2740 3.4.3.6 Link-LSA */
+/****************************/
+
+int
+ospf6_link_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
   char *start, *end, *current;
+  struct ospf6_link_lsa *link_lsa;
+  int prefixnum;
+  char buf[128], options[32];
+  struct ospf6_prefix *prefix;
+  char *p, *mc, *la, *nu;
+  struct in6_addr in6;
 
-  assert (lsa->header);
-  iap_lsa = (struct ospf6_intra_area_prefix_lsa *) (lsa->header + 1);
+  link_lsa = (struct ospf6_link_lsa *)
+    ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header));
 
-  prefixnum = ntohs (iap_lsa->prefix_number);
-  ospf6_lsa_type_string (iap_lsa->refer_lstype, type, sizeof (type));
-  inet_ntop (AF_INET, &iap_lsa->refer_lsid, id, sizeof (id));
-  inet_ntop (AF_INET, &iap_lsa->refer_advrtr, adv_router,
-             sizeof (adv_router));
+  ospf6_options_printbuf (link_lsa->options, options, sizeof (options));
+  inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, sizeof (buf));
+  prefixnum = ntohl (link_lsa->prefix_num);
 
+  vty_out (vty, "     Priority: %d Options: %s%s",
+           link_lsa->priority, options, VTY_NEWLINE);
+  vty_out (vty, "     LinkLocal Address: %s%s", buf, VTY_NEWLINE);
   vty_out (vty, "     Number of Prefix: %d%s", prefixnum, VTY_NEWLINE);
-  vty_out (vty, "     Referenced LS Type: %s%s", type, VTY_NEWLINE);
-  vty_out (vty, "     Referenced LS ID: %s%s", id, VTY_NEWLINE);
-  vty_out (vty, "     Referenced Advertising Router: %s%s", adv_router,
-           VTY_NEWLINE);
 
-  start = (char *) lsa->header + sizeof (struct ospf6_lsa_header)
-          + sizeof (struct ospf6_intra_area_prefix_lsa);
-  end = (char *) lsa->header + ntohs (lsa->header->length);
-
+  start = (char *) link_lsa + sizeof (struct ospf6_link_lsa);
+  end = (char *) lsa->header + ntohs (lsa->header->length); 
   for (current = start; current < end; current += OSPF6_PREFIX_SIZE (prefix))
     {
       prefix = (struct ospf6_prefix *) current;
-      if (current + OSPF6_PREFIX_SIZE (prefix) > end)
-        {
-          vty_out (vty, "    Trailing %d byte garbage ... Malformed%s",
-                   end - current, VTY_NEWLINE);
-          return -1;
-        }
+      if (prefix->prefix_length == 0 ||
+          current + OSPF6_PREFIX_SIZE (prefix) > end)
+        break;
 
-      ospf6_prefix_options_str (prefix->prefix_options, buf, sizeof (buf));
-      vty_out (vty, "     Prefix Options: %s%s", buf, VTY_NEWLINE);
+      p = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_P) ?
+           "P" : "--");
+      mc = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_MC) ?
+           "MC" : "--");
+      la = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_LA) ?
+           "LA" : "--");
+      nu = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_NU) ?
+           "NU" : "--");
+      vty_out (vty, "     Prefix Options: %s|%s|%s|%s%s",
+               p, mc, la, nu, VTY_NEWLINE);
 
-      ospf6_prefix_in6_addr (prefix, &in6);
+      memset (&in6, 0, sizeof (in6));
+      memcpy (&in6, OSPF6_PREFIX_BODY (prefix),
+              OSPF6_PREFIX_SPACE (prefix->prefix_length));
       inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
       vty_out (vty, "     Prefix: %s/%d%s",
                buf, prefix->prefix_length, VTY_NEWLINE);
@@ -378,519 +559,890 @@
 }
 
 void
-ospf6_lsa_intra_prefix_update_transit (char *ifname)
+ospf6_link_lsa_originate_sub (struct ospf6_interface *oi, int force)
 {
-  char buffer [MAXLSASIZE];
-  u_int16_t size;
-  struct ospf6_lsa *old;
-  struct interface *ifp;
-  struct ospf6_interface *o6i;
-  struct ospf6_neighbor *o6n;
+  char buffer[OSPF6_MAX_LSASIZE];
+  struct ospf6_lsa_header *lsa_header;
+  struct ospf6_lsa *old, *lsa;
 
-  struct ospf6_intra_area_prefix_lsa *iap;
-  struct ospf6_lsdb_node n;
-  listnode node;
-  char *start, *end, *current;
-  struct ospf6_prefix *prefix, *dup, *src, *dst;
-  struct ospf6_link_lsa *link;
-  char buf[128];
-  int count, prefix_num;
+  struct ospf6_link_lsa *link_lsa;
+  struct ospf6_route *route;
+  struct ospf6_prefix *op;
 
-  list adv_list;
-
-  ifp = if_lookup_by_name (ifname);
-  if (! ifp)
-    {
-      zlog_warn ("Update Intra-Prefix (Transit): No such Interface: %s",
-                  ifname);
-      return;
-    }
-
-  o6i = (struct ospf6_interface *) ifp->info;
-  if (! o6i || ! o6i->area)
-    {
-      zlog_warn ("Update Intra-Prefix (Transit): Interface not enabled: %s",
-                  ifname);
-      return;
-    }
+  if (oi->area == NULL)
+    return;
 
   /* find previous LSA */
-  old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
-                           htonl (o6i->if_id), ospf6->router_id,
-                           o6i->area);
+  old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_LINK),
+                           htonl (oi->interface->ifindex),
+                           oi->area->ospf6->router_id, oi->lsdb);
 
-  /* Don't originate Network-LSA if not DR */
-  if (o6i->state != IFS_DR)
+  if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE))
     {
       if (old)
-        {
-          if (IS_OSPF6_DUMP_PREFIX)
-            zlog_info ("Update Intra-Prefix (Transit): %s not DR",
-                       o6i->interface->name);
-          ospf6_lsa_premature_aging (old);
-        }
-      return;
-    }
-
-  /* If none of neighbor is adjacent to us */
-  count = 0;
-  o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state);
-  if (count == 0)
-    {
-      if (IS_OSPF6_DUMP_PREFIX)
-        zlog_info ("Update Intra-Prefix (Transit): %s is Stub",
-                   o6i->interface->name);
-      if (old)
         ospf6_lsa_premature_aging (old);
       return;
     }
 
-  if (IS_OSPF6_DUMP_PREFIX)
-    zlog_info ("Update Intra-Prefix (Transit): Interface %s",
-               o6i->interface->name);
+  if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+    zlog_info ("Originate Link-LSA for Interface %s", oi->interface->name);
 
-  adv_list = list_new ();
-
-  /* foreach Link-LSA associated with this Link */
-  for (ospf6_lsdb_type (&n, htons (OSPF6_LSA_TYPE_LINK), o6i->lsdb);
-       ! ospf6_lsdb_is_end (&n); ospf6_lsdb_next (&n))
+  /* can't make Link-LSA if linklocal address not set */
+  if (oi->linklocal_addr == NULL)
     {
-      if (IS_LSA_MAXAGE (n.lsa))
+      if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+        zlog_info ("No Linklocal address on %s, defer originating",
+                   oi->interface->name);
+      if (old)
+        ospf6_lsa_premature_aging (old);
+      return;
+    }
+
+  /* prepare buffer */
+  memset (buffer, 0, sizeof (buffer));
+  lsa_header = (struct ospf6_lsa_header *) buffer;
+  link_lsa = (struct ospf6_link_lsa *)
+    ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header));
+
+  /* Fill Link-LSA */
+  link_lsa->priority = oi->priority;
+  memcpy (link_lsa->options, oi->area->options, 3);
+  memcpy (&link_lsa->linklocal_addr, oi->linklocal_addr,
+          sizeof (struct in6_addr));
+  link_lsa->prefix_num = htonl (oi->route_connected->count);
+
+  op = (struct ospf6_prefix *)
+    ((caddr_t) link_lsa + sizeof (struct ospf6_link_lsa));
+
+  /* connected prefix to advertise */
+  for (route = ospf6_route_head (oi->route_connected); route;
+       route = ospf6_route_next (route))
+    {
+      op->prefix_length = route->prefix.prefixlen;
+      op->prefix_options = route->path.prefix_options;
+      op->prefix_metric = htons (0);
+      memcpy (OSPF6_PREFIX_BODY (op), &route->prefix.u.prefix6,
+              OSPF6_PREFIX_SPACE (op->prefix_length));
+      op = OSPF6_PREFIX_NEXT (op);
+    }
+
+  /* Fill LSA Header */
+  lsa_header->age = 0;
+  lsa_header->type = htons (OSPF6_LSTYPE_LINK);
+  lsa_header->id = htonl (oi->interface->ifindex);
+  lsa_header->adv_router = oi->area->ospf6->router_id;
+  lsa_header->seqnum =
+    ospf6_lsa_new_seqnum (lsa_header->type, lsa_header->id,
+                          lsa_header->adv_router, oi);
+  lsa_header->length = htons ((caddr_t) op - (caddr_t) buffer);
+
+  /* LSA checksum */
+  ospf6_lsa_checksum (lsa_header);
+
+  /* create LSA */
+  lsa = ospf6_lsa_create (lsa_header);
+  lsa->scope = oi;
+  if (force)
+    SET_FLAG (lsa->flag, OSPF6_LSA_REFRESH);
+
+  /* Originate */
+  ospf6_lsa_originate (lsa);
+}
+
+int
+ospf6_link_lsa_originate (struct thread *thread)
+{
+  struct ospf6_interface *oi;
+  int force = 0;
+
+  oi = (struct ospf6_interface *) THREAD_ARG (thread);
+  oi->thread_link_lsa = NULL;
+  ospf6_link_lsa_originate_sub (oi, force);
+
+  return 0;
+}
+
+int
+ospf6_link_lsa_reoriginate (struct ospf6_lsa *lsa)
+{
+  struct ospf6_interface *oi;
+  int force = 1;
+
+  oi = ospf6_interface_lookup_by_ifindex (ntohl (lsa->header->id));
+  ospf6_link_lsa_originate_sub (oi, force);
+
+  return 0;
+}
+
+
+/*****************************************/
+/* RFC2740 3.4.3.7 Intra-Area-Prefix-LSA */
+/*****************************************/
+
+int
+ospf6_intra_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+  char *start, *end, *current;
+  struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
+  int prefixnum;
+  char buf[128];
+  struct ospf6_prefix *prefix;
+  char id[16], adv_router[16];
+  char *p, *mc, *la, *nu;
+  struct in6_addr in6;
+
+  intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)
+    ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header));
+
+  prefixnum = ntohs (intra_prefix_lsa->prefix_num);
+
+  vty_out (vty, "     Number of Prefix: %d%s", prefixnum, VTY_NEWLINE);
+
+  inet_ntop (AF_INET, &intra_prefix_lsa->ref_id, id, sizeof (id));
+  inet_ntop (AF_INET, &intra_prefix_lsa->ref_adv_router,
+             adv_router, sizeof (adv_router));
+  vty_out (vty, "     Reference: %s Id: %s Adv: %s%s",
+           OSPF6_LSTYPE_NAME (intra_prefix_lsa->ref_type), id, adv_router,
+           VTY_NEWLINE);
+
+  start = (char *) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa);
+  end = (char *) lsa->header + ntohs (lsa->header->length); 
+  for (current = start; current < end; current += OSPF6_PREFIX_SIZE (prefix))
+    {
+      prefix = (struct ospf6_prefix *) current;
+      if (prefix->prefix_length == 0 ||
+          current + OSPF6_PREFIX_SIZE (prefix) > end)
+        break;
+
+      p = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_P) ?
+           "P" : "--");
+      mc = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_MC) ?
+           "MC" : "--");
+      la = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_LA) ?
+           "LA" : "--");
+      nu = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_NU) ?
+           "NU" : "--");
+      vty_out (vty, "     Prefix Options: %s|%s|%s|%s%s",
+               p, mc, la, nu, VTY_NEWLINE);
+
+      memset (&in6, 0, sizeof (in6));
+      memcpy (&in6, OSPF6_PREFIX_BODY (prefix),
+              OSPF6_PREFIX_SPACE (prefix->prefix_length));
+      inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
+      vty_out (vty, "     Prefix: %s/%d%s",
+               buf, prefix->prefix_length, VTY_NEWLINE);
+    }
+
+  return 0;
+}
+
+void
+ospf6_intra_prefix_lsa_originate_stub_sub (struct ospf6_area *oa,
+                                           int force)
+{
+  char buffer[OSPF6_MAX_LSASIZE];
+  struct ospf6_lsa_header *lsa_header;
+  struct ospf6_lsa *old, *lsa;
+
+  struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
+  struct ospf6_interface *oi;
+  struct ospf6_neighbor *on;
+  struct ospf6_route *route;
+  struct ospf6_prefix *op;
+  listnode i, j;
+  int full_count = 0;
+  unsigned short prefix_num = 0;
+  char buf[BUFSIZ];
+  struct ospf6_route_table *route_advertise;
+
+  /* find previous LSA */
+  old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_INTRA_PREFIX),
+                           htonl (0), oa->ospf6->router_id, oa->lsdb);
+
+  if (CHECK_FLAG (oa->flag, OSPF6_AREA_DISABLE))
+    {
+      if (old)
+        ospf6_lsa_premature_aging (old);
+      return;
+    }
+
+  if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+    zlog_info ("Originate Intra-Area-Prefix-LSA for area %s's stub prefix",
+               oa->name);
+
+  /* prepare buffer */
+  memset (buffer, 0, sizeof (buffer));
+  lsa_header = (struct ospf6_lsa_header *) buffer;
+  intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)
+    ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header));
+
+  /* Fill Intra-Area-Prefix-LSA */
+  intra_prefix_lsa->ref_type = htons (OSPF6_LSTYPE_ROUTER);
+  intra_prefix_lsa->ref_id = htonl (0);
+  intra_prefix_lsa->ref_adv_router = oa->ospf6->router_id;
+
+  route_advertise = ospf6_route_table_create ();
+
+  for (i = listhead (oa->if_list); i; nextnode (i))
+    {
+      oi = (struct ospf6_interface *) getdata (i);
+
+      if (oi->state == OSPF6_INTERFACE_DOWN)
+        {
+          if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+            zlog_info ("  Interface %s is down, ignore", oi->interface->name);
+          continue;
+        }
+
+      full_count = 0;
+      for (j = listhead (oi->neighbor_list); j; nextnode (j))
+        {
+          on = (struct ospf6_neighbor *) getdata (j);
+          if (on->state == OSPF6_NEIGHBOR_FULL)
+            full_count++;
+        }
+      if (oi->state != OSPF6_INTERFACE_LOOPBACK &&
+          oi->state != OSPF6_INTERFACE_POINTTOPOINT &&
+          full_count != 0)
+        {
+          if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+            zlog_info ("  Interface %s is not stub, ignore",
+                       oi->interface->name);
+          continue;
+        }
+
+      if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+        zlog_info ("  Interface %s:", oi->interface->name);
+
+      /* connected prefix to advertise */
+      for (route = ospf6_route_head (oi->route_connected); route;
+           route = ospf6_route_best_next (route))
+        {
+          if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+            {
+              prefix2str (&route->prefix, buf, sizeof (buf));
+              zlog_info ("    include %s", buf);
+            }
+          ospf6_route_add (ospf6_route_copy (route), route_advertise);
+        }
+    }
+
+  if (route_advertise->count == 0)
+    {
+      if (old)
+        ospf6_lsa_premature_aging (old);
+      ospf6_route_table_delete (route_advertise);
+      return;
+    }
+
+  /* put prefixes to advertise */
+  prefix_num = 0;
+  op = (struct ospf6_prefix *)
+    ((caddr_t) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa));
+  for (route = ospf6_route_head (route_advertise); route;
+       route = ospf6_route_best_next (route))
+    {
+      op->prefix_length = route->prefix.prefixlen;
+      op->prefix_options = route->path.prefix_options;
+      op->prefix_metric = htons (route->path.cost);
+      memcpy (OSPF6_PREFIX_BODY (op), &route->prefix.u.prefix6,
+              OSPF6_PREFIX_SPACE (op->prefix_length));
+      op = OSPF6_PREFIX_NEXT (op);
+      prefix_num++;
+    }
+
+  ospf6_route_table_delete (route_advertise);
+
+  if (prefix_num == 0)
+    {
+      if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+        zlog_info ("Quit to Advertise Intra-Prefix: no route to advertise");
+      return;
+    }
+
+  intra_prefix_lsa->prefix_num = htons (prefix_num);
+
+  /* Fill LSA Header */
+  lsa_header->age = 0;
+  lsa_header->type = htons (OSPF6_LSTYPE_INTRA_PREFIX);
+  lsa_header->id = htonl (0);
+  lsa_header->adv_router = oa->ospf6->router_id;
+  lsa_header->seqnum =
+    ospf6_lsa_new_seqnum (lsa_header->type, lsa_header->id,
+                          lsa_header->adv_router, oa);
+  lsa_header->length = htons ((caddr_t) op - (caddr_t) lsa_header);
+
+  /* LSA checksum */
+  ospf6_lsa_checksum (lsa_header);
+
+  /* create LSA */
+  lsa = ospf6_lsa_create (lsa_header);
+  lsa->scope = oa;
+  if (force)
+    SET_FLAG (lsa->flag, OSPF6_LSA_REFRESH);
+
+  /* Originate */
+  ospf6_lsa_originate (lsa);
+}
+
+void
+ospf6_intra_prefix_lsa_originate_transit_sub (struct ospf6_interface *oi,
+                                              int force)
+{
+  char buffer[OSPF6_MAX_LSASIZE];
+  struct ospf6_lsa_header *lsa_header;
+  struct ospf6_lsa *old, *lsa;
+
+  struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
+  struct ospf6_neighbor *on;
+  struct ospf6_route *route;
+  struct ospf6_prefix *op;
+  listnode i;
+  int full_count = 0;
+  unsigned short prefix_num = 0;
+  struct ospf6_route_table *route_advertise;
+  struct ospf6_link_lsa *link_lsa;
+  char *start, *end, *current;
+  u_int16_t type;
+  char buf[BUFSIZ];
+
+  if (oi->area == NULL)
+    return;
+
+  /* find previous LSA */
+  old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_INTRA_PREFIX),
+                           htonl (oi->interface->ifindex),
+                           oi->area->ospf6->router_id, oi->area->lsdb);
+
+  if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE))
+    {
+      if (old)
+        ospf6_lsa_premature_aging (old);
+      return;
+    }
+
+  if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+    zlog_info ("Originate Intra-Area-Prefix-LSA for interface %s's prefix",
+               oi->interface->name);
+
+  /* prepare buffer */
+  memset (buffer, 0, sizeof (buffer));
+  lsa_header = (struct ospf6_lsa_header *) buffer;
+  intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)
+    ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header));
+
+  /* Fill Intra-Area-Prefix-LSA */
+  intra_prefix_lsa->ref_type = htons (OSPF6_LSTYPE_NETWORK);
+  intra_prefix_lsa->ref_id = htonl (oi->interface->ifindex);
+  intra_prefix_lsa->ref_adv_router = oi->area->ospf6->router_id;
+
+  if (oi->state != OSPF6_INTERFACE_DR)
+    {
+      if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+        zlog_info ("  Interface is not DR");
+      if (old)
+        ospf6_lsa_premature_aging (old);
+      return;
+    }
+
+  full_count = 0;
+  for (i = listhead (oi->neighbor_list); i; nextnode (i))
+    {
+      on = (struct ospf6_neighbor *) getdata (i);
+      if (on->state == OSPF6_NEIGHBOR_FULL)
+        full_count++;
+    }
+  if (full_count == 0)
+    {
+      if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+        zlog_info ("  Interface is stub");
+      if (old)
+        ospf6_lsa_premature_aging (old);
+      return;
+    }
+
+  /* connected prefix to advertise */
+  route_advertise = ospf6_route_table_create ();
+
+  type = ntohs (OSPF6_LSTYPE_LINK);
+  for (lsa = ospf6_lsdb_type_head (type, oi->lsdb); lsa;
+       lsa = ospf6_lsdb_type_next (type, lsa))
+    {
+      if (OSPF6_LSA_IS_MAXAGE (lsa))
         continue;
 
-      if (IS_OSPF6_DUMP_PREFIX)
-        zlog_info ("Update Intra-Prefix (Transit): Checking %s",
-                    n.lsa->str);
+      if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+        zlog_info ("  include prefix from %s", lsa->name);
 
-      /* Check status of the advertising router */
-      if (n.lsa->header->adv_router != o6i->area->ospf6->router_id)
+      if (lsa->header->adv_router != oi->area->ospf6->router_id)
         {
-          o6n = ospf6_neighbor_lookup (n.lsa->header->adv_router, o6i);
-          if (! o6n)
+          on = ospf6_neighbor_lookup (lsa->header->adv_router, oi);
+          if (on == NULL || on->state != OSPF6_NEIGHBOR_FULL)
             {
-              if (IS_OSPF6_DUMP_PREFIX)
-                zlog_info ("Update Intra-Prefix (Transit): neighbor not found");
-              continue;
-            }
-
-          if (o6n->state != NBS_FULL)
-            {
-              if (IS_OSPF6_DUMP_PREFIX)
-                zlog_info ("Update Intra-Prefix (Transit): %s not FULL",
-                           o6n->str);
+              if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+                zlog_info ("    Neighbor not found or not Full, ignore");
               continue;
             }
         }
 
-      /* For each Prefix in this Link-LSA */
-      link = (struct ospf6_link_lsa *) (n.lsa->header + 1);
-      prefix_num = ntohl (link->llsa_prefix_num);
+      link_lsa = (struct ospf6_link_lsa *)
+        ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header));
 
-      if (IS_OSPF6_DUMP_PREFIX)
-        zlog_info ("  Prefix #%d", prefix_num);
-
-      start = (char *) (link + 1);
-      end = (char *) (n.lsa->header) + ntohs (n.lsa->header->length);
-      prefix = (struct ospf6_prefix *) start;
-      for (current = start; current < end;
-           current += OSPF6_PREFIX_SIZE (prefix))
+      prefix_num = (unsigned short) ntohl (link_lsa->prefix_num);
+      start = (char *) link_lsa + sizeof (struct ospf6_link_lsa);
+      end = (char *) lsa->header + ntohs (lsa->header->length); 
+      for (current = start; current < end && prefix_num;
+           current += OSPF6_PREFIX_SIZE (op))
         {
-          prefix = (struct ospf6_prefix *) current;
-          ospf6_prefix_string (prefix, buf, sizeof (buf));
+          op = (struct ospf6_prefix *) current;
+          if (op->prefix_length == 0 ||
+              current + OSPF6_PREFIX_SIZE (op) > end)
+            break;
 
-          /* Check duplicate prefix */
-          dup = ospf6_prefix_lookup (adv_list, prefix);
-          if (dup)
+          route = ospf6_route_create ();
+
+          route->type = OSPF6_DEST_TYPE_NETWORK;
+          route->prefix.family = AF_INET6;
+          route->prefix.prefixlen = op->prefix_length;
+          memset (&route->prefix.u.prefix6, 0, sizeof (struct in6_addr));
+          memcpy (&route->prefix.u.prefix6, OSPF6_PREFIX_BODY (op),
+                  OSPF6_PREFIX_SPACE (op->prefix_length));
+
+          route->path.origin.type = lsa->header->type;
+          route->path.origin.id = lsa->header->id;
+          route->path.origin.adv_router = lsa->header->adv_router;
+          route->path.options[0] = link_lsa->options[0];
+          route->path.options[1] = link_lsa->options[1];
+          route->path.options[2] = link_lsa->options[2];
+          route->path.prefix_options = op->prefix_options;
+          route->path.area_id = oi->area->area_id;
+          route->path.type = OSPF6_PATH_TYPE_INTRA;
+
+          if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
             {
-              if (IS_OSPF6_DUMP_PREFIX)
-                zlog_info ("  Duplicate %s", buf);
-              dup->prefix_options |= prefix->prefix_options;
-              continue;
+              prefix2str (&route->prefix, buf, sizeof (buf));
+              zlog_info ("    include %s", buf);
             }
 
-          if (prefix_num <= 0)
-            {
-              zlog_warn ("  Wong prefix number ...");
-              break;
-            }
-
-          if (IS_OSPF6_DUMP_PREFIX)
-            zlog_info ("  Prefix %s", buf);
-
-          /* copy prefix to advertise list */
-          ospf6_prefix_add (adv_list, prefix);
-
-          prefix_num --;
+          ospf6_route_add (route, route_advertise);
+          prefix_num--;
         }
+      if (current != end && IS_OSPF6_DEBUG_LSA (ORIGINATE))
+        zlog_info ("Trailing garbage in %s", lsa->name);
     }
 
-  /* if no prefix to advertise, return */
-  if (listcount (adv_list) == 0)
+  op = (struct ospf6_prefix *)
+    ((caddr_t) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa));
+
+  prefix_num = 0;
+  for (route = ospf6_route_head (route_advertise); route;
+       route = ospf6_route_best_next (route))
     {
-      if (IS_OSPF6_DUMP_PREFIX)
-        zlog_info ("  No Prefix to advertise");
-      if (old)
-        ospf6_lsa_premature_aging (old);
+      op->prefix_length = route->prefix.prefixlen;
+      op->prefix_options = route->path.prefix_options;
+      op->prefix_metric = htons (0);
+      memcpy (OSPF6_PREFIX_BODY (op), &route->prefix.u.prefix6,
+              OSPF6_PREFIX_SPACE (op->prefix_length));
+      op = OSPF6_PREFIX_NEXT (op);
+      prefix_num++;
+    }
+
+  ospf6_route_table_delete (route_advertise);
+
+  if (prefix_num == 0)
+    {
+      if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+        zlog_info ("Quit to Advertise Intra-Prefix: no route to advertise");
       return;
     }
 
-  /* prepare buffer */
-  memset (buffer, 0, sizeof (buffer));
-  size = sizeof (struct ospf6_intra_area_prefix_lsa);
-  iap = (struct ospf6_intra_area_prefix_lsa *) buffer;
+  intra_prefix_lsa->prefix_num = htons (prefix_num);
 
-  /* Set Referenced LSA field */
-  iap->refer_lstype = htons (OSPF6_LSA_TYPE_NETWORK);
-  iap->refer_lsid = htonl (o6i->if_id);
-  iap->refer_advrtr = o6i->area->ospf6->router_id;
+  /* Fill LSA Header */
+  lsa_header->age = 0;
+  lsa_header->type = htons (OSPF6_LSTYPE_INTRA_PREFIX);
+  lsa_header->id = htonl (oi->interface->ifindex);
+  lsa_header->adv_router = oi->area->ospf6->router_id;
+  lsa_header->seqnum =
+    ospf6_lsa_new_seqnum (lsa_header->type, lsa_header->id,
+                          lsa_header->adv_router, oi->area);
+  lsa_header->length = htons ((caddr_t) op - (caddr_t) lsa_header);
 
-  dst = (struct ospf6_prefix *) (iap + 1);
-  for (node = listhead (adv_list); node; nextnode (node))
-    {
-      src = (struct ospf6_prefix *) getdata (node);
+  /* LSA checksum */
+  ospf6_lsa_checksum (lsa_header);
 
-      memcpy (dst, src, OSPF6_PREFIX_SIZE (src));
+  /* create LSA */
+  lsa = ospf6_lsa_create (lsa_header);
+  lsa->scope = oi->area;
+  if (force)
+    SET_FLAG (lsa->flag, OSPF6_LSA_REFRESH);
 
-      size += OSPF6_PREFIX_SIZE (dst);
-      dst = OSPF6_NEXT_PREFIX (dst);
-    }
-  iap->prefix_number = htons (listcount (adv_list));
-
-  while ((node = listhead (adv_list)) != NULL)
-    {
-      prefix = getdata (node);
-      ospf6_prefix_delete (prefix);
-      listnode_delete (adv_list, prefix);
-    }
-  list_delete (adv_list);
-
-  ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
-                       htonl (o6i->if_id), ospf6->router_id,
-                       buffer, size, o6i->area);
-}
-
-void
-ospf6_lsa_intra_prefix_update_stub (u_int32_t area_id)
-{
-  char buffer [MAXLSASIZE];
-  u_int16_t size;
-  struct ospf6_lsa *old;
-  struct ospf6_area *o6a;
-  int count;
-
-  struct ospf6_intra_area_prefix_lsa *iap;
-  listnode i,j;
-  struct ospf6_interface *o6i = NULL;
-  struct ospf6_prefix *prefix, *dst, *src;
-  struct connected *c;
-  char buf[128];
-
-  list adv_list;
-  listnode node;
-  char prefix_buf[sizeof (struct ospf6_prefix) + sizeof (struct in6_addr)];
-
-  o6a = ospf6_area_lookup (area_id, ospf6);
-  if (! o6a)
-    {
-      char tmp[16];
-      inet_ntop (AF_INET, &area_id, tmp, sizeof (tmp));
-      zlog_warn ("Update Intra-Prefix (Stub): No such area: %s", tmp);
-      return;
-    }
-  else if (IS_OSPF6_DUMP_PREFIX)
-    {
-      zlog_info ("Update Intra-Prefix (Stub): area: %s", o6a->str);
-    }
-
-  /* find previous LSA */
-  old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
-                           htonl (0), ospf6->router_id,
-                           o6a); /* xxx, ls-id */
-
-  adv_list = list_new ();
-
-  /* Examin for each interface */
-  for (i = listhead (o6a->if_list); i; nextnode (i))
-    {
-      o6i = (struct ospf6_interface *) getdata (i);
-
-      if (o6i->state == IFS_DOWN)
-        {
-          if (IS_OSPF6_DUMP_PREFIX)
-            zlog_info ("    Interface %s: down", o6i->interface->name);
-          continue;
-        }
-
-      count = 0;
-      o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state);
-      if (o6i->state != IFS_LOOPBACK && o6i->state != IFS_PTOP &&
-          count != 0)
-        {
-          /* This interface's prefix will be included in DR's */
-          if (IS_OSPF6_DUMP_PREFIX)
-            zlog_info ("    Interface %s: not stub", o6i->interface->name);
-          continue;
-        }
-
-      if (IS_OSPF6_DUMP_PREFIX)
-        zlog_info ("    Interface %s:", o6i->interface->name);
-
-      /* copy foreach address prefix */
-      for (j = listhead (o6i->interface->connected); j; nextnode (j))
-        {
-          c = (struct connected *) getdata (j);
-
-          /* filter prefix not IPv6 */
-          if (c->address->family != AF_INET6)
-            continue;
-
-          /* for log */
-          prefix2str (c->address, buf, sizeof (buf));
-
-          CONTINUE_IF_ADDRESS_LINKLOCAL (c->address);
-          CONTINUE_IF_ADDRESS_UNSPECIFIED (c->address);
-          CONTINUE_IF_ADDRESS_LOOPBACK (c->address);
-          CONTINUE_IF_ADDRESS_V4COMPAT (c->address);
-          CONTINUE_IF_ADDRESS_V4MAPPED (c->address);
-
-          /* filter prefix specified by configuration */
-          if (o6i->plist_name)
-            {
-              struct prefix_list *plist;
-              enum prefix_list_type result = PREFIX_PERMIT;
-
-              plist = prefix_list_lookup (AFI_IP6, o6i->plist_name);
-              if (plist)
-                result = prefix_list_apply (plist, c->address);
-              else
-                zlog_warn ("Update Intra-Prefix (Stub): "
-                           "Prefix list \"%s\" not found",
-                           o6i->plist_name);
-
-              if (result == PREFIX_DENY)
-                {
-                  if (IS_OSPF6_DUMP_PREFIX)
-                    zlog_info ("    %s: Filtered by %s",
-                               buf, o6i->plist_name);
-                  continue;
-                }
-            }
-
-          /* initialize buffer for ospf6 prefix */
-          memset (prefix_buf, 0, sizeof (prefix_buf));
-          prefix = (struct ospf6_prefix *) prefix_buf;
-
-          /* set ospf6 prefix according to its state */
-          /* xxx, virtual links */
-          if (! CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_FORCE_PREFIX) &&
-              (o6i->state == IFS_LOOPBACK || o6i->state == IFS_PTOP
-              /* xxx, PoinToMultiPoint I/F type */ ))
-            {
-              prefix->prefix_length = 128;
-              prefix->prefix_options = OSPF6_PREFIX_OPTION_LA;
-              prefix->prefix_metric = htons (0);
-              memcpy (prefix + 1, &c->address->u.prefix6,
-                      OSPF6_PREFIX_SPACE (prefix->prefix_length));
-            }
-          else
-            {
-              struct prefix_ipv6 prefix_ipv6;
-              /* apply mask */
-              prefix_copy ((struct prefix *) &prefix_ipv6, c->address);
-              apply_mask_ipv6 (&prefix_ipv6);
-
-              prefix->prefix_length = prefix_ipv6.prefixlen;
-              prefix->prefix_options = 0;  /* xxx, no options yet */
-              prefix->prefix_metric = htons (o6i->cost);
-              memcpy (prefix + 1, &prefix_ipv6.prefix,
-                      OSPF6_PREFIX_SPACE (prefix->prefix_length));
-            }
-
-          ospf6_prefix_string (prefix, buf, sizeof (buf));
-          if (IS_OSPF6_DUMP_PREFIX)
-            zlog_info ("    Advertise %s", buf);
-
-          /* check in the prefix to advertising prefix list */
-          ospf6_prefix_add (adv_list, prefix);
-        }
-    }
-
-  /* If no prefix to advertise */
-  if (listcount (adv_list) == 0)
-    {
-      if (IS_OSPF6_DUMP_PREFIX)
-        zlog_info ("    No prefix to advertise");
-      if (old)
-        ospf6_lsa_premature_aging (old);
-      return;
-    }
-
-  /* prepare buffer */
-  memset (buffer, 0, sizeof (buffer));
-  size = sizeof (struct ospf6_intra_area_prefix_lsa);
-  iap = (struct ospf6_intra_area_prefix_lsa *) buffer;
-
-  /* Set Referenced LSA field */
-  iap->refer_lstype = htons (OSPF6_LSA_TYPE_ROUTER);
-  iap->refer_lsid = htonl (0);
-  iap->refer_advrtr = o6a->ospf6->router_id;
-
-  dst = (struct ospf6_prefix *) (iap + 1);
-  for (node = listhead (adv_list); node; nextnode (node))
-    {
-      src = (struct ospf6_prefix *) getdata (node);
-
-      memcpy (dst, src, OSPF6_PREFIX_SIZE (src));
-
-      size += OSPF6_PREFIX_SIZE (dst);
-      dst = OSPF6_NEXT_PREFIX (dst);
-    }
-  iap->prefix_number = htons (listcount (adv_list));
-
-  while ((node = listhead (adv_list)) != NULL)
-    {
-      prefix = getdata (node);
-      ospf6_prefix_delete (prefix);
-      listnode_delete (adv_list, prefix);
-    }
-  list_delete (adv_list);
-
-  ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
-                       htonl (0) /* xxx */, ospf6->router_id,
-                       buffer, size, o6a);
+  /* Originate */
+  ospf6_lsa_originate (lsa);
 }
 
 int
-ospf6_lsa_intra_prefix_hook_interface (void *interface)
+ospf6_intra_prefix_lsa_originate_stub (struct thread *thread)
 {
-  struct ospf6_interface *o6i = interface;
-  if (o6i->area)
-    {
-      ospf6_lsa_intra_prefix_update_transit (o6i->interface->name);
-      ospf6_lsa_intra_prefix_update_stub (o6i->area->area_id);
-    }
+  struct ospf6_area *oa;
+  int force = 0;
+
+  oa = (struct ospf6_area *) THREAD_ARG (thread);
+  oa->thread_intra_prefix_lsa = NULL;
+  ospf6_intra_prefix_lsa_originate_stub_sub (oa, force);
+
   return 0;
 }
 
 int
-ospf6_lsa_intra_prefix_hook_neighbor (void *neighbor)
+ospf6_intra_prefix_lsa_originate_transit (struct thread *thread)
 {
-  struct ospf6_neighbor *o6n = neighbor;
-  if (o6n->ospf6_interface->area)
-    {
-      ospf6_lsa_intra_prefix_update_transit (o6n->ospf6_interface->interface->name);
-      ospf6_lsa_intra_prefix_update_stub (o6n->ospf6_interface->area->area_id);
-    }
+  struct ospf6_interface *oi;
+  int force = 0;
+
+  oi = (struct ospf6_interface *) THREAD_ARG (thread);
+  oi->thread_intra_prefix_lsa = NULL;
+  ospf6_intra_prefix_lsa_originate_transit_sub (oi, force);
+
   return 0;
 }
 
 int
-ospf6_intra_prefix_link_database_hook (void *new)
+ospf6_intra_prefix_lsa_reoriginate (struct ospf6_lsa *lsa)
 {
-  struct ospf6_lsa *lsa = new;
-  struct ospf6_interface *o6i;
-
-  if (lsa->header->type != htons (OSPF6_LSA_TYPE_LINK))
-    return 0;
-
-  o6i = lsa->scope;
-  if (o6i->state != IFS_DR)
-    return 0;
-
-  ospf6_lsa_intra_prefix_update_transit (o6i->interface->name);
-  ospf6_lsa_intra_prefix_update_stub (o6i->area->area_id);
-  return 0;
-}
-
-int
-ospf6_lsa_intra_prefix_refresh (void *old)
-{
-  struct ospf6_lsa *lsa = old;
-  struct ospf6_interface *o6i;
-  struct ospf6_area *o6a;
+  struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
+  u_int16_t type;
   u_int32_t id;
+  struct ospf6_area *oa;
+  struct ospf6_interface *oi;
+  int force = 1;
 
-  id = ntohl (lsa->header->id);
-  if (id)
+  intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)
+    ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header));
+  type = ntohs (intra_prefix_lsa->ref_type);
+  id = ntohl (intra_prefix_lsa->ref_id);
+
+  if (type == OSPF6_LSTYPE_ROUTER && id == 0)
     {
-      o6i = ospf6_interface_lookup_by_index (id);
-      if (o6i)
-        ospf6_lsa_intra_prefix_update_transit (o6i->interface->name);
-      else
+      oa = (struct ospf6_area *) lsa->scope;
+      ospf6_intra_prefix_lsa_originate_stub_sub (oa, force);
+    }
+  else if (type == OSPF6_LSTYPE_NETWORK && id != 0)
+    {
+      if (intra_prefix_lsa->ref_id != lsa->header->id)
         ospf6_lsa_premature_aging (lsa);
+      oi = ospf6_interface_lookup_by_ifindex (id);
+      ospf6_intra_prefix_lsa_originate_transit_sub (oi, force);
     }
   else
-    {
-      o6a = lsa->scope;
-      ospf6_lsa_intra_prefix_update_stub (o6a->area_id);
-    }
+    ospf6_lsa_premature_aging (lsa);
 
   return 0;
 }
 
 void
-ospf6_intra_prefix_register ()
+ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa)
 {
-  struct ospf6_lsa_slot slot, *sp;
-  struct ospf6_hook hook;
+  struct ospf6_area *oa;
+  struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
+  struct prefix ls_prefix;
+  struct ospf6_route *route, *ls_entry;
+  int i, prefix_num;
+  struct ospf6_prefix *op;
+  char *start, *current, *end;
+  char buf[64];
 
-  memset (&slot, 0, sizeof (struct ospf6_lsa_slot));
-  slot.type              = htons (OSPF6_LSA_TYPE_INTRA_PREFIX);
-  slot.name              = "Intra-Prefix";
-  slot.func_show         = ospf6_lsa_intra_prefix_show;
-  slot.func_refresh      = ospf6_lsa_intra_prefix_refresh;
-  ospf6_lsa_slot_register (&slot);
+  if (IS_OSPF6_DEBUG_ROUTE (INTRA))
+    zlog_info ("%s found", lsa->name);
 
-  memset (&hook, 0, sizeof (hook));
-  hook.name = "OriginateIntraPrefix";
-  hook.hook_add = ospf6_lsa_intra_prefix_hook_interface;
-  hook.hook_change = ospf6_lsa_intra_prefix_hook_interface;
-  hook.hook_remove = NULL; /* XXX */
-  ospf6_hook_register (&hook, &interface_hook);
+  oa = (struct ospf6_area *) lsa->scope;
+  intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)
+    OSPF6_LSA_HEADER_END (lsa->header);
+  if (intra_prefix_lsa->ref_type == htons (OSPF6_LSTYPE_ROUTER))
+    ospf6_linkstate_prefix (intra_prefix_lsa->ref_adv_router,
+                            htonl (0), &ls_prefix);
+  else if (intra_prefix_lsa->ref_type == htons (OSPF6_LSTYPE_NETWORK))
+    ospf6_linkstate_prefix (intra_prefix_lsa->ref_adv_router,
+                            intra_prefix_lsa->ref_id, &ls_prefix);
+  else
+    {
+      if (IS_OSPF6_DEBUG_ROUTE (INTRA))
+        zlog_info ("Unknown reference LS-type: %#hx",
+                   ntohs (intra_prefix_lsa->ref_type));
+      return;
+    }
 
-  memset (&hook, 0, sizeof (hook));
-  hook.name = "OriginateIntraPrefix";
-  hook.hook_add = ospf6_lsa_intra_prefix_hook_neighbor;
-  hook.hook_change = ospf6_lsa_intra_prefix_hook_neighbor;
-  hook.hook_remove = ospf6_lsa_intra_prefix_hook_neighbor;
-  ospf6_hook_register (&hook, &neighbor_hook);
+  ls_entry = ospf6_route_lookup (&ls_prefix, oa->spf_table);
+  if (ls_entry == NULL)
+    {
+      if (IS_OSPF6_DEBUG_ROUTE (INTRA))
+        {
+          ospf6_linkstate_prefix2str (&ls_prefix, buf, sizeof (buf));
+          zlog_info ("LS entry does not exist: %s", buf);
+        }
+      return;
+    }
 
-  sp = ospf6_lsa_slot_get (htons (OSPF6_LSA_TYPE_INTRA_PREFIX));
-  hook.name = "CalculateIntraPrefix";
-  hook.hook_add = ospf6_intra_prefix_database_hook_add;
-  hook.hook_change = ospf6_intra_prefix_database_hook_add;
-  hook.hook_remove = ospf6_intra_prefix_database_hook_remove;
-  ospf6_hook_register (&hook, &sp->database_hook);
+  prefix_num = ntohs (intra_prefix_lsa->prefix_num);
+  start = (caddr_t) intra_prefix_lsa +
+          sizeof (struct ospf6_intra_prefix_lsa);
+  end = OSPF6_LSA_END (lsa->header);
+  for (current = start; current < end; current += OSPF6_PREFIX_SIZE (op))
+    {
+      op = (struct ospf6_prefix *) current;
+      if (prefix_num == 0)
+        break;
+      if (end < current + OSPF6_PREFIX_SIZE (op))
+        break;
+
+      route = ospf6_route_create ();
+      route->prefix.prefixlen = op->prefix_length;
+      route->prefix.family = AF_INET6;
+      memcpy (&route->prefix.u.prefix6, OSPF6_PREFIX_BODY (op),
+              OSPF6_PREFIX_SPACE (op->prefix_length));
+      route->type = OSPF6_DEST_TYPE_NETWORK;
+      route->path.origin.type = lsa->header->type;
+      route->path.origin.id = lsa->header->id;
+      route->path.origin.adv_router = lsa->header->adv_router;
+      route->path.prefix_options = op->prefix_options;
+      route->path.area_id = oa->area_id;
+      route->path.type = OSPF6_PATH_TYPE_INTRA;
+      route->path.metric_type = 1;
+      route->path.cost = ls_entry->path.cost +
+                         ntohs (op->prefix_metric);
+
+      for (i = 0; ospf6_nexthop_is_set (&ls_entry->nexthop[i]) &&
+           i < OSPF6_MULTI_PATH_LIMIT; i++)
+        ospf6_nexthop_copy (&route->nexthop[i], &ls_entry->nexthop[i]);
+
+      if (IS_OSPF6_DEBUG_ROUTE (INTRA))
+        {
+          prefix2str (&route->prefix, buf, sizeof (buf));
+          zlog_info ("  add %s", buf);
+        }
+
+      ospf6_route_add (route, oa->route_table);
+      prefix_num--;
+    }
+
+  if (current != end && IS_OSPF6_DEBUG_ROUTE (INTRA))
+    zlog_info ("Trailing garbage ignored");
 }
 
 void
-ospf6_intra_database_hook_intra_prefix (struct ospf6_lsa *old,
-                                        struct ospf6_lsa *new)
+ospf6_intra_prefix_lsa_remove (struct ospf6_lsa *lsa)
 {
-  if (old)
-    ospf6_intra_prefix_database_hook_remove (old);
-  if (new && ! IS_LSA_MAXAGE (new))
-    ospf6_intra_prefix_database_hook_add (new);
+  struct ospf6_area *oa;
+  struct ospf6_intra_prefix_lsa *intra_prefix_lsa;
+  struct prefix prefix;
+  struct ospf6_route *route;
+  int prefix_num;
+  struct ospf6_prefix *op;
+  char *start, *current, *end;
+  char buf[64];
+
+  if (IS_OSPF6_DEBUG_ROUTE (INTRA))
+    zlog_info ("%s disappearing", lsa->name);
+
+  oa = (struct ospf6_area *) lsa->scope;
+  intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *)
+    OSPF6_LSA_HEADER_END (lsa->header);
+
+  prefix_num = ntohs (intra_prefix_lsa->prefix_num);
+  start = (caddr_t) intra_prefix_lsa +
+          sizeof (struct ospf6_intra_prefix_lsa);
+  end = OSPF6_LSA_END (lsa->header);
+  for (current = start; current < end; current += OSPF6_PREFIX_SIZE (op))
+    {
+      op = (struct ospf6_prefix *) current;
+      if (prefix_num == 0)
+        break;
+      if (end < current + OSPF6_PREFIX_SIZE (op))
+        break;
+      prefix_num--;
+
+      prefix.family = AF_INET6;
+      prefix.prefixlen = op->prefix_length;
+      ospf6_prefix_in6_addr (&prefix.u.prefix6, op);
+
+      route = ospf6_route_lookup (&prefix, oa->route_table);
+      if (route == NULL)
+        continue;
+
+      for (ospf6_route_lock (route);
+           route && ospf6_route_is_prefix (&prefix, route);
+           route = ospf6_route_next (route))
+        {
+          if (route->type != OSPF6_DEST_TYPE_NETWORK)
+            continue;
+          if (route->path.area_id != oa->area_id)
+            continue;
+          if (route->path.type != OSPF6_PATH_TYPE_INTRA)
+            continue;
+          if (route->path.origin.type != lsa->header->type ||
+              route->path.origin.id != lsa->header->id ||
+              route->path.origin.adv_router != lsa->header->adv_router)
+            continue;
+
+          if (IS_OSPF6_DEBUG_ROUTE (INTRA))
+            {
+              prefix2str (&route->prefix, buf, sizeof (buf));
+              zlog_info ("remove %s", buf);
+            }
+          ospf6_route_remove (route, oa->route_table);
+        }
+    }
+
+  if (current != end && IS_OSPF6_DEBUG_ROUTE (INTRA))
+    zlog_info ("Trailing garbage ignored");
 }
 
 void
-ospf6_intra_database_hook_link (struct ospf6_lsa *old,
-                                struct ospf6_lsa *new)
+ospf6_intra_route_calculation (struct ospf6_area *oa)
 {
-  ospf6_intra_prefix_link_database_hook (new);
-  ospf6_spf_database_hook (old, new);
+  struct ospf6_route *route;
+  u_int16_t type;
+  struct ospf6_lsa *lsa;
+  void (*hook_add) (struct ospf6_route *) = NULL;
+  void (*hook_remove) (struct ospf6_route *) = NULL;
+
+  if (IS_OSPF6_DEBUG_ROUTE (INTRA))
+    zlog_info ("Intra-area routing table calculation for area %s",
+               oa->name);
+
+  hook_add = oa->route_table->hook_add;
+  hook_remove = oa->route_table->hook_remove;
+  oa->route_table->hook_add = NULL;
+  oa->route_table->hook_remove = NULL;
+
+  for (route = ospf6_route_head (oa->route_table); route;
+       route = ospf6_route_next (route))
+    route->flag = OSPF6_ROUTE_REMOVE;
+
+  type = htons (OSPF6_LSTYPE_INTRA_PREFIX);
+  for (lsa = ospf6_lsdb_type_head (type, oa->lsdb); lsa;
+       lsa = ospf6_lsdb_type_next (type, lsa))
+    ospf6_intra_prefix_lsa_add (lsa);
+
+  oa->route_table->hook_add = hook_add;
+  oa->route_table->hook_remove = hook_remove;
+
+  for (route = ospf6_route_head (oa->route_table); route;
+       route = ospf6_route_next (route))
+    {
+      if (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE) &&
+          CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD))
+        {
+          UNSET_FLAG (route->flag, OSPF6_ROUTE_REMOVE);
+          UNSET_FLAG (route->flag, OSPF6_ROUTE_ADD);
+        }
+
+      if (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE))
+        ospf6_route_remove (route, oa->route_table);
+      else if (CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD) ||
+               CHECK_FLAG (route->flag, OSPF6_ROUTE_CHANGE))
+        {
+          if (hook_add)
+            (*hook_add) (route);
+        }
+
+      route->flag = 0;
+    }
+
+  if (IS_OSPF6_DEBUG_ROUTE (INTRA))
+    zlog_info ("Intra-area routing table calculation for area %s: Done",
+               oa->name);
+}
+
+void
+ospf6_intra_asbr_calculation (struct ospf6_area *oa)
+{
+  struct ospf6_route *lsentry, *copy;
+  void (*hook_add) (struct ospf6_route *) = NULL;
+  void (*hook_remove) (struct ospf6_route *) = NULL;
+
+  if (IS_OSPF6_DEBUG_ASBR)
+    zlog_info ("Intra-area ASBR calculation for area %s", oa->name);
+
+  hook_add = oa->ospf6->asbr_table->hook_add;
+  hook_remove = oa->ospf6->asbr_table->hook_remove;
+  oa->ospf6->asbr_table->hook_add = NULL;
+  oa->ospf6->asbr_table->hook_remove = NULL;
+
+  for (lsentry = ospf6_route_head (oa->ospf6->asbr_table); lsentry;
+       lsentry = ospf6_route_next (lsentry))
+    {
+      if (lsentry->path.area_id != oa->area_id)
+        continue;
+      lsentry->flag = OSPF6_ROUTE_REMOVE;
+    }
+
+  for (lsentry = ospf6_route_head (oa->spf_table); lsentry;
+       lsentry = ospf6_route_next (lsentry))
+    {
+      if (lsentry->type != OSPF6_DEST_TYPE_LINKSTATE)
+        continue;
+      if (ospf6_linkstate_prefix_id (&lsentry->prefix) != htonl (0))
+        continue;
+      if (! CHECK_FLAG (lsentry->path.router_bits, OSPF6_ROUTER_BIT_E))
+        continue;
+
+      copy = ospf6_route_copy (lsentry);
+      copy->type = OSPF6_DEST_TYPE_ROUTER;
+      copy->prefix.family = AF_INET;
+      copy->prefix.prefixlen = 32;
+      ospf6_route_add (copy, oa->ospf6->asbr_table);
+    }
+
+  oa->ospf6->asbr_table->hook_add = hook_add;
+  oa->ospf6->asbr_table->hook_remove = hook_remove;
+
+  for (lsentry = ospf6_route_head (oa->ospf6->asbr_table); lsentry;
+       lsentry = ospf6_route_next (lsentry))
+    {
+      if (lsentry->path.area_id != oa->area_id)
+        continue;
+
+      if (CHECK_FLAG (lsentry->flag, OSPF6_ROUTE_REMOVE) &&
+          CHECK_FLAG (lsentry->flag, OSPF6_ROUTE_ADD))
+        {
+          UNSET_FLAG (lsentry->flag, OSPF6_ROUTE_REMOVE);
+          UNSET_FLAG (lsentry->flag, OSPF6_ROUTE_ADD);
+        }
+
+      if (CHECK_FLAG (lsentry->flag, OSPF6_ROUTE_REMOVE))
+        ospf6_route_remove (lsentry, oa->ospf6->asbr_table);
+      else if (CHECK_FLAG (lsentry->flag, OSPF6_ROUTE_ADD) ||
+               CHECK_FLAG (lsentry->flag, OSPF6_ROUTE_CHANGE))
+        {
+          if (hook_add)
+            (*hook_add) (lsentry);
+        }
+
+      lsentry->flag = 0;
+    }
+
+  if (IS_OSPF6_DEBUG_ASBR)
+    zlog_info ("Intra-area ASBR calculation for area %s: Done", oa->name);
 }
 
 void
 ospf6_intra_init ()
 {
-  ospf6_lsdb_hook[OSPF6_LSA_TYPE_INTRA_PREFIX & OSPF6_LSTYPE_CODE_MASK].hook =
-    ospf6_intra_database_hook_intra_prefix;
-  ospf6_lsdb_hook[OSPF6_LSA_TYPE_LINK & OSPF6_LSTYPE_CODE_MASK].hook = 
-    ospf6_intra_database_hook_link;
+  ospf6_lstype[1].name = "Router";
+  ospf6_lstype[2].name = "Network";
+  ospf6_lstype[8].name = "Link";
+  ospf6_lstype[9].name = "Intra-Prefix";
 
-  intra_index = ospf6_dump_install ("intra-area", "Intra-area calculation\n");
-  ospf6_intra_prefix_register ();
+  ospf6_lstype[1].reoriginate = ospf6_router_lsa_reoriginate;
+  ospf6_lstype[2].reoriginate = ospf6_network_lsa_reoriginate;
+  ospf6_lstype[8].reoriginate = ospf6_link_lsa_reoriginate;
+  ospf6_lstype[9].reoriginate = ospf6_intra_prefix_lsa_reoriginate;
+
+  ospf6_lstype[1].show = ospf6_router_lsa_show;
+  ospf6_lstype[2].show = ospf6_network_lsa_show;
+  ospf6_lstype[8].show = ospf6_link_lsa_show;
+  ospf6_lstype[9].show = ospf6_intra_prefix_lsa_show;
 }
 
 
diff --git a/ospf6d/ospf6_intra.h b/ospf6d/ospf6_intra.h
index 4fb68e9..28780b4 100644
--- a/ospf6d/ospf6_intra.h
+++ b/ospf6d/ospf6_intra.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -22,10 +22,132 @@
 #ifndef OSPF6_INTRA_H
 #define OSPF6_INTRA_H
 
-void ospf6_intra_topology_add (void *);
-void ospf6_intra_topology_remove (void *);
+/* Router-LSA */
+struct ospf6_router_lsa
+{
+  u_char bits;
+  u_char options[3];
+  /* followed by ospf6_router_lsdesc(s) */
+};
+
+/* Link State Description in Router-LSA */
+struct ospf6_router_lsdesc
+{
+  u_char    type;
+  u_char    reserved;
+  u_int16_t metric;                /* output cost */
+  u_int32_t interface_id;
+  u_int32_t neighbor_interface_id;
+  u_int32_t neighbor_router_id;
+};
+
+#define OSPF6_ROUTER_LSDESC_POINTTOPOINT       1
+#define OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK    2
+#define OSPF6_ROUTER_LSDESC_STUB_NETWORK       3
+#define OSPF6_ROUTER_LSDESC_VIRTUAL_LINK       4
+
+#define ROUTER_LSDESC_IS_TYPE(t,x)                         \
+  ((((struct ospf6_router_lsdesc *)(x))->type ==           \
+   OSPF6_ROUTER_LSDESC_ ## t) ? 1 : 0)
+#define ROUTER_LSDESC_GET_METRIC(x)                        \
+  (ntohs (((struct ospf6_router_lsdesc *)(x))->metric))
+#define ROUTER_LSDESC_GET_IFID(x)                          \
+  (ntohl (((struct ospf6_router_lsdesc *)(x))->interface_id))
+#define ROUTER_LSDESC_GET_NBR_IFID(x)                      \
+  (ntohl (((struct ospf6_router_lsdesc *)(x))->neighbor_interface_id))
+#define ROUTER_LSDESC_GET_NBR_ROUTERID(x)                  \
+  (((struct ospf6_router_lsdesc *)(x))->neighbor_router_id)
+
+/* Network-LSA */
+struct ospf6_network_lsa
+{
+  u_char reserved;
+  u_char options[3];
+  /* followed by ospf6_netowrk_lsd(s) */
+};
+
+/* Link State Description in Router-LSA */
+struct ospf6_network_lsdesc
+{
+  u_int32_t router_id;
+};
+#define NETWORK_LSDESC_GET_NBR_ROUTERID(x)                  \
+  (((struct ospf6_network_lsdesc *)(x))->router_id)
+
+/* Link-LSA */
+struct ospf6_link_lsa
+{
+  u_char          priority;
+  u_char          options[3];
+  struct in6_addr linklocal_addr;
+  u_int32_t       prefix_num;
+  /* followed by ospf6 prefix(es) */
+};
+
+/* Intra-Area-Prefix-LSA */
+struct ospf6_intra_prefix_lsa
+{
+  u_int16_t prefix_num;
+  u_int16_t ref_type;
+  u_int32_t ref_id;
+  u_int32_t ref_adv_router;
+  /* followed by ospf6 prefix(es) */
+};
+
+
+#define OSPF6_ROUTER_LSA_SCHEDULE(oa) \
+  do { \
+    if (! (oa)->thread_router_lsa) \
+      (oa)->thread_router_lsa = \
+        thread_add_event (master, ospf6_router_lsa_originate, oa, 0); \
+  } while (0)
+#define OSPF6_NETWORK_LSA_SCHEDULE(oi) \
+  do { \
+    if (! (oi)->thread_network_lsa) \
+      (oi)->thread_network_lsa = \
+        thread_add_event (master, ospf6_network_lsa_originate, oi, 0); \
+  } while (0)
+#define OSPF6_LINK_LSA_SCHEDULE(oi) \
+  do { \
+    if (! (oi)->thread_link_lsa) \
+      (oi)->thread_link_lsa = \
+        thread_add_event (master, ospf6_link_lsa_originate, oi, 0); \
+  } while (0)
+#define OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oa) \
+  do { \
+    if (! (oa)->thread_intra_prefix_lsa) \
+      (oa)->thread_intra_prefix_lsa = \
+        thread_add_event (master, ospf6_intra_prefix_lsa_originate_stub, \
+                          oa, 0); \
+  } while (0)
+#define OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT(oi) \
+  do { \
+    if (! (oi)->thread_intra_prefix_lsa) \
+      (oi)->thread_intra_prefix_lsa = \
+        thread_add_event (master, ospf6_intra_prefix_lsa_originate_transit, \
+                          oi, 0); \
+  } while (0)
+
+/* Function Prototypes */
+char *ospf6_router_lsdesc_lookup (u_char type, u_int32_t interface_id,
+                            u_int32_t neighbor_interface_id,
+                            u_int32_t neighbor_router_id,
+                            struct ospf6_lsa *lsa);
+char *ospf6_network_lsdesc_lookup (u_int32_t router_id,
+                                   struct ospf6_lsa *lsa);
+
+int ospf6_router_lsa_originate (struct thread *);
+int ospf6_network_lsa_originate (struct thread *);
+int ospf6_link_lsa_originate (struct thread *);
+int ospf6_intra_prefix_lsa_originate_transit (struct thread *);
+int ospf6_intra_prefix_lsa_originate_stub (struct thread *);
+void ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa);
+void ospf6_intra_prefix_lsa_remove (struct ospf6_lsa *lsa);
+
+void ospf6_intra_route_calculation (struct ospf6_area *oa);
+void ospf6_intra_asbr_calculation (struct ospf6_area *oa);
 
 void ospf6_intra_init ();
 
-#endif /* OSPF6_INTRA_H */
+#endif /* OSPF6_LSA_H */
 
diff --git a/ospf6d/ospf6_ism.c b/ospf6d/ospf6_ism.c
deleted file mode 100644
index bb14604..0000000
--- a/ospf6d/ospf6_ism.c
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- * Copyright (C) 1999 Yasuhiro Ohara
- *
- * 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.  
- */
-
-/* Interface State Machine */
-
-#include "ospf6d.h"
-
-int
-ifs_change (state_t ifs_next, char *reason, struct ospf6_interface *o6i)
-{
-  state_t ifs_prev;
-
-  ifs_prev = o6i->state;
-
-  if (ifs_prev == ifs_next)
-    return 0;
-
-  if (IS_OSPF6_DUMP_INTERFACE)
-    zlog_info ("I/F: %s: %s -> %s (%s)",
-               o6i->interface->name,
-               ospf6_interface_state_string[ifs_prev],
-               ospf6_interface_state_string[ifs_next], reason);
-
-  if ((ifs_prev == IFS_DR || ifs_prev == IFS_BDR) &&
-      (ifs_next != IFS_DR && ifs_next != IFS_BDR))
-    ospf6_leave_alldrouters (o6i->interface->ifindex);
-  else if ((ifs_prev != IFS_DR && ifs_prev != IFS_BDR) &&
-           (ifs_next == IFS_DR || ifs_next == IFS_BDR))
-    ospf6_join_alldrouters (o6i->interface->ifindex);
-
-  o6i->state = ifs_next;
-
-  if (o6i->prevdr != o6i->dr || o6i->prevbdr != o6i->bdr)
-    {
-      if (IS_OSPF6_DUMP_INTERFACE)
-        {
-          char dr[16], bdr[16], prevdr[16], prevbdr[16];
-          inet_ntop (AF_INET, &o6i->prevdr, prevdr, sizeof (prevdr));
-          inet_ntop (AF_INET, &o6i->prevbdr, prevbdr, sizeof (prevbdr));
-          inet_ntop (AF_INET, &o6i->dr, dr, sizeof (dr));
-          inet_ntop (AF_INET, &o6i->bdr, bdr, sizeof (bdr));
-          zlog_info ("I/F: %s: DR: %s -> %s", o6i->interface->name,
-                     prevdr, dr);
-          zlog_info ("I/F: %s: BDR: %s -> %s", o6i->interface->name,
-                     prevbdr, bdr);
-        }
-    }
-
-  CALL_CHANGE_HOOK (&interface_hook, o6i);
-  return 0;
-}
-
-
-/* Interface State Machine */
-int
-interface_up (struct thread *thread)
-{
-  struct ospf6_interface *ospf6_interface;
-
-  ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread);
-
-  assert (ospf6_interface);
-  assert (ospf6_interface->interface);
-
-  if (IS_OSPF6_DUMP_INTERFACE)
-    zlog_info ("I/F: %s: InterfaceUp",
-               ospf6_interface->interface->name);
-
-  /* check physical interface is up */
-  if (!if_is_up (ospf6_interface->interface))
-    {
-      if (IS_OSPF6_DUMP_INTERFACE)
-        zlog_warn ("  interface %s down, can't execute InterfaceUp",
-                   ospf6_interface->interface->name);
-      return -1;
-    }
-
-  /* if already enabled, do nothing */
-  if (ospf6_interface->state > IFS_DOWN)
-    {
-      zlog_warn ("Interface %s already up",
-                 ospf6_interface->interface->name);
-      return 0;
-    }
-
-  /* ifid of this interface */
-  ospf6_interface->if_id = ospf6_interface->interface->ifindex;
-
-  /* Join AllSPFRouters */
-  ospf6_join_allspfrouters (ospf6_interface->interface->ifindex);
-
-  /* set socket options */
-  ospf6_set_reuseaddr ();
-  ospf6_reset_mcastloop ();
-  ospf6_set_pktinfo ();
-  ospf6_set_checksum ();
-
-  /* Schedule Hello */
-  if (! CHECK_FLAG (ospf6_interface->flag, OSPF6_INTERFACE_FLAG_PASSIVE))
-    thread_add_event (master, ospf6_send_hello, ospf6_interface, 0);
-
-  /* decide next interface state */
-  if (if_is_pointopoint (ospf6_interface->interface))
-    ifs_change (IFS_PTOP, "IF Type PointToPoint", ospf6_interface);
-  else if (ospf6_interface->priority == 0)
-    ifs_change (IFS_DROTHER, "Router Priority = 0", ospf6_interface);
-  else
-    {
-      ifs_change (IFS_WAITING, "Priority > 0", ospf6_interface);
-      thread_add_timer (master, wait_timer, ospf6_interface,
-                        ospf6_interface->dead_interval);
-    }
-
-  CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, ospf6_interface);
-
-  return 0;
-}
-
-int
-wait_timer (struct thread *thread)
-{
-  struct ospf6_interface *ospf6_interface;
-
-  ospf6_interface = (struct ospf6_interface *)THREAD_ARG  (thread);
-  assert (ospf6_interface);
-
-  if (ospf6_interface->state != IFS_WAITING)
-    return 0;
-
-  if (IS_OSPF6_DUMP_INTERFACE)
-    zlog_info ("I/F: %s: WaitTimer", ospf6_interface->interface->name);
-
-  ifs_change (dr_election (ospf6_interface),
-              "WaitTimer:DR Election", ospf6_interface);
-  return 0;
-}
-
-int backup_seen (struct thread *thread)
-{
-  struct ospf6_interface *ospf6_interface;
-
-  ospf6_interface = (struct ospf6_interface *)THREAD_ARG  (thread);
-  assert (ospf6_interface);
-
-  if (IS_OSPF6_DUMP_INTERFACE)
-    zlog_info ("I/F: %s: BackupSeen", ospf6_interface->interface->name);
-
-  if (ospf6_interface->state == IFS_WAITING)
-    ifs_change (dr_election (ospf6_interface),
-                "BackupSeen:DR Election", ospf6_interface);
-
-  return 0;
-}
-
-int neighbor_change (struct thread *thread)
-{
-  struct ospf6_interface *ospf6_interface;
-
-  ospf6_interface = (struct ospf6_interface *)THREAD_ARG  (thread);
-  assert (ospf6_interface);
-
-  if (ospf6_interface->state != IFS_DROTHER &&
-      ospf6_interface->state != IFS_BDR &&
-      ospf6_interface->state != IFS_DR)
-    return 0;
-
-  if (IS_OSPF6_DUMP_INTERFACE)
-    zlog_info ("I/F: %s: NeighborChange", ospf6_interface->interface->name);
-
-  ifs_change (dr_election (ospf6_interface),
-              "NeighborChange:DR Election", ospf6_interface);
-
-  return 0;
-}
-
-int
-loopind (struct thread *thread)
-{
-  struct ospf6_interface *ospf6_interface;
-
-  ospf6_interface = (struct ospf6_interface *)THREAD_ARG (thread);
-  assert (ospf6_interface);
-
-  if (IS_OSPF6_DUMP_INTERFACE)
-    zlog_info ("I/F: %s: LoopInd", ospf6_interface->interface->name);
-
-  /* XXX not yet */
-
-  return 0;
-}
-
-int
-interface_down (struct thread *thread)
-{
-  struct ospf6_interface *ospf6_interface;
-
-  ospf6_interface = (struct ospf6_interface *) THREAD_ARG (thread);
-  assert (ospf6_interface);
-
-  if (IS_OSPF6_DUMP_INTERFACE)
-    zlog_info ("I/F: %s: InterfaceDown", ospf6_interface->interface->name);
-
-  if (ospf6_interface->state == IFS_NONE)
-    return 1;
-
-  /* Leave AllSPFRouters */
-  if (ospf6_interface_is_enabled (ospf6_interface->interface->ifindex))
-    ospf6_leave_allspfrouters (ospf6_interface->interface->ifindex);
-
-  ifs_change (IFS_DOWN, "Configured", ospf6_interface);
-
-  return 0;
-}
-
-
-/* 9.4 of RFC2328 */
-int
-dr_election (struct ospf6_interface *ospf6_interface)
-{
-  list candidate_list = list_new ();
-  listnode i, j, n;
-  ifid_t prevdr, prevbdr, dr = 0, bdr;
-  struct ospf6_neighbor *nbpi, *nbpj, myself, *nbr;
-  int declare = 0;
-  int gofive = 0;
-
-  /* statistics */
-  ospf6_interface->ospf6_stat_dr_election++;
-
-  /* pseudo neighbor "myself" */
-  memset (&myself, 0, sizeof (myself));
-  myself.state = NBS_TWOWAY;
-  myself.dr = ospf6_interface->dr;
-  myself.bdr = ospf6_interface->bdr;
-  myself.priority = ospf6_interface->priority;
-  myself.ifid = ospf6_interface->if_id;
-  myself.router_id = ospf6_interface->area->ospf6->router_id;
-
-/* step_one: */
-
-  ospf6_interface->prevdr = prevdr = ospf6_interface->dr;
-  ospf6_interface->prevbdr = prevbdr = ospf6_interface->bdr;
-
-step_two:
-
-  /* Calculate Backup Designated Router. */
-  /* Make Candidate list */
-  if (!list_isempty (candidate_list))
-    list_delete_all_node (candidate_list);
-  declare = 0;
-  for (i = listhead (ospf6_interface->neighbor_list); i; nextnode (i))
-    {
-      nbpi = (struct ospf6_neighbor *)getdata (i);
-      if (nbpi->priority == 0)
-        continue;
-      if (nbpi->state < NBS_TWOWAY)
-        continue;
-      if (nbpi->dr == nbpi->router_id)
-        continue;
-      if (nbpi->bdr == nbpi->router_id)
-        declare++;
-      listnode_add (candidate_list, nbpi);
-    }
-
-  if (myself.priority)
-    {
-      if (myself.dr != myself.router_id)
-        {
-          if (myself.bdr == myself.router_id)
-            declare++;
-          listnode_add (candidate_list, &myself);
-        }
-    }
-
-  /* Elect BDR */
-  for (i = listhead (candidate_list);
-       candidate_list->count > 1;
-       i = listhead (candidate_list))
-    {
-      j = i;
-      nextnode(j);
-      assert (j);
-      nbpi = (struct ospf6_neighbor *)getdata (i);
-      nbpj = (struct ospf6_neighbor *)getdata (j);
-      if (declare)
-        {
-          int deleted = 0;
-          if (nbpi->bdr != nbpi->router_id)
-            {
-              listnode_delete (candidate_list, nbpi);
-              deleted++;
-            }
-          if (nbpj->bdr != nbpj->router_id)
-            {
-              listnode_delete (candidate_list, nbpj);
-              deleted++;
-            }
-          if (deleted)
-            continue;
-        }
-      if (nbpi->priority > nbpj->priority)
-        {
-          listnode_delete (candidate_list, nbpj);
-          continue;
-        }
-      else if (nbpi->priority < nbpj->priority)
-        {
-          listnode_delete (candidate_list, nbpi);
-          continue;
-        }
-      else /* equal, case of tie */
-        {
-          if (ntohl (nbpi->router_id) > ntohl (nbpj->router_id))
-            {
-              listnode_delete (candidate_list, nbpj);
-              continue;
-            }
-          else if (ntohl (nbpi->router_id) < ntohl (nbpj->router_id))
-            {
-              listnode_delete (candidate_list, nbpi);
-              continue;
-            }
-          else
-            assert (0);
-        }
-    }
-
-  if (!list_isempty (candidate_list))
-    {
-      assert (candidate_list->count == 1);
-      n = listhead (candidate_list);
-      nbr = (struct ospf6_neighbor *)getdata (n);
-      bdr = nbr->router_id;
-    }
-  else
-    bdr = 0;
-
-/* step_three: */
-
-  /* Calculate Designated Router. */
-  /* Make Candidate list */
-  if (!list_isempty (candidate_list))
-    list_delete_all_node (candidate_list);
-  declare = 0;
-  for (i = listhead (ospf6_interface->neighbor_list); i; nextnode (i))
-    {
-      nbpi = (struct ospf6_neighbor *)getdata (i);
-      if (nbpi->priority == 0)
-        continue;
-      if (nbpi->state < NBS_TWOWAY)
-        continue;
-      if (nbpi->dr == nbpi->router_id)
-        {
-          declare++;
-          listnode_add (candidate_list, nbpi);
-        }
-    }
-  if (myself.priority)
-    {
-      if (myself.dr == myself.router_id)
-        {
-          declare++;
-          listnode_add (candidate_list, &myself);
-        }
-    }
-
-  /* Elect DR */
-  if (declare == 0)
-    {
-      assert (list_isempty (candidate_list));
-      /* No one declare but candidate_list not empty */
-      dr = bdr;
-    }
-  else
-    {
-      assert (!list_isempty (candidate_list));
-      for (i = listhead (candidate_list);
-           candidate_list->count > 1;
-           i = listhead (candidate_list))
-        {
-          j = i;
-          nextnode (j);
-          assert (j);
-          nbpi = (struct ospf6_neighbor *)getdata (i);
-          nbpj = (struct ospf6_neighbor *)getdata (j);
-
-          if (nbpi->dr != nbpi->router_id)
-            {
-              list_delete_node (candidate_list, i);
-              continue;
-            }
-          if (nbpj->dr != nbpj->router_id)
-            {
-              list_delete_node (candidate_list, j);
-              continue;
-            }
-
-          if (nbpi->priority > nbpj->priority)
-            {
-              list_delete_node (candidate_list, j);
-              continue;
-            }
-          else if (nbpi->priority < nbpj->priority)
-            {
-              list_delete_node (candidate_list, i);
-              continue;
-            }
-          else /* equal, case of tie */
-            {
-              if (ntohl (nbpi->router_id) > ntohl (nbpj->router_id))
-                {
-                  list_delete_node (candidate_list, j);
-                  continue;
-                }
-              else if (ntohl (nbpi->router_id) < ntohl (nbpj->router_id))
-                {
-                  list_delete_node (candidate_list, i);
-                  continue;
-                }
-              else
-                {
-                  zlog_warn ("!!!THE SAME ROUTER ID FOR DIFFERENT NEIGHBOR");
-                  zlog_warn ("!!!MISCONFIGURATION?");
-                  list_delete_node (candidate_list, i);
-                  continue;
-                }
-            }
-        }
-      if (!list_isempty (candidate_list))
-        {
-          assert (candidate_list->count == 1);
-          n = listhead (candidate_list);
-          nbr = (struct ospf6_neighbor *)getdata (n);
-          dr = nbr->router_id;
-        }
-      else
-        assert (0);
-    }
-
-/* step_four: */
-
-  if (gofive)
-    goto step_five;
-
-  if (dr != prevdr)
-    {
-      if ((dr == myself.router_id || prevdr == myself.router_id)
-          && !(dr == myself.router_id && prevdr == myself.router_id))
-        {
-          myself.dr = dr;
-          myself.bdr = bdr;
-          gofive++;
-          goto step_two;
-        }
-    }
-  if (bdr != prevbdr)
-    {
-      if ((bdr == myself.router_id || prevbdr == myself.router_id)
-          && !(bdr == myself.router_id && prevbdr == myself.router_id))
-        {
-          myself.dr = dr;
-          myself.bdr = bdr;
-          gofive++;
-          goto step_two;
-        }
-    }
-
-step_five:
-
-  ospf6_interface->dr = dr;
-  ospf6_interface->bdr = bdr;
-
-  if (prevdr != dr || prevbdr != bdr)
-    {
-      for (i = listhead (ospf6_interface->neighbor_list); i; nextnode (i))
-        {
-          nbpi = getdata (i);
-          if (nbpi->state < NBS_TWOWAY)
-            continue;
-          /* Schedule or Execute AdjOK. which does "invoke" mean? */
-          thread_add_event (master, adj_ok, nbpi, 0);
-        }
-    }
-
-  list_delete (candidate_list);
-
-  if (dr == myself.router_id)
-    {
-      assert (bdr != myself.router_id);
-      return IFS_DR;
-    }
-  else if (bdr == myself.router_id)
-    {
-      assert (dr != myself.router_id);
-      return IFS_BDR;
-    }
-  else
-    return IFS_DROTHER;
-}
-
-
diff --git a/ospf6d/ospf6_ism.h b/ospf6d/ospf6_ism.h
deleted file mode 100644
index 12470d9..0000000
--- a/ospf6d/ospf6_ism.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 1999 Yasuhiro Ohara
- *
- * 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.  
- */
-
-#ifndef OSPF6_ISM_H
-#define OSPF6_ISM_H
-
-/* interface state */
-#define IFS_NONE     0
-#define IFS_DOWN     1
-#define IFS_LOOPBACK 2
-#define IFS_WAITING  3
-#define IFS_PTOP     4
-#define IFS_DROTHER  5
-#define IFS_BDR      6
-#define IFS_DR       7
-#define IFS_MAX      8
-
-
-
-/* Function Prototypes */
-/* interface event */
-int interface_up (struct thread *);
-int interface_down (struct thread *);
-int wait_timer (struct thread *);
-int backup_seen (struct thread *);
-int neighbor_change (struct thread *);
-
-
-#include "ospf6_types.h"
-
-int dr_change (struct ospf6_interface *);
-int ifs_change (state_t, char *, struct ospf6_interface *);
-
-#endif /* OSPF6_ISM_H */
-
diff --git a/ospf6d/ospf6_linklist.c b/ospf6d/ospf6_linklist.c
deleted file mode 100644
index 8c17935..0000000
--- a/ospf6d/ospf6_linklist.c
+++ /dev/null
@@ -1,193 +0,0 @@
-
-#include <zebra.h>
-
-#include "ospf6_linklist.h"
-
-static struct linklist_node *
-linklist_lookup_node (void *data, struct linklist *linklist)
-{
-  struct linklist_node *node;
-
-  for (node = linklist->head; node; node = node->next)
-    {
-      if (linklist->cmp && (*linklist->cmp) (node->data, data) == 0)
-        return node;
-      if (node->data == data)
-        return node;
-    }
-
-  return NULL;
-}
-
-void *
-linklist_lookup (void *data, struct linklist *linklist)
-{
-  struct linklist_node *node;
-
-  node = linklist_lookup_node (data, linklist);
-  if (node)
-    return node->data;
-  return NULL;
-}
-
-int
-linklist_add (void *data, struct linklist *linklist)
-{
-  struct linklist_node *node = NULL, *add;
-
-  if (linklist_lookup_node (data, linklist))
-    return -1;
-
-  add = malloc (sizeof (struct linklist_node));
-  if (add == NULL)
-    return -1;
-  memset (add, 0, sizeof (struct linklist_node));
-  add->data = data;
-
-  if (linklist->cmp)
-    {
-      for (node = linklist->head; node; node = node->next)
-        {
-          if ((*linklist->cmp) (node->data, add->data) > 0)
-            break;
-        }
-    }
-
-  if (! node)
-    {
-      /* add to tail */
-      if (linklist->tail)
-        {
-          linklist->tail->next = add;
-          add->prev = linklist->tail;
-        }
-      else
-        {
-          linklist->head = add;
-          add->prev = NULL;
-        }
-
-      linklist->tail = add;
-      add->next = NULL;
-    }
-  else
-    {
-      /* insert just before 'node' */
-      if (node->prev)
-        {
-          node->prev->next = add;
-          add->prev = node->prev;
-        }
-      else
-        {
-          linklist->head = add;
-          add->prev = NULL;
-        }
-
-      add->next = node;
-      node->prev = add;
-    }
-
-  linklist->count++;
-  return 0;
-}
-
-int
-linklist_remove (void *data, struct linklist *linklist)
-{
-  struct linklist_node *rem;
-
-  rem = linklist_lookup_node (data, linklist);
-  if (rem == NULL)
-    return -1;
-
-  if (rem->prev)
-    rem->prev->next = rem->next;
-  else
-    linklist->head = rem->next;
-
-  if (rem->next)
-    rem->next->prev = rem->prev;
-  else
-    linklist->tail = rem->prev;
-
-  free (rem);
-  linklist->count--;
-  return 0;
-}
-
-void
-linklist_head (struct linklist *linklist, struct linklist_node *node)
-{
-  if (linklist->head == NULL)
-    {
-      node->prev = NULL;
-      node->next = NULL;
-      node->data = NULL;
-      return;
-    }
-
-  node->prev = linklist->head->prev;
-  node->next = linklist->head->next;
-  node->data = linklist->head->data;
-}
-
-int
-linklist_end (struct linklist_node *node)
-{
-  if (node->data == NULL && node->next == NULL)
-    return 1;
-  return 0;
-}
-
-void
-linklist_next (struct linklist_node *node)
-{
-  if (node->next == NULL)
-    {
-      node->prev = NULL;
-      node->next = NULL;
-      node->data = NULL;
-      return;
-    }
-
-  node->data = node->next->data;
-  node->prev = node->next->prev;
-  node->next = node->next->next;
-}
-
-struct linklist *
-linklist_create ()
-{
-  struct linklist *linklist;
-
-  linklist = malloc (sizeof (struct linklist));
-  if (linklist == NULL)
-    return NULL;
-  memset (linklist, 0, sizeof (struct linklist));
-
-  return linklist;
-}
-
-void
-linklist_remove_all (struct linklist *linklist)
-{
-  struct linklist_node node;
-
-  for (linklist_head (linklist, &node); ! linklist_end (&node);
-       linklist_next (&node))
-    linklist_remove (node.data, linklist);
-}
-
-void
-linklist_delete (struct linklist *linklist)
-{
-  linklist_remove_all (linklist);
-  assert (linklist->count == 0);
-  assert (linklist->head == NULL);
-  assert (linklist->tail == NULL);
-
-  free (linklist);
-}
-
-
diff --git a/ospf6d/ospf6_linklist.h b/ospf6d/ospf6_linklist.h
deleted file mode 100644
index 6d97899..0000000
--- a/ospf6d/ospf6_linklist.h
+++ /dev/null
@@ -1,35 +0,0 @@
-
-#ifndef _LINKLIST_H_
-#define _LINKLIST_H_
-
-struct linklist_node
-{
-  struct linklist_node *prev;
-  struct linklist_node *next;
-
-  void *data;
-};
-
-struct linklist
-{
-  int count;
-  struct linklist_node *head;
-  struct linklist_node *tail;
-
-  int    (*cmp) (void *, void *);
-};
-
-void *linklist_lookup (void *data, struct linklist *linklist);
-int   linklist_add (void *data, struct linklist *linklist);
-int   linklist_remove (void *data, struct linklist *linklist);
-void  linklist_remove_all (struct linklist *linklist);
-
-void linklist_head (struct linklist *linklist, struct linklist_node *node);
-int  linklist_end (struct linklist_node *node);
-void linklist_next (struct linklist_node *node);
-
-struct linklist *linklist_create ();
-void linklist_delete (struct linklist *);
-
-#endif /*_LINKLIST_H_*/
-
diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c
index 712aa68..13e9a07 100644
--- a/ospf6d/ospf6_lsa.c
+++ b/ospf6d/ospf6_lsa.c
@@ -1,6 +1,5 @@
 /*
- * LSA function
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -23,73 +22,56 @@
 #include <zebra.h>
 
 /* Include other stuffs */
-#include <lib/version.h>
 #include "log.h"
-#include "getopt.h"
 #include "linklist.h"
-#include "thread.h"
 #include "command.h"
 #include "memory.h"
-#include "sockunion.h"
-#include "if.h"
-#include "prefix.h"
-#include "stream.h"
 #include "thread.h"
-#include "filter.h"
-#include "zclient.h"
-#include "table.h"
-#include "plist.h"
 
+#include "ospf6d.h"
 #include "ospf6_proto.h"
-#include "ospf6_prefix.h"
 #include "ospf6_lsa.h"
 #include "ospf6_lsdb.h"
 #include "ospf6_message.h"
-#include "ospf6_dump.h"
 
 #include "ospf6_top.h"
 #include "ospf6_area.h"
 #include "ospf6_interface.h"
 #include "ospf6_neighbor.h"
-#include "ospf6_ism.h"
-#include "ospf6_nsm.h"
-#include "ospf6_dbex.h"
 
-#define HEADER_DEPENDENCY
-#include "ospf6d.h"
-#undef HEADER_DEPENDENCY
+#include "ospf6_flood.h"
 
-/* test LSAs identity */
-static int
-ospf6_lsa_issame (struct ospf6_lsa_header__ *lsh1,
-                  struct ospf6_lsa_header__ *lsh2)
+unsigned char conf_debug_ospf6_lsa = 0;
+
+struct ospf6_lstype ospf6_lstype[OSPF6_LSTYPE_SIZE];
+
+char *ospf6_lstype_str[OSPF6_LSTYPE_SIZE] =
+  {"Unknown", "Router", "Network", "Inter-Prefix", "Inter-Router",
+   "AS-External", "Group-Membership", "Type-7", "Link", "Intra-Prefix"};
+
+char *
+ospf6_lstype_name (u_int16_t type)
 {
-  assert (lsh1 && lsh2);
+  static char buf[8];
+  int index = ntohs (type) & OSPF6_LSTYPE_FCODE_MASK;
 
-  if (lsh1->adv_router != lsh2->adv_router)
-    return 0;
+  if (index < OSPF6_LSTYPE_SIZE && ospf6_lstype_str[index])
+    return ospf6_lstype_str[index];
 
-  if (lsh1->id != lsh2->id)
-    return 0;
-
-  if (lsh1->type != lsh2->type)
-    return 0;
-
-  return 1;
+  snprintf (buf, sizeof (buf), "0x%04hx", ntohs (type));
+  return buf;
 }
 
 /* RFC2328: Section 13.2 */
 int
-ospf6_lsa_differ (struct ospf6_lsa *lsa1,
-                  struct ospf6_lsa *lsa2)
+ospf6_lsa_is_differ (struct ospf6_lsa *lsa1,
+                     struct ospf6_lsa *lsa2)
 {
-  int diff, cmplen;
+  int len;
 
-  if (! ospf6_lsa_issame (lsa1->header, lsa2->header))
-    return 1;
+  assert (OSPF6_LSA_IS_SAME (lsa1, lsa2));
 
-  /* check Options field */
-  /* xxx */
+  /* XXX, Options ??? */
 
   ospf6_lsa_age_current (lsa1);
   ospf6_lsa_age_current (lsa2);
@@ -104,26 +86,26 @@
   if (ntohs (lsa1->header->length) != ntohs (lsa2->header->length))
     return 1;
 
-  cmplen = ntohs (lsa1->header->length) - sizeof (struct ospf6_lsa_header);
-  diff = memcmp (lsa1->header + 1, lsa2->header + 1, cmplen);
-
-  return diff;
+  len = ntohs (lsa1->header->length) - sizeof (struct ospf6_lsa_header);
+  return memcmp (lsa1->header + 1, lsa2->header + 1, len);
 }
 
 int
-ospf6_lsa_match (u_int16_t type, u_int32_t id, u_int32_t adv_router,
-                 struct ospf6_lsa_header *lsh)
+ospf6_lsa_is_changed (struct ospf6_lsa *lsa1,
+                      struct ospf6_lsa *lsa2)
 {
-  if (lsh->advrtr != adv_router)
-    return 0;
+  int length;
 
-  if (lsh->ls_id != id)
-    return 0;
+  if (OSPF6_LSA_IS_MAXAGE (lsa1) ^ OSPF6_LSA_IS_MAXAGE (lsa2))
+    return 1;
+  if (ntohs (lsa1->header->length) != ntohs (lsa2->header->length))
+    return 1;
 
-  if (lsh->type != type)
-    return 0;
+  length = OSPF6_LSA_SIZE (lsa1->header) - sizeof (struct ospf6_lsa_header);
+  assert (length > 0);
 
-  return 1;
+  return memcmp (OSPF6_LSA_HEADER_END (lsa1->header),
+                 OSPF6_LSA_HEADER_END (lsa2->header), length);
 }
 
 /* ospf6 age functions */
@@ -143,7 +125,8 @@
   lsa->birth.tv_usec = now.tv_usec;
   if (ntohs (lsa->header->age) != MAXAGE)
     lsa->expire = thread_add_timer (master, ospf6_lsa_expire, lsa,
-                                    lsa->birth.tv_sec + MAXAGE - now.tv_sec);
+                                    MAXAGE + lsa->birth.tv_sec
+                                    - now.tv_sec);
   else
     lsa->expire = NULL;
   return;
@@ -163,17 +146,14 @@
 
   /* current time */
   if (gettimeofday (&now, (struct timezone *)NULL) < 0)
-    zlog_warn ("LSA: gettimeofday failed, may fail ages: %s",
+    zlog_warn ("LSA: gettimeofday failed, may fail LSA AGEs: %s",
                strerror (errno));
 
   /* calculate age */
   ulage = now.tv_sec - lsa->birth.tv_sec;
 
   /* if over MAXAGE, set to it */
-  if (ulage > MAXAGE)
-    age = MAXAGE;
-  else
-    age = ulage;
+  age = (ulage > MAXAGE ? MAXAGE : ulage);
 
   lsa->header->age = htons (age);
   return age;
@@ -189,22 +169,17 @@
   if (age > MAXAGE)
     age = MAXAGE;
   lsa->header->age = htons (age);
-  return;
 }
 
 void
 ospf6_lsa_premature_aging (struct ospf6_lsa *lsa)
 {
   /* log */
-  if (IS_OSPF6_DUMP_LSA)
-    zlog_info ("LSA: Premature aging: %s", lsa->str);
+  if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+    zlog_info ("LSA: Premature aging: %s", lsa->name);
 
-  if (lsa->expire)
-    thread_cancel (lsa->expire);
-  lsa->expire = (struct thread *) NULL;
-  if (lsa->refresh)
-    thread_cancel (lsa->refresh);
-  lsa->refresh = (struct thread *) NULL;
+  THREAD_OFF (lsa->expire);
+  THREAD_OFF (lsa->refresh);
 
   memset (&lsa->birth, 0, sizeof (struct timeval));
   thread_execute (master, ospf6_lsa_expire, lsa, 0);
@@ -213,7 +188,7 @@
 /* check which is more recent. if a is more recent, return -1;
    if the same, return 0; otherwise(b is more recent), return 1 */
 int
-ospf6_lsa_check_recent (struct ospf6_lsa *a, struct ospf6_lsa *b)
+ospf6_lsa_compare (struct ospf6_lsa *a, struct ospf6_lsa *b)
 {
   signed long seqnuma, seqnumb;
   u_int16_t cksuma, cksumb;
@@ -221,7 +196,7 @@
 
   assert (a && a->header);
   assert (b && b->header);
-  assert (ospf6_lsa_issame (a->header, b->header));
+  assert (OSPF6_LSA_IS_SAME (a, b));
 
   seqnuma = ((signed long) ntohl (a->header->seqnum))
              - (signed long) INITIAL_SEQUENCE_NUMBER;
@@ -229,8 +204,7 @@
              - (signed long) INITIAL_SEQUENCE_NUMBER;
 
   /* compare by sequence number */
-    /* xxx, care about LS sequence number wrapping */
-  recent_reason = "seqnum";
+  /* XXX, LS sequence number wrapping */
   if (seqnuma > seqnumb)
     return -1;
   else if (seqnuma < seqnumb)
@@ -244,188 +218,89 @@
   if (cksuma < cksumb)
     return 0;
 
-  /* Age check */
+  /* Update Age */
   agea = ospf6_lsa_age_current (a);
   ageb = ospf6_lsa_age_current (b);
 
-    /* MaxAge check */
-  recent_reason = "max age";
-  if (agea == OSPF6_LSA_MAXAGE && ageb != OSPF6_LSA_MAXAGE)
+  /* MaxAge check */
+  if (agea == MAXAGE && ageb != MAXAGE)
     return -1;
-  else if (agea != OSPF6_LSA_MAXAGE && ageb == OSPF6_LSA_MAXAGE)
+  else if (agea != MAXAGE && ageb == MAXAGE)
     return 1;
 
-  recent_reason = "age differ";
-  if (agea > ageb && agea - ageb >= OSPF6_LSA_MAXAGEDIFF)
+  /* Age check */
+  if (agea > ageb && agea - ageb >= MAX_AGE_DIFF)
     return 1;
-  else if (agea < ageb && ageb - agea >= OSPF6_LSA_MAXAGEDIFF)
+  else if (agea < ageb && ageb - agea >= MAX_AGE_DIFF)
     return -1;
 
   /* neither recent */
-  recent_reason = "the same instance";
   return 0;
 }
 
-int
-ospf6_lsa_lsd_num (struct ospf6_lsa_header *lsa_header)
+char *
+ospf6_lsa_printbuf (struct ospf6_lsa *lsa, char *buf, int size)
 {
-  int ldnum = 0;
-  u_int16_t len;
-
-  len = ntohs (lsa_header->length);
-  len -= sizeof (struct ospf6_lsa_header);
-  if (lsa_header->type == htons (OSPF6_LSA_TYPE_ROUTER))
-    {
-      len -= sizeof (struct ospf6_router_lsa);
-      ldnum = len / sizeof (struct ospf6_router_lsd);
-    }
-  else /* (lsa_header->type == htons (OSPF6_LSA_TYPE_NETWORK)) */
-    {
-      len -= sizeof (struct ospf6_network_lsa);
-      ldnum = len / sizeof (u_int32_t);
-    }
-
-  return ldnum;
+  char id[16], adv_router[16];
+  inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id));
+  inet_ntop (AF_INET, &lsa->header->adv_router, adv_router,
+             sizeof (adv_router));
+  snprintf (buf, size, "[%s Id:%s Adv:%s]",
+            OSPF6_LSTYPE_NAME (lsa->header->type), id, adv_router);
+  return buf;
 }
 
-void *
-ospf6_lsa_lsd_get (int index, struct ospf6_lsa_header *lsa_header)
+void
+ospf6_lsa_header_print_raw (struct ospf6_lsa_header *header)
 {
-  void *p;
-  struct ospf6_router_lsa *router_lsa;
-  struct ospf6_router_lsd *router_lsd;
-  struct ospf6_network_lsa *network_lsa;
-  struct ospf6_network_lsd *network_lsd;
-
-  if (lsa_header->type == htons (OSPF6_LSA_TYPE_ROUTER))
-    {
-      router_lsa = (struct ospf6_router_lsa *) (lsa_header + 1);
-      router_lsd = (struct ospf6_router_lsd *) (router_lsa + 1);
-      router_lsd += index;
-      p = (void *) router_lsd;
-    }
-  else if (lsa_header->type == htons (OSPF6_LSA_TYPE_NETWORK))
-    {
-      network_lsa = (struct ospf6_network_lsa *) (lsa_header + 1);
-      network_lsd = (struct ospf6_network_lsd *) (network_lsa + 1);
-      network_lsd += index;
-      p = (void *) network_lsd;
-    }
-  else
-    {
-      p = (void *) NULL;
-    }
-
-  return p;
+  char id[16], adv_router[16];
+  inet_ntop (AF_INET, &header->id, id, sizeof (id));
+  inet_ntop (AF_INET, &header->adv_router, adv_router,
+             sizeof (adv_router));
+  zlog_info ("    [%s Id:%s Adv:%s]",
+             OSPF6_LSTYPE_NAME (header->type), id, adv_router);
+  zlog_info ("    Age: %4hu SeqNum: %#08lx Cksum: %04hx Len: %d",
+             ntohs (header->age), (u_long) ntohl (header->seqnum),
+             ntohs (header->checksum), ntohs (header->length));
 }
 
-/* network_lsd <-> router_lsd */
-static int
-ospf6_lsa_lsd_network_reference_match (struct ospf6_network_lsd *network_lsd1,
-                                       struct ospf6_lsa_header *lsa_header1,
-                                       struct ospf6_router_lsd *router_lsd2,
-                                       struct ospf6_lsa_header *lsa_header2)
+void
+ospf6_lsa_header_print (struct ospf6_lsa *lsa)
 {
-  if (network_lsd1->adv_router != lsa_header2->advrtr)
-    return 0;
-  if (router_lsd2->type != OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK)
-    return 0;
-  if (router_lsd2->neighbor_router_id != lsa_header1->advrtr)
-    return 0;
-  if (router_lsd2->neighbor_interface_id != lsa_header1->ls_id)
-    return 0;
-  return 1;
-}
-
-/* router_lsd <-> router_lsd */
-static int
-ospf6_lsa_lsd_router_reference_match (struct ospf6_router_lsd *router_lsd1,
-                                      struct ospf6_lsa_header *lsa_header1,
-                                      struct ospf6_router_lsd *router_lsd2,
-                                      struct ospf6_lsa_header *lsa_header2)
-{
-  if (router_lsd1->type != OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT)
-    return 0;
-  if (router_lsd2->type != OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT)
-    return 0;
-  if (router_lsd1->neighbor_router_id != lsa_header2->advrtr)
-    return 0;
-  if (router_lsd2->neighbor_router_id != lsa_header1->advrtr)
-    return 0;
-  if (router_lsd1->neighbor_interface_id != router_lsd2->interface_id)
-    return 0;
-  if (router_lsd2->neighbor_interface_id != router_lsd1->interface_id)
-    return 0;
-  return 1;
-}
-
-int
-ospf6_lsa_lsd_is_refer_ok (int index1, struct ospf6_lsa_header *lsa_header1,
-                           int index2, struct ospf6_lsa_header *lsa_header2)
-{
-  struct ospf6_router_lsd *r1, *r2;
-  struct ospf6_network_lsd *n;
-
-  r1 = (struct ospf6_router_lsd *) NULL;
-  r2 = (struct ospf6_router_lsd *) NULL;
-  n = (struct ospf6_network_lsd *) NULL;
-  if (lsa_header1->type == htons (OSPF6_LSA_TYPE_ROUTER))
-    r1 = (struct ospf6_router_lsd *) ospf6_lsa_lsd_get (index1, lsa_header1);
-  else
-    n = (struct ospf6_network_lsd *) ospf6_lsa_lsd_get (index1, lsa_header1);
-
-  if (lsa_header2->type == htons (OSPF6_LSA_TYPE_ROUTER))
-    r2 = (struct ospf6_router_lsd *) ospf6_lsa_lsd_get (index2, lsa_header2);
-  else
-    n = (struct ospf6_network_lsd *) ospf6_lsa_lsd_get (index2, lsa_header2);
-
-  if (r1 && r2)
-    return ospf6_lsa_lsd_router_reference_match (r1, lsa_header1,
-                                                 r2, lsa_header2);
-  else if (r1 && n)
-    return ospf6_lsa_lsd_network_reference_match (n, lsa_header2,
-                                                  r1, lsa_header1);
-  else if (n && r2)
-    return ospf6_lsa_lsd_network_reference_match (n, lsa_header1,
-                                                 r2, lsa_header2);
-  return 0;
+  ospf6_lsa_age_current (lsa);
+  ospf6_lsa_header_print_raw (lsa->header);
 }
 
 void
 ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
 {
-  char adv_router[64], id[64], type[32];
+  char adv_router[64], id[64];
+  int index;
 
-  assert (lsa);
-  assert (lsa->header);
+  assert (lsa && lsa->header);
 
-  ospf6_lsa_type_string (lsa->header->type, type, sizeof (type));
   inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id));
   inet_ntop (AF_INET, &lsa->header->adv_router,
              adv_router, sizeof (adv_router));
 
   vty_out (vty, "%s", VTY_NEWLINE);
   vty_out (vty, "Age: %4hu Type: %s%s", ospf6_lsa_age_current (lsa),
-           type, VTY_NEWLINE);
+           OSPF6_LSTYPE_NAME (lsa->header->type), VTY_NEWLINE);
   vty_out (vty, "Link State ID: %s%s", id, VTY_NEWLINE);
   vty_out (vty, "Advertising Router: %s%s", adv_router, VTY_NEWLINE);
-  vty_out (vty, "LS Sequence Number: %#lx%s", (u_long)ntohl (lsa->header->seqnum),
-           VTY_NEWLINE);
-  vty_out (vty, "CheckSum: %#hx Length: %hu%s", ntohs (lsa->header->checksum),
+  vty_out (vty, "LS Sequence Number: %#010lx%s",
+           (u_long) ntohl (lsa->header->seqnum), VTY_NEWLINE);
+  vty_out (vty, "CheckSum: %#06hx Length: %hu%s",
+           ntohs (lsa->header->checksum),
            ntohs (lsa->header->length), VTY_NEWLINE);
 
-  {
-    struct ospf6_lsa_slot *slot;
-    slot = ospf6_lsa_slot_get (lsa->header->type);
-    if (slot)
-      {
-        (*slot->func_show) (vty, lsa);
-        vty_out (vty, "%s", VTY_NEWLINE);
-        return;
-      }
-  }
+  index = OSPF6_LSTYPE_INDEX (ntohs (lsa->header->type));
+  if (ospf6_lstype[index].show)
+    (*ospf6_lstype[index].show) (vty, lsa);
+  else
+    vty_out (vty, "%sUnknown LSA type ...%s", VTY_NEWLINE, VTY_NEWLINE);
 
-  vty_out (vty, "%sUnknown LSA type ...%s", VTY_NEWLINE, VTY_NEWLINE);
+  vty_out (vty, "%s", VTY_NEWLINE);
 }
 
 void
@@ -439,25 +314,24 @@
 void
 ospf6_lsa_show_summary (struct vty *vty, struct ospf6_lsa *lsa)
 {
-  char adv_router[16], id[16], type[16];
+  char adv_router[16], id[16];
   struct timeval now, res;
   char duration[16];
 
   assert (lsa);
   assert (lsa->header);
 
-  memset (type, 0, sizeof (type));
-  ospf6_lsa_type_string (lsa->header->type, type, 13);
   inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id));
   inet_ntop (AF_INET, &lsa->header->adv_router, adv_router,
              sizeof (adv_router));
 
   gettimeofday (&now, NULL);
-  ospf6_timeval_sub (&now, &lsa->installed, &res);
-  ospf6_timeval_string_summary (&res, duration, sizeof (duration));
+  timersub (&now, &lsa->installed, &res);
+  timerstring (&res, duration, sizeof (duration));
 
   vty_out (vty, "%-12s %-15s %-15s %4hu %8lx %04hx %4hu %8s%s",
-           type, id, adv_router, ospf6_lsa_age_current (lsa),
+           OSPF6_LSTYPE_NAME (lsa->header->type),
+           id, adv_router, ospf6_lsa_age_current (lsa),
            (u_long) ntohl (lsa->header->seqnum),
            ntohs (lsa->header->checksum), ntohs (lsa->header->length),
            duration, VTY_NEWLINE);
@@ -473,7 +347,7 @@
   end = (char *) lsa->header + ntohs (lsa->header->length);
 
   vty_out (vty, "%s", VTY_NEWLINE);
-  vty_out (vty, "%s:%s", lsa->str, VTY_NEWLINE);
+  vty_out (vty, "%s:%s", lsa->name, VTY_NEWLINE);
 
   for (current = start; current < end; current ++)
     {
@@ -489,149 +363,136 @@
   vty_out (vty, "%s%s", VTY_NEWLINE, VTY_NEWLINE);
 }
 
+void
+ospf6_lsa_show_internal (struct vty *vty, struct ospf6_lsa *lsa)
+{
+  char adv_router[64], id[64];
+
+  assert (lsa && lsa->header);
+
+  inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id));
+  inet_ntop (AF_INET, &lsa->header->adv_router,
+             adv_router, sizeof (adv_router));
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+  vty_out (vty, "Age: %4hu Type: %s%s", ospf6_lsa_age_current (lsa),
+           OSPF6_LSTYPE_NAME (lsa->header->type), VTY_NEWLINE);
+  vty_out (vty, "Link State ID: %s%s", id, VTY_NEWLINE);
+  vty_out (vty, "Advertising Router: %s%s", adv_router, VTY_NEWLINE);
+  vty_out (vty, "LS Sequence Number: %#010lx%s",
+           (u_long) ntohl (lsa->header->seqnum), VTY_NEWLINE);
+  vty_out (vty, "CheckSum: %#06hx Length: %hu%s",
+           ntohs (lsa->header->checksum),
+           ntohs (lsa->header->length), VTY_NEWLINE);
+  vty_out (vty, "    Prev: %p This: %p Next: %p%s",
+           lsa->prev, lsa, lsa->next, VTY_NEWLINE);
+  vty_out (vty, "    Reference count: %ld%s", lsa->refcnt, VTY_NEWLINE);
+  vty_out (vty, "    Reference source: %s (%p) %s",
+           (lsa->refsrc ? lsa->refsrc->name : "None"),
+           lsa->refsrc, VTY_NEWLINE);
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
 /* OSPFv3 LSA creation/deletion function */
 
 /* calculate LS sequence number for my new LSA.
    return value is network byte order */
-static signed long
-ospf6_lsa_seqnum_new (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+u_int32_t
+ospf6_lsa_new_seqnum (u_int16_t type, u_int32_t id, u_int32_t adv_router,
                       void *scope)
 {
+  struct ospf6_lsdb *lsdb = NULL;
   struct ospf6_lsa *lsa;
-  signed long seqnum;
+  signed long seqnum = 0;
 
   /* get current database copy */
-  lsa = ospf6_lsdb_lookup (type, id, adv_router, scope);
+  lsdb = ospf6_get_scoped_lsdb (type, scope);
+  if (lsdb == NULL)
+    {
+      zlog_warn ("Can't decide scoped LSDB");
+      return ((u_int32_t) htonl (INITIAL_SEQUENCE_NUMBER));
+    }
 
   /* if current database copy not found, return InitialSequenceNumber */
-  if (!lsa)
+  lsa = ospf6_lsdb_lookup (type, id, adv_router, lsdb);
+  if (lsa == NULL)
     seqnum = INITIAL_SEQUENCE_NUMBER;
   else
     seqnum = (signed long) ntohl (lsa->header->seqnum) + 1;
 
-  return (htonl (seqnum));
+  return ((u_int32_t) htonl (seqnum));
 }
 
-#if 0
-static void
-ospf6_lsa_header_set (u_int16_t type, u_int32_t ls_id, u_int32_t advrtr,
-                      struct ospf6_lsa_header *lsa_header, int bodysize)
-{
-  /* fill LSA header */
-  lsa_header->age = 0;
-  lsa_header->type = type;
-  lsa_header->ls_id = ls_id;
-  lsa_header->advrtr = advrtr;
-  lsa_header->seqnum =
-    ospf6_lsa_seqnum_new (lsa_header->type, lsa_header->ls_id,
-                          lsa_header->advrtr);
-  lsa_header->length = htons (sizeof (struct ospf6_lsa_header) + bodysize);
-
-  /* LSA checksum */
-  ospf6_lsa_checksum (lsa_header);
-}
-#endif /*0*/
-
 struct ospf6_lsa *
-ospf6_lsa_create (struct ospf6_lsa_header *source)
+ospf6_lsa_create (struct ospf6_lsa_header *header)
 {
   struct ospf6_lsa *lsa = NULL;
-  struct ospf6_lsa_header *lsa_header = NULL;
+  struct ospf6_lsa_header *new_header = NULL;
   u_int16_t lsa_size = 0;
-  char buf_router[16], buf_id[16], typebuf[32];
 
-  /* whole length of this LSA */
-  lsa_size = ntohs (source->length);
+  /* size of the entire LSA */
+  lsa_size = ntohs (header->length);   /* XXX vulnerable */
 
   /* allocate memory for this LSA */
-  lsa_header = (struct ospf6_lsa_header *)
+  new_header = (struct ospf6_lsa_header *)
     XMALLOC (MTYPE_OSPF6_LSA, lsa_size);
-  if (! lsa_header)
-    {
-      zlog_err ("Can't allocate memory for LSA Header");
-      return (struct ospf6_lsa *) NULL;
-    }
-  memset (lsa_header, 0, lsa_size);
 
-  /* copy LSA from source */
-  memcpy (lsa_header, source, lsa_size);
+  /* copy LSA from original header */
+  memcpy (new_header, header, lsa_size);
 
   /* LSA information structure */
   /* allocate memory */
   lsa = (struct ospf6_lsa *)
-          XMALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa));
+    XMALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa));
   memset (lsa, 0, sizeof (struct ospf6_lsa));
 
-  lsa->lsa_hdr = (struct ospf6_lsa_hdr *) lsa_header;
-  lsa->header = (struct ospf6_lsa_header__ *) lsa_header;
-
-  lsa->summary = 0; /* this is not LSA summary */
+  lsa->header = (struct ospf6_lsa_header *) new_header;
+  lsa->headeronly = 0; /* this is not header only */
 
   /* dump string */
-  inet_ntop (AF_INET, &lsa->header->id, buf_id, sizeof (buf_id));
-  inet_ntop (AF_INET, &lsa->header->adv_router, buf_router,
-             sizeof (buf_router));
-  snprintf (lsa->str, sizeof (lsa->str), "[%s ID=%s Adv=%s]",
-            ospf6_lsa_type_string (lsa_header->type, typebuf,
-                                   sizeof (typebuf)),
-            buf_id, buf_router);
+  ospf6_lsa_printbuf (lsa, lsa->name, sizeof (lsa->name));
 
   /* calculate birth, expire and refresh of this lsa */
   ospf6_lsa_age_set (lsa);
 
-#ifdef DEBUG
-  if (IS_OSPF6_DUMP_LSA)
-    zlog_info ("Create: %s (%p/%p)", lsa->str, lsa, lsa->header);
-#endif /*DEBUG*/
+  if (IS_OSPF6_DEBUG_LSA (MEMORY))
+    zlog_info ("Create LSA Memory: %s (%p/%p)",
+               lsa->name, lsa, lsa->header);
 
   return lsa;
 }
 
 struct ospf6_lsa *
-ospf6_lsa_summary_create (struct ospf6_lsa_header__ *source)
+ospf6_lsa_create_headeronly (struct ospf6_lsa_header *header)
 {
   struct ospf6_lsa *lsa = NULL;
-  struct ospf6_lsa_header *lsa_header = NULL;
-  u_int16_t lsa_size = 0;
-  char buf_router[16], buf_id[16], typebuf[16];
-
-  /* LSA summary contains LSA Header only */
-  lsa_size = sizeof (struct ospf6_lsa_header);
+  struct ospf6_lsa_header *new_header = NULL;
 
   /* allocate memory for this LSA */
-  lsa_header = (struct ospf6_lsa_header *)
-    XMALLOC (MTYPE_OSPF6_LSA_SUMMARY, lsa_size);
-  memset (lsa_header, 0, lsa_size);
+  new_header = (struct ospf6_lsa_header *)
+    XMALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa_header));
 
-  /* copy LSA from source */
-  memcpy (lsa_header, source, lsa_size);
+  /* copy LSA from original header */
+  memcpy (new_header, header, sizeof (struct ospf6_lsa_header));
 
   /* LSA information structure */
   /* allocate memory */
   lsa = (struct ospf6_lsa *)
-          XMALLOC (MTYPE_OSPF6_LSA_SUMMARY, sizeof (struct ospf6_lsa));
+    XMALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa));
   memset (lsa, 0, sizeof (struct ospf6_lsa));
 
-  lsa->lsa_hdr = (struct ospf6_lsa_hdr *) lsa_header;
-  lsa->header = (struct ospf6_lsa_header__ *) lsa_header;
-  lsa->summary = 1; /* this is LSA summary */
+  lsa->header = (struct ospf6_lsa_header *) new_header;
+  lsa->headeronly = 1; /* this is header only */
 
   /* dump string */
-  inet_ntop (AF_INET, &lsa->header->id, buf_id, sizeof (buf_id));
-  inet_ntop (AF_INET, &lsa->header->adv_router, buf_router,
-             sizeof (buf_router));
-  snprintf (lsa->str, sizeof (lsa->str), "[%s Summary ID=%s Adv=%s]",
-            ospf6_lsa_type_string (lsa->header->type, typebuf,
-                                   sizeof (typebuf)),
-            buf_id, buf_router);
+  ospf6_lsa_printbuf (lsa, lsa->name, sizeof (lsa->name));
 
   /* calculate birth, expire and refresh of this lsa */
   ospf6_lsa_age_set (lsa);
 
-#ifdef DEBUG
-  if (IS_OSPF6_DUMP_LSA)
-    zlog_info ("Create: %s (%p/%p)", lsa->str, lsa, lsa->header);
-#endif /*DEBUG*/
+  if (IS_OSPF6_DEBUG_LSA (MEMORY))
+    zlog_info ("Create LSA (Header-only) Memory: %s (%p/%p)",
+               lsa->name, lsa, lsa->header);
 
   return lsa;
 }
@@ -639,40 +500,48 @@
 void
 ospf6_lsa_delete (struct ospf6_lsa *lsa)
 {
-  /* just to make sure */
-  if (lsa->lock != 0)
-    {
-      zlog_err ("Can't delete %s: lock: %ld", lsa->str, lsa->lock);
-      return;
-    }
+  assert (lsa->lock == 0);
 
   /* cancel threads */
-  if (lsa->expire)
-    thread_cancel (lsa->expire);
-  lsa->expire = (struct thread *) NULL;
-  if (lsa->refresh)
-    thread_cancel (lsa->refresh);
-  lsa->refresh = (struct thread *) NULL;
+  THREAD_OFF (lsa->expire);
+  THREAD_OFF (lsa->refresh);
 
-#ifdef DEBUG
-  if (IS_OSPF6_DUMP_LSA)
-      zlog_info ("Delete %s (%p/%p)", lsa->str, lsa, lsa->header);
-#endif /*DEBUG*/
+  if (IS_OSPF6_DEBUG_LSA (MEMORY))
+    zlog_info ("Delete LSA %s Memory: %s (%p/%p)",
+               (lsa->headeronly ? "(Header-only) " : ""),
+               lsa->name, lsa, lsa->header);
 
   /* do free */
-  if (lsa->summary)
-    XFREE (MTYPE_OSPF6_LSA_SUMMARY, lsa->header);
-  else
-    XFREE (MTYPE_OSPF6_LSA, lsa->header);
-  lsa->header = NULL;
-
-  if (lsa->summary)
-    XFREE (MTYPE_OSPF6_LSA_SUMMARY, lsa);
-  else
-    XFREE (MTYPE_OSPF6_LSA, lsa);
+  XFREE (MTYPE_OSPF6_LSA, lsa->header);
+  XFREE (MTYPE_OSPF6_LSA, lsa);
 }
 
-/* increment reference counter of  struct ospf6_lsa */
+struct ospf6_lsa *
+ospf6_lsa_copy (struct ospf6_lsa *lsa)
+{
+  struct ospf6_lsa *copy = NULL;
+
+  if (IS_OSPF6_DEBUG_LSA (MEMORY))
+    zlog_info ("Create LSA Copy from %s", lsa->name);
+
+  ospf6_lsa_age_current (lsa);
+  if (lsa->headeronly)
+    copy = ospf6_lsa_create_headeronly (lsa->header);
+  else
+    copy = ospf6_lsa_create (lsa->header);
+  assert (copy->lock == 0);
+
+  copy->installed = lsa->installed;
+  copy->originated = lsa->originated;
+  copy->scope = lsa->scope;
+
+  copy->refsrc = lsa;
+  copy->refsrc->refcnt++;
+
+  return copy;
+}
+
+/* increment reference counter of struct ospf6_lsa */
 void
 ospf6_lsa_lock (struct ospf6_lsa *lsa)
 {
@@ -680,163 +549,156 @@
   return;
 }
 
-/* decrement reference counter of  struct ospf6_lsa */
+/* decrement reference counter of struct ospf6_lsa */
 void
 ospf6_lsa_unlock (struct ospf6_lsa *lsa)
 {
   /* decrement reference counter */
-  if (lsa->lock > 0)
-    lsa->lock--;
-  else
-    zlog_warn ("Can't unlock %s: already no lock", lsa->str);
+  assert (lsa->lock > 0);
+  lsa->lock--;
 
-  if (lsa->lock == 0)
-    ospf6_lsa_delete (lsa);
+  if (lsa->lock != 0)
+    return;
+
+  if (lsa->refsrc)
+    lsa->refsrc->refcnt--;
+
+  ospf6_lsa_delete (lsa);
 }
 
 void
-ospf6_lsa_originate (u_int16_t type, u_int32_t id, u_int32_t adv_router,
-                     char *data, int data_len, void *scope)
+ospf6_lsa_originate (struct ospf6_lsa *lsa)
 {
-  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));
-
-  lsa_header = (struct ospf6_lsa_header *) buffer;
-
-  /* Copy LSA Body */
-  memcpy (buffer + sizeof (struct ospf6_lsa_header), data, data_len);
-
-  /* Fill LSA Header */
-  lsa_header->age = 0;
-  lsa_header->type = type;
-  lsa_header->ls_id = id;
-  lsa_header->advrtr = adv_router;
-  lsa_header->seqnum =
-    ospf6_lsa_seqnum_new (lsa_header->type, lsa_header->ls_id,
-                          lsa_header->advrtr, scope);
-  lsa_header->length = htons (sizeof (struct ospf6_lsa_header) + data_len);
-
-  /* LSA checksum */
-  ospf6_lsa_checksum (lsa_header);
-
-  /* create LSA */
-  lsa = ospf6_lsa_create ((struct ospf6_lsa_header *) buffer);
-  lsa->scope = scope;
+  struct ospf6_lsdb *lsdb = NULL;
 
   /* find previous LSA */
+  lsdb = ospf6_get_scoped_lsdb (lsa->header->type, lsa->scope);
+  if (lsdb == NULL)
+    {
+      zlog_warn ("Can't decide scoped LSDB");
+      ospf6_lsa_delete (lsa);
+      return;
+    }
+
   old = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id,
-                           lsa->header->adv_router, lsa->scope);
+                           lsa->header->adv_router, lsdb);
   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 this origination is neither different instance nor refresh,
+         suppress this origination */
+      if (! CHECK_FLAG (old->flag, OSPF6_LSA_REFRESH) &&
+          ! OSPF6_LSA_IS_DIFFER (lsa, old))
         {
-          if (IS_OSPF6_DUMP_LSA)
-            zlog_info ("LSA: Suppress updating %s", lsa->str);
+          if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+            zlog_info ("Suppress updating LSA: %s", lsa->name);
           ospf6_lsa_delete (lsa);
           return;
         }
     }
 
   lsa->refresh = thread_add_timer (master, ospf6_lsa_refresh, lsa,
-                                   OSPF6_LS_REFRESH_TIME);
-  gettimeofday (&lsa->originated, NULL);
+                                   LS_REFRESH_TIME);
 
-  //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);
+  if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+    {
+      zlog_info ("LSA Originate:");
+      ospf6_lsa_header_print (lsa);
+    }
 
-  ospf6_dbex_remove_from_all_retrans_list (lsa);
-  ospf6_dbex_flood (lsa, NULL);
-  ospf6_lsdb_install (lsa);
+  if (old)
+    ospf6_flood_clear (old);
+  ospf6_flood_lsa (lsa, NULL);
+  ospf6_install_lsa (lsa, lsdb);
+}
+
+void
+ospf6_lsa_re_originate (struct ospf6_lsa *lsa)
+{
+  u_int16_t index;
+
+  if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+    {
+      zlog_info ("LSA Reoriginate:");
+      ospf6_lsa_header_print (lsa);
+    }
+
+  index = OSPF6_LSTYPE_INDEX (ntohs (lsa->header->type));
+  if (ospf6_lstype[index].reoriginate)
+    (*ospf6_lstype[index].reoriginate) (lsa);
+  else
+    ospf6_lsa_premature_aging (lsa);
 }
 
 
-/* ospf6_lsa expired */
+/* ospf6 lsa expiry */
 int
 ospf6_lsa_expire (struct thread *thread)
 {
   struct ospf6_lsa *lsa;
   struct ospf6_lsdb *lsdb = NULL;
-  void (*hook) (struct ospf6_lsa *, struct ospf6_lsa *);
 
   lsa = (struct ospf6_lsa *) THREAD_ARG (thread);
-  assert (lsa && lsa->lsa_hdr);
 
-  /* assertion */
-  assert (IS_LSA_MAXAGE (lsa));
-  assert (!lsa->refresh);
+  assert (lsa && lsa->header);
+  assert (OSPF6_LSA_IS_MAXAGE (lsa));
+  assert (! lsa->refresh);
 
   lsa->expire = (struct thread *) NULL;
 
-  /* log */
-  if (IS_OSPF6_DUMP_LSA)
-    zlog_info ("LSA: Expire: %s", lsa->str);
-
-  if (!lsa->summary)
+  if (IS_OSPF6_DEBUG_LSA (TIMER))
     {
-      /* reflood lsa */
-      ospf6_dbex_flood (lsa, NULL);
-
-      /* get scoped lsdb, call remove hook */
-      if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (ntohs (lsa->header->type)))
-        lsdb = ((struct ospf6_interface *) lsa->scope)->lsdb;
-      else if (OSPF6_LSA_IS_SCOPE_AREA (ntohs (lsa->header->type)))
-        lsdb = ((struct ospf6_area *) lsa->scope)->lsdb;
-      else if (OSPF6_LSA_IS_SCOPE_AS (ntohs (lsa->header->type)))
-        lsdb = ((struct ospf6 *) lsa->scope)->lsdb;
-      else
-        assert (0);
-
-      /* call LSDB hook to re-process LSA */
-      hook = ospf6_lsdb_hook[ntohs (lsa->header->type) &
-                             OSPF6_LSTYPE_CODE_MASK].hook;
-      if (hook)
-        (*hook) (NULL, lsa);
-
-      /* do not free LSA, and do nothing about lslists.
-         wait event (ospf6_lsdb_check_maxage) */
+      zlog_info ("LSA Expire:");
+      ospf6_lsa_header_print (lsa);
     }
 
+  if (lsa->headeronly)
+    return 0;    /* dbexchange will do something ... */
+
+  /* reflood lsa */
+  ospf6_flood_lsa (lsa, NULL);
+
+  /* reinstall lsa */
+  lsdb = ospf6_get_scoped_lsdb (lsa->header->type, lsa->scope);
+  if (lsdb == NULL)
+    {
+      zlog_warn ("Can't decide scoped LSDB: %s", lsa->name);
+      return 0;
+    }
+  if (IS_OSPF6_DEBUG_LSA (DATABASE))
+    zlog_info ("Reinstall MaxAge %s", lsa->name);
+  ospf6_lsdb_add (lsa, lsdb);
+
+  /* schedule maxage remover */
+  ospf6_maxage_remove (ospf6);
+
   return 0;
 }
 
+/* Below will become dummy thread.
+   refresh function must be set individually per each LSAs */
 int
 ospf6_lsa_refresh (struct thread *thread)
 {
   struct ospf6_lsa *lsa;
-  struct ospf6_lsa_slot *slot;
 
   assert (thread);
-  lsa = (struct ospf6_lsa *) THREAD_ARG  (thread);
-  assert (lsa && lsa->lsa_hdr);
+  lsa = (struct ospf6_lsa *) THREAD_ARG (thread);
+  assert (lsa && lsa->header);
 
-  /* this will be used later as flag to decide really originate */
   lsa->refresh = (struct thread *) NULL;
-  SET_FLAG (lsa->flag, OSPF6_LSA_FLAG_REFRESH);
 
-  /* log */
-  if (IS_OSPF6_DUMP_LSA)
-    zlog_info ("LSA Refresh: %s", lsa->str);
+  /* this will be used later to decide really originate or not */
+  SET_FLAG (lsa->flag, OSPF6_LSA_REFRESH);
 
-  slot = ospf6_lsa_slot_get (lsa->header->type);
-  if (slot)
+  if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
     {
-      zlog_info ("LSA Refresh: %s", slot->name);
-      (*slot->func_refresh) (lsa);
-      return 0;
+      zlog_info ("LSA Refresh:");
+      ospf6_lsa_header_print (lsa);
     }
 
-  zlog_warn ("Can't Refresh LSA: Unknown type: %#x",
-             ntohs (lsa->header->type));
-  return 1;
+  ospf6_lsa_re_originate (lsa);
+  return 0;
 }
 
 
@@ -885,1042 +747,205 @@
 }
 
 int
-ospf6_lsa_is_known_type (struct ospf6_lsa_header *lsa_header)
+ospf6_unknown_reoriginate (struct ospf6_lsa *lsa)
 {
-  struct ospf6_lsa_slot *slot;
-
-  slot = ospf6_lsa_slot_get (lsa_header->type);
-  if (slot)
-    return 1;
-  return 0;
-}
-
-struct ospf6_lsa_slot *slot_head = NULL;
-
-struct ospf6_lsa_slot *
-ospf6_lsa_slot_get (u_int16_t type)
-{
-  struct ospf6_lsa_slot *slot;
-
-  for (slot = slot_head; slot; slot = slot->next)
-    {
-      if (slot->type == type)
-        return slot;
-    }
-
-  return NULL;
-}
-
-int
-ospf6_lsa_slot_register (struct ospf6_lsa_slot *src)
-{
-  struct ospf6_lsa_slot *new, *slot;
-
-  slot = ospf6_lsa_slot_get (src->type);
-  if (slot)
-    {
-      if (IS_OSPF6_DUMP_LSA)
-        zlog_info ("LSA: Slot register: already exists: %#x %s",
-                   slot->type, slot->name);
-      return -1;
-    }
-
-  new = (struct ospf6_lsa_slot *)
-    XMALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa_slot));
-  if (! new)
-    {
-      zlog_err ("Can't allocate memory for LSA slot: %s", strerror (errno));
-      return -1;
-    }
-  memset (new, 0, sizeof (struct ospf6_lsa_slot));
-  memcpy (new, src, sizeof (struct ospf6_lsa_slot));
-
-  if (IS_OSPF6_DUMP_LSA)
-    zlog_info ("LSA: Slot register: %#x %s", slot->type, slot->name);
-
-  if (slot_head == NULL)
-    {
-      new->prev = NULL;
-      new->next = NULL;
-      slot_head = new;
-      return 0;
-    }
-
-  slot = slot_head;
-  while (slot->next)
-    slot = slot->next;
-
-  slot->next = new;
-  new->prev = slot;
-
+  ospf6_lsa_premature_aging (lsa);
   return 0;
 }
 
 int
-ospf6_lsa_slot_unregister (u_int16_t type)
+ospf6_unknown_show (struct vty *vty, struct ospf6_lsa *lsa)
 {
-  struct ospf6_lsa_slot *slot;
+  u_char *start, *end, *current;
+  char byte[4];
 
-  slot = ospf6_lsa_slot_get (type);
-  if (slot == NULL)
-    {
-      if (IS_OSPF6_DUMP_LSA)
-        zlog_info ("Registering LSA slot: no such slot: %#x", type);
-      return -1;
-    }
-
-  if (IS_OSPF6_DUMP_LSA)
-    zlog_info ("Unregistering LSA Slot: %#x %s", slot->type, slot->name);
-
-  if (slot->prev)
-    slot->prev->next = slot->next;
-  if (slot->next)
-    slot->next->prev = slot->prev;
-
-  if (slot_head == slot)
-    slot_head = slot->next;
-
-  XFREE (MTYPE_OSPF6_LSA, slot);
-  return 0;
-}
-
-char *
-ospf6_lsa_type_string (u_int16_t type, char *buf, int bufsize)
-{
-  struct ospf6_lsa_slot *slot;
-
-  slot = ospf6_lsa_slot_get (type);
-  if (slot)
-    snprintf (buf, bufsize, "%s", slot->name);
-  else
-    snprintf (buf, bufsize, "Type=0x%04x", ntohs (type));
-
-  return buf;
-}
-
-
-/*******************/
-/* LSA Origination */
-/*******************/
-
-#define CONTINUE_IF_ADDRESS_LINKLOCAL(addr)\
-  if (IN6_IS_ADDR_LINKLOCAL (&(addr)->u.prefix6))\
-    {\
-      char buf[64];\
-      prefix2str (addr, buf, sizeof (buf));\
-      if (IS_OSPF6_DUMP_LSA)\
-        zlog_info ("  Filter out Linklocal: %s", buf);\
-      continue;\
-    }
-
-#define CONTINUE_IF_ADDRESS_UNSPECIFIED(addr)\
-  if (IN6_IS_ADDR_UNSPECIFIED (&(addr)->u.prefix6))\
-    {\
-      char buf[64];\
-      prefix2str (addr, buf, sizeof (buf));\
-      if (IS_OSPF6_DUMP_LSA)\
-        zlog_info ("  Filter out Unspecified: %s", buf);\
-      continue;\
-    }
-
-#define CONTINUE_IF_ADDRESS_LOOPBACK(addr)\
-  if (IN6_IS_ADDR_LOOPBACK (&(addr)->u.prefix6))\
-    {\
-      char buf[64];\
-      prefix2str (addr, buf, sizeof (buf));\
-      if (IS_OSPF6_DUMP_LSA)\
-        zlog_info ("  Filter out Loopback: %s", buf);\
-      continue;\
-    }
-
-#define CONTINUE_IF_ADDRESS_V4COMPAT(addr)\
-  if (IN6_IS_ADDR_V4COMPAT (&(addr)->u.prefix6))\
-    {\
-      char buf[64];\
-      prefix2str (addr, buf, sizeof (buf));\
-      if (IS_OSPF6_DUMP_LSA)\
-        zlog_info ("  Filter out V4Compat: %s", buf);\
-      continue;\
-    }
-
-#define CONTINUE_IF_ADDRESS_V4MAPPED(addr)\
-  if (IN6_IS_ADDR_V4MAPPED (&(addr)->u.prefix6))\
-    {\
-      char buf[64];\
-      prefix2str (addr, buf, sizeof (buf));\
-      if (IS_OSPF6_DUMP_LSA)\
-        zlog_info ("  Filter out V4Mapped: %s", buf);\
-      continue;\
-    }
-
-/******************************/
-/* RFC2740 3.4.3.1 Router-LSA */
-/******************************/
-
-char *
-ospf6_lsa_router_bits_string (u_char router_bits, char *buf, int size)
-{
-  char w, v, e, b;
-
-  w = (router_bits & OSPF6_ROUTER_LSA_BIT_W ? 'W' : '-');
-  v = (router_bits & OSPF6_ROUTER_LSA_BIT_V ? 'V' : '-');
-  e = (router_bits & OSPF6_ROUTER_LSA_BIT_E ? 'E' : '-');
-  b = (router_bits & OSPF6_ROUTER_LSA_BIT_B ? 'B' : '-');
-  snprintf (buf, size, "----%c%c%c%c", w, v, e, b);
-  return buf;
-}
-
-int
-ospf6_lsa_router_show (struct vty *vty, struct ospf6_lsa *lsa)
-{
-  char *start, *end, *current;
-  char buf[32], name[32], bits[32], options[32];
-  struct ospf6_router_lsa *router_lsa;
-  struct ospf6_router_lsd *lsdesc;
-
-  assert (lsa->header);
-
-  router_lsa = (struct ospf6_router_lsa *)
-    ((char *) lsa->header + sizeof (struct ospf6_lsa_header));
-
-  ospf6_lsa_router_bits_string (router_lsa->bits, bits, sizeof (bits));
-  ospf6_options_string (router_lsa->options, options, sizeof (options));
-  vty_out (vty, "    Bits: %s Options: %s%s", bits, options, VTY_NEWLINE);
-
-  start = (char *) router_lsa + sizeof (struct ospf6_router_lsa);
+  start = (char *) lsa->header + sizeof (struct ospf6_lsa_header);
   end = (char *) lsa->header + ntohs (lsa->header->length);
-  for (current = start; current + sizeof (struct ospf6_router_lsd) <= end;
-       current += sizeof (struct ospf6_router_lsd))
+
+  vty_out (vty, "        Unknown contents:%s", VTY_NEWLINE);
+  for (current = start; current < end; current ++)
     {
-      lsdesc = (struct ospf6_router_lsd *) current;
+      if ((current - start) % 16 == 0)
+        vty_out (vty, "%s        ", VTY_NEWLINE);
+      else if ((current - start) % 4 == 0)
+        vty_out (vty, " ");
 
-      if (lsdesc->type == OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT)
-        snprintf (name, sizeof (name), "Point-To-Point");
-      else if (lsdesc->type == OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK)
-        snprintf (name, sizeof (name), "Transit-Network");
-      else if (lsdesc->type == OSPF6_ROUTER_LSD_TYPE_STUB_NETWORK)
-        snprintf (name, sizeof (name), "Stub-Network");
-      else if (lsdesc->type == OSPF6_ROUTER_LSD_TYPE_VIRTUAL_LINK)
-        snprintf (name, sizeof (name), "Virtual-Link");
-      else
-        snprintf (name, sizeof (name), "Unknown (%#x)", lsdesc->type);
-
-      vty_out (vty, "    Type: %s Metric: %d%s",
-               name, ntohs (lsdesc->metric), VTY_NEWLINE);
-      vty_out (vty, "    Interface ID: %s%s",
-               inet_ntop (AF_INET, &lsdesc->interface_id,
-                          buf, sizeof (buf)), VTY_NEWLINE);
-      vty_out (vty, "    Neighbor Interface ID: %s%s",
-               inet_ntop (AF_INET, &lsdesc->neighbor_interface_id,
-                          buf, sizeof (buf)), VTY_NEWLINE);
-      vty_out (vty, "    Neighbor Router ID: %s%s",
-               inet_ntop (AF_INET, &lsdesc->neighbor_router_id,
-                          buf, sizeof (buf)), VTY_NEWLINE);
+      snprintf (byte, sizeof (byte), "%02x", *current);
+      vty_out (vty, "%s", byte);
     }
+
+  vty_out (vty, "%s%s", VTY_NEWLINE, VTY_NEWLINE);
   return 0;
 }
 
-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_area *o6a;
-  int count;
-  u_int32_t area_id;
-
-  struct ospf6_router_lsa *router_lsa;
-  struct ospf6_router_lsd *router_lsd;
-  listnode i;
-  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_info ("LSA: Update Router-LSA: No such area: %s", buffer);
-      return 0;
-    }
-
-  /* clear thread */
-  o6a->thread_router_lsa = NULL;
-
-  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));
-  router_lsa = (struct ospf6_router_lsa *) buffer;
-
-  OSPF6_OPT_CLEAR_ALL (router_lsa->options);
-  OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_V6);
-  OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_E);
-  OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_MC);
-  OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_N);
-  OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_R);
-  OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_DC);
-
-  OSPF6_ROUTER_LSA_CLEAR_ALL_BITS (router_lsa);
-  OSPF6_ROUTER_LSA_CLEAR (router_lsa, OSPF6_ROUTER_LSA_BIT_B);
-
-  if (ospf6_is_asbr (o6a->ospf6))
-    OSPF6_ROUTER_LSA_SET (router_lsa, OSPF6_ROUTER_LSA_BIT_E);
-  else
-    OSPF6_ROUTER_LSA_CLEAR (router_lsa, OSPF6_ROUTER_LSA_BIT_E);
-
-  OSPF6_ROUTER_LSA_CLEAR (router_lsa, OSPF6_ROUTER_LSA_BIT_V);
-  OSPF6_ROUTER_LSA_CLEAR (router_lsa, OSPF6_ROUTER_LSA_BIT_W);
-
-  /* describe links for each interfaces */
-  router_lsd = (struct ospf6_router_lsd *) (router_lsa + 1);
-  for (i = listhead (o6a->if_list); i; nextnode (i))
-    {
-      o6i = (struct ospf6_interface *) getdata (i);
-      assert (o6i);
-
-      /* Interfaces in state Down or Loopback are not described */
-      if (o6i->state == IFS_DOWN || o6i->state == IFS_LOOPBACK)
-        continue;
-
-      /* Nor are interfaces without any full adjacencies described */
-      count = 0;
-      o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state);
-      if (count == 0)
-        continue;
-
-      /* Point-to-Point interfaces */
-      if (if_is_pointopoint (o6i->interface))
-        {
-          if (listcount (o6i->neighbor_list) == 0)
-            continue;
-
-          if (listcount (o6i->neighbor_list) != 1)
-            zlog_warn ("LSA: Multiple neighbors on PoinToPoint: %s",
-                       o6i->interface->name);
-
-          o6n = (struct ospf6_neighbor *)
-                   getdata (listhead (o6i->neighbor_list));
-          assert (o6n);
-
-          router_lsd->type = OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT;
-          router_lsd->metric = htons (o6i->cost);
-          router_lsd->interface_id = htonl (o6i->if_id);
-          router_lsd->neighbor_interface_id = htonl (o6n->ifid);
-          router_lsd->neighbor_router_id = o6n->router_id;
-
-          size += sizeof (struct ospf6_router_lsd);
-          router_lsd ++;
-
-          continue;
-        }
-
-      /* Broadcast and NBMA interfaces */
-      if (if_is_broadcast (o6i->interface))
-        {
-          /* If this router is not DR,
-             and If this router not fully adjacent with DR,
-             this interface is not transit yet: ignore. */
-          if (o6i->state != IFS_DR)
-            {
-              o6n = ospf6_neighbor_lookup (o6i->dr, o6i); /* find DR */
-              if (o6n == NULL || o6n->state != NBS_FULL)
-                continue;
-            }
-          else
-            {
-              count = 0;
-              o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state);
-              if (count == 0)
-                continue;
-            }
-
-          router_lsd->type = OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK;
-          router_lsd->metric = htons (o6i->cost);
-          router_lsd->interface_id = htonl (o6i->if_id);
-          if (o6i->state != IFS_DR)
-            {
-              router_lsd->neighbor_interface_id = htonl (o6n->ifid);
-              router_lsd->neighbor_router_id = o6n->router_id;
-            }
-          else
-            {
-              router_lsd->neighbor_interface_id = htonl (o6i->if_id);
-              router_lsd->neighbor_router_id = o6i->area->ospf6->router_id;
-            }
-
-          size += sizeof (struct ospf6_router_lsd);
-          router_lsd ++;
-
-          continue;
-        }
-
-      /* Virtual links */
-        /* xxx */
-      /* Point-to-Multipoint interfaces */
-        /* xxx */
-    }
-
-  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
-ospf6_lsa_router_hook_neighbor (void *neighbor)
-{
-  struct ospf6_neighbor *o6n = neighbor;
-  if (o6n->ospf6_interface->area)
-    ospf6_lsa_schedule_router (o6n->ospf6_interface->area);
-  return 0;
-}
-
-int
-ospf6_lsa_router_hook_interface (void *interface)
-{
-  struct ospf6_interface *o6i = interface;
-  if (o6i->area)
-    ospf6_lsa_schedule_router (o6i->area);
-  return 0;
-}
-
-int
-ospf6_lsa_router_hook_area (void *area)
-{
-  struct ospf6_area *o6a = area;
-  ospf6_lsa_schedule_router (o6a);
-  return 0;
-}
-
-int
-ospf6_lsa_router_hook_top (void *ospf6)
-{
-  struct ospf6 *o6 = ospf6;
-  struct ospf6_area *o6a;
-  listnode node;
-
-  for (node = listhead (o6->area_list); node; nextnode (node))
-    {
-      o6a = getdata (node);
-      ospf6_lsa_schedule_router (o6a);
-    }
-  return 0;
-}
-
-int
-ospf6_lsa_router_refresh (void *old)
-{
-  struct ospf6_lsa *lsa = old;
-  struct ospf6_area *o6a;
-
-  o6a = lsa->scope;
-  ospf6_lsa_schedule_router (o6a);
-  return 0;
-}
-
-void
-ospf6_lsa_slot_register_router ()
-{
-  struct ospf6_lsa_slot slot;
-  struct ospf6_hook hook;
-
-  memset (&slot, 0, sizeof (struct ospf6_lsa_slot));
-  slot.type              = htons (OSPF6_LSA_TYPE_ROUTER);
-  slot.name              = "Router";
-  slot.func_show         = ospf6_lsa_router_show;
-  slot.func_refresh      = ospf6_lsa_router_refresh;
-  ospf6_lsa_slot_register (&slot);
-
-  ospf6_lsdb_hook[OSPF6_LSA_TYPE_ROUTER & OSPF6_LSTYPE_CODE_MASK].hook = 
-    ospf6_spf_database_hook;
-
-  memset (&hook, 0, sizeof (hook));
-  hook.name = "OriginateRouter";
-  hook.hook_change  = ospf6_lsa_router_hook_neighbor;
-  ospf6_hook_register (&hook, &neighbor_hook);
-
-  memset (&hook, 0, sizeof (hook));
-  hook.name = "OriginateRouter";
-  hook.hook_change = ospf6_lsa_router_hook_interface;
-  ospf6_hook_register (&hook, &interface_hook);
-
-  memset (&hook, 0, sizeof (hook));
-  hook.name = "OriginateRouter";
-  hook.hook_change      = ospf6_lsa_router_hook_area;
-  ospf6_hook_register (&hook, &area_hook);
-
-  memset (&hook, 0, sizeof (hook));
-  hook.name = "OriginateRouter";
-  hook.hook_change       = ospf6_lsa_router_hook_top;
-  ospf6_hook_register (&hook, &top_hook);
-}
-
-/*******************************/
-/* RFC2740 3.4.3.2 Network-LSA */
-/*******************************/
-
-int
-ospf6_lsa_network_show (struct vty *vty, struct ospf6_lsa *lsa)
-{
-  char *start, *end, *current;
-  struct ospf6_network_lsa *network_lsa;
-  u_int32_t *router_id;
-  char buf[128], options[32];
-
-  assert (lsa->header);
-  network_lsa = (struct ospf6_network_lsa *) (lsa->header + 1);
-  router_id = (u_int32_t *)(network_lsa + 1);
-
-  ospf6_options_string (network_lsa->options, options, sizeof (options));
-  vty_out (vty, "     Options: %s%s", options, VTY_NEWLINE);
-
-  start = (char *) network_lsa + sizeof (struct ospf6_network_lsa);
-  end = (char *) lsa->header + ntohs (lsa->header->length);
-  for (current = start; current + sizeof (u_int32_t) <= end;
-       current += sizeof (u_int32_t))
-    {
-      router_id = (u_int32_t *) current;
-      inet_ntop (AF_INET, router_id, buf, sizeof (buf));
-      vty_out (vty, "     Attached Router: %s%s", buf, VTY_NEWLINE);
-    }
-  return 0;
-}
-
-void
-ospf6_lsa_network_update (char *ifname)
-{
-  char buffer [MAXLSASIZE];
-  u_int16_t size;
-  struct ospf6_lsa *old;
-  struct interface *ifp;
-  struct ospf6_interface *o6i;
-  int count;
-
-  struct ospf6_network_lsa *network_lsa;
-  struct ospf6_neighbor *o6n;
-  u_int32_t *router_id;
-  listnode node;
-
-  ifp = if_lookup_by_name (ifname);
-  if (! ifp)
-    {
-      if (IS_OSPF6_DUMP_LSA)
-        zlog_warn ("Update Network: No such Interface: %s", ifname);
-      return;
-    }
-
-  o6i = (struct ospf6_interface *) ifp->info;
-  if (! o6i || ! o6i->area)
-    {
-      if (IS_OSPF6_DUMP_LSA)
-        zlog_warn ("Update Network: Interface not enabled: %s", ifname);
-      return;
-    }
-
-  /* find previous LSA */
-  old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_NETWORK),
-                           htonl (o6i->if_id),
-                           o6i->area->ospf6->router_id, o6i->area);
-
-  /* Don't originate Network-LSA if not DR */
-  if (o6i->state != IFS_DR)
-    {
-      if (IS_OSPF6_DUMP_LSA)
-        zlog_info ("Update Network: Interface %s is not DR",
-                   o6i->interface->name);
-      if (old)
-        ospf6_lsa_premature_aging (old);
-      return;
-    }
-
-  /* If none of neighbor is adjacent to us */
-  count = 0;
-  o6i->foreach_nei (o6i, &count, NBS_FULL, ospf6_count_state);
-  if (count == 0)
-    {
-      if (IS_OSPF6_DUMP_LSA)
-        zlog_info ("Update Network: Interface %s is Stub",
-                   o6i->interface->name);
-      if (old)
-        ospf6_lsa_premature_aging (old);
-      return;
-    }
-
-  if (IS_OSPF6_DUMP_LSA)
-    zlog_info ("Update Network: Interface %s", o6i->interface->name);
-
-  /* prepare buffer */
-  memset (buffer, 0, sizeof (buffer));
-  size = sizeof (struct ospf6_network_lsa);
-  network_lsa = (struct ospf6_network_lsa *) buffer;
-  router_id = (u_int32_t *)(network_lsa + 1);
-
-  /* set fields of myself */
-  *router_id++ = o6i->area->ospf6->router_id;
-  size += sizeof (u_int32_t);
-  network_lsa->options[0] |= o6i->area->options[0];
-  network_lsa->options[1] |= o6i->area->options[1];
-  network_lsa->options[2] |= o6i->area->options[2];
-
-  /* Walk through neighbors */
-  for (node = listhead (o6i->neighbor_list); node; nextnode (node))
-    {
-      o6n = (struct ospf6_neighbor *) getdata (node);
-
-      if (o6n->state != NBS_FULL)
-        continue;
-
-      /* set this neighbor's Router-ID to LSA */
-      *router_id++ = o6n->router_id;
-      size += sizeof (u_int32_t);
-
-      /* options field is logical OR */
-      network_lsa->options[0] |= o6n->options[0];
-      network_lsa->options[1] |= o6n->options[1];
-      network_lsa->options[2] |= o6n->options[2];
-    }
-
-  ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_NETWORK),
-                       htonl (o6i->if_id), o6i->area->ospf6->router_id,
-                       (char *) network_lsa, size, o6i->area);
-}
-
-int
-ospf6_lsa_network_hook_neighbor (void *neighbor)
-{
-  struct ospf6_neighbor *o6n = neighbor;
-  ospf6_lsa_network_update (o6n->ospf6_interface->interface->name);
-  return 0;
-}
-
-int
-ospf6_lsa_network_hook_interface (void *interface)
-{
-  struct ospf6_interface *o6i = interface;
-  if (o6i->area)
-    ospf6_lsa_network_update (o6i->interface->name);
-  return 0;
-}
-
-int
-ospf6_lsa_network_refresh (void *old)
-{
-  struct ospf6_lsa *lsa = old;
-  struct interface *ifp;
-
-  ifp = if_lookup_by_index (ntohl (lsa->header->id));
-  if (! ifp)
-    ospf6_lsa_premature_aging (old);
-  else
-    ospf6_lsa_network_update (ifp->name);
-
-  return 0;
-}
-
-void
-ospf6_lsa_slot_register_network ()
-{
-  struct ospf6_lsa_slot slot;
-  struct ospf6_hook hook;
-
-  memset (&slot, 0, sizeof (struct ospf6_lsa_slot));
-  slot.type              = htons (OSPF6_LSA_TYPE_NETWORK);
-  slot.name              = "Network";
-  slot.func_show         = ospf6_lsa_network_show;
-  slot.func_refresh      = ospf6_lsa_network_refresh;
-  ospf6_lsa_slot_register (&slot);
-
-  ospf6_lsdb_hook[OSPF6_LSA_TYPE_NETWORK & OSPF6_LSTYPE_CODE_MASK].hook = 
-    ospf6_spf_database_hook;
-
-  memset (&hook, 0, sizeof (hook));
-  hook.name  = "OriginateNetwork";
-  hook.hook_change  = ospf6_lsa_network_hook_neighbor;
-  ospf6_hook_register (&hook, &neighbor_hook);
-
-  memset (&hook, 0, sizeof (hook));
-  hook.name  = "OriginateNetwork";
-  hook.hook_change = ospf6_lsa_network_hook_interface;
-  ospf6_hook_register (&hook, &interface_hook);
-}
-
-/****************************/
-/* RFC2740 3.4.3.6 Link-LSA */
-/****************************/
-
-int
-ospf6_lsa_link_show (struct vty *vty, struct ospf6_lsa *lsa)
-{
-  char *start, *end, *current;
-  struct ospf6_link_lsa *link_lsa;
-  int prefixnum;
-  struct ospf6_prefix *prefix;
-  char buf[128];
-  struct in6_addr in6;
-
-  assert (lsa->header);
-
-  link_lsa = (struct ospf6_link_lsa *) (lsa->header + 1);
-  prefixnum = ntohl (link_lsa->llsa_prefix_num);
-
-  inet_ntop (AF_INET6, (void *)&link_lsa->llsa_linklocal, buf, sizeof (buf));
-  vty_out (vty, "     LinkLocal Address: %s%s", buf, VTY_NEWLINE);
-  vty_out (vty, "     Number of Prefix: %d%s", prefixnum, VTY_NEWLINE);
-
-  start = (char *) link_lsa + sizeof (struct ospf6_link_lsa);
-  end = (char *) lsa->header + ntohs (lsa->header->length); 
-  for (current = start; current < end; current += OSPF6_PREFIX_SIZE (prefix))
-    {
-      prefix = (struct ospf6_prefix *) current;
-      if (current + OSPF6_PREFIX_SIZE (prefix) > end)
-        {
-          vty_out (vty, "    Trailing %d byte garbage ... Malformed%s",
-                   end - current, VTY_NEWLINE);
-          return -1;
-        }
-
-      ospf6_prefix_options_str (prefix->prefix_options, buf, sizeof (buf));
-      vty_out (vty, "     Prefix Options: %s%s", buf, VTY_NEWLINE);
-      ospf6_prefix_in6_addr (prefix, &in6);
-      inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
-      vty_out (vty, "     Prefix: %s/%d%s",
-               buf, prefix->prefix_length, VTY_NEWLINE);
-    }
-
-  return 0;
-}
-
-
-void
-ospf6_lsa_link_update (char *ifname)
-{
-  char *cp, buffer [MAXLSASIZE], buf[32];
-  u_int16_t size;
-  struct ospf6_lsa *old;
-  struct interface *ifp;
-  struct ospf6_interface *o6i;
-
-  struct ospf6_link_lsa *link_lsa;
-  struct ospf6_prefix *p;
-  list prefix_connected;
-  listnode node;
-  struct connected *c;
-
-  ifp = if_lookup_by_name (ifname);
-  if (! ifp)
-    {
-      if (IS_OSPF6_DUMP_LSA)
-        zlog_info ("Update Link: No such Interface: %s", ifname);
-      return;
-    }
-
-  o6i = (struct ospf6_interface *) ifp->info;
-  if (! o6i || ! o6i->area)
-    {
-      if (IS_OSPF6_DUMP_LSA)
-        zlog_info ("Update Link: Interface not enabled: %s", ifname);
-      return;
-    }
-
-#if 0
-  /* Link-LSA is on Broadcast or NBMA */
-  if (! if_is_broadcast (o6i->interface) /* && ! NBMA xxx */)
-    {
-      return;
-    }
-#endif /*0*/
-
-  /* find previous LSA */
-  old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_LINK), htonl (o6i->if_id),
-                           ospf6->router_id, o6i->area);
-
-  /* can't make Link-LSA if linklocal address not set */
-  if (! o6i->lladdr)
-    {
-      if (IS_OSPF6_DUMP_LSA)
-        zlog_warn ("Update Link: No Linklocal Address: %s",
-                   o6i->interface->name);
-      if (old)
-        ospf6_lsa_premature_aging (old);
-      return;
-    }
-
-  if (IS_OSPF6_DUMP_LSA)
-    zlog_info ("Update Link: Interface %s", o6i->interface->name);
-
-  if (! ospf6_interface_is_enabled (o6i->interface->ifindex))
-    {
-      if (IS_OSPF6_DUMP_LSA)
-        zlog_info ("  Interface %s not enabled", o6i->interface->name);
-      if (old)
-        ospf6_lsa_premature_aging (old);
-      return;
-    }
-
-  /* check connected prefix */
-  prefix_connected = list_new ();
-  for (node = listhead (o6i->interface->connected); node; nextnode (node))
-    {
-      c = (struct connected *) getdata (node);
-
-      /* filter prefix not IPv6 */
-      if (c->address->family != AF_INET6)
-        continue;
-
-      /* for log */
-      prefix2str (c->address, buf, sizeof (buf));
-
-      CONTINUE_IF_ADDRESS_LINKLOCAL (c->address);
-      CONTINUE_IF_ADDRESS_UNSPECIFIED (c->address);
-      CONTINUE_IF_ADDRESS_LOOPBACK (c->address);
-      CONTINUE_IF_ADDRESS_V4COMPAT (c->address);
-      CONTINUE_IF_ADDRESS_V4MAPPED (c->address);
-
-      /* filter prefix specified by configuration */
-      if (o6i->plist_name)
-        {
-          struct prefix_list *plist;
-          enum prefix_list_type result = PREFIX_PERMIT;
-
-          plist = prefix_list_lookup (AFI_IP6, o6i->plist_name);
-          if (plist)
-            result = prefix_list_apply (plist, c->address);
-          else if (IS_OSPF6_DUMP_LSA)
-            zlog_warn ("Update Intra-Prefix (Stub): "
-                       "Prefix list \"%s\" not found", o6i->plist_name);
-
-          if (result == PREFIX_DENY)
-            {
-              if (IS_OSPF6_DUMP_LSA)
-                zlog_info ("  Filter out Prefix-list %s: %s",
-                           o6i->plist_name, buf);
-              continue;
-            }
-        }
-
-      if (IS_OSPF6_DUMP_LSA)
-        zlog_info ("    Advertise %s", buf);
-
-      /* hold prefix in list. duplicate is filtered in ospf6_prefix_add() */
-      p = ospf6_prefix_create (0, 0, (struct prefix_ipv6 *) c->address);
-      ospf6_prefix_add (prefix_connected, p);
-    }
-
-  /* Note: even if no prefix configured, still we have to create Link-LSA
-     for next-hop resolution */
-
-  memset (buffer, 0, sizeof (buffer));
-  size = sizeof (struct ospf6_link_lsa);
-  link_lsa = (struct ospf6_link_lsa *) buffer;
-
-  /* fill Link LSA and calculate size */
-  link_lsa->llsa_rtr_pri = o6i->priority;
-  link_lsa->llsa_options[0] = o6i->area->options[0];
-  link_lsa->llsa_options[1] = o6i->area->options[1];
-  link_lsa->llsa_options[2] = o6i->area->options[2];
-
-  /* linklocal address */
-  memcpy (&link_lsa->llsa_linklocal, o6i->lladdr, sizeof (struct in6_addr));
-
-#ifdef KAME /* clear ifindex */
-  if (link_lsa->llsa_linklocal.s6_addr[3] & 0x0f)
-    link_lsa->llsa_linklocal.s6_addr[3] &= ~((char)0x0f);
-#endif /* KAME */
-
-  link_lsa->llsa_prefix_num = htonl (listcount (prefix_connected));
-  cp = (char *)(link_lsa + 1);
-  for (node = listhead (prefix_connected); node; nextnode (node))
-    {
-      p = (struct ospf6_prefix *) getdata (node);
-      size += OSPF6_PREFIX_SIZE (p);
-      memcpy (cp, p, OSPF6_PREFIX_SIZE (p));
-      cp += OSPF6_PREFIX_SIZE (p);
-    }
-
-  for (node = listhead (prefix_connected); node; nextnode (node))
-    {
-      p = (struct ospf6_prefix *) getdata (node);
-      ospf6_prefix_delete (p);
-    }
-  list_delete (prefix_connected);
-
-  ospf6_lsa_originate (htons (OSPF6_LSA_TYPE_LINK),
-                       htonl (o6i->if_id), o6i->area->ospf6->router_id,
-                       (char *) link_lsa, size, o6i);
-}
-
-int
-ospf6_lsa_link_hook_interface (void *interface)
-{
-  struct ospf6_interface *o6i = interface;
-  if (o6i->area)
-    ospf6_lsa_link_update (o6i->interface->name);
-  return 0;
-}
-
-int
-ospf6_lsa_link_refresh (void *old)
-{
-  struct ospf6_lsa *lsa = old;
-  struct interface *ifp;
-
-  ifp = if_lookup_by_index (ntohl (lsa->header->id));
-  if (! ifp)
-    ospf6_lsa_premature_aging (old);
-  else
-    ospf6_lsa_link_update (ifp->name);
-
-  return 0;
-}
-
-void
-ospf6_lsa_slot_register_link ()
-{
-  struct ospf6_lsa_slot slot;
-
-  memset (&slot, 0, sizeof (struct ospf6_lsa_slot));
-  slot.type              = htons (OSPF6_LSA_TYPE_LINK);
-  slot.name              = "Link";
-  slot.func_show         = ospf6_lsa_link_show;
-  slot.func_refresh      = ospf6_lsa_link_refresh;
-  slot.hook_interface.name = "OriginateLink";
-  slot.hook_interface.hook_change = ospf6_lsa_link_hook_interface;
-  ospf6_lsa_slot_register (&slot);
-
-  /*
-   * Link LSA handling will be shift in ospf6_intra.c
-   * Currently, only database hook only moved to ospf6_intra.c
-   */
-#if 0
-  ospf6_lsdb_hook[OSPF6_LSA_TYPE_LINK & OSPF6_LSTYPE_CODE_MASK].hook = 
-    ospf6_spf_database_hook;
-#endif /*0*/
-}
-
-int
-ospf6_lsa_add_hook (void *data)
-{
-  struct ospf6_lsa *lsa = data;
-  struct ospf6_lsa_slot *sp;
-
-  sp = ospf6_lsa_slot_get (lsa->header->type);
-  if (sp)
-    {
-      CALL_CHANGE_HOOK (&sp->database_hook, lsa);
-    }
-  else
-    zlog_warn ("Unknown LSA added to database: %s", lsa->str);
-  return 0;
-}
-
-int
-ospf6_lsa_change_hook (void *data)
-{
-  struct ospf6_lsa *lsa = data;
-  struct ospf6_lsa_slot *sp;
-
-  sp = ospf6_lsa_slot_get (lsa->header->type);
-  if (sp)
-    {
-      CALL_CHANGE_HOOK (&sp->database_hook, lsa);
-    }
-  else
-    zlog_warn ("Unknown LSA changed in database: %s", lsa->str);
-  return 0;
-}
-
-int
-ospf6_lsa_remove_hook (void *data)
-{
-  struct ospf6_lsa *lsa = data;
-  struct ospf6_lsa_slot *sp;
-
-  sp = ospf6_lsa_slot_get (lsa->header->type);
-  if (sp)
-    {
-      CALL_REMOVE_HOOK (&sp->database_hook, lsa);
-    }
-  else
-    zlog_warn ("Unknown LSA removed from database: %s", lsa->str);
-  return 0;
-}
-
-/* Initialize LSA slots */
 void
 ospf6_lsa_init ()
 {
-  struct ospf6_hook hook;
+  memset (ospf6_lstype, 0, sizeof (ospf6_lstype));
 
-  slot_head = NULL;
-  ospf6_lsa_slot_register_router ();
-  ospf6_lsa_slot_register_network ();
-  ospf6_lsa_slot_register_link ();
-#if 0
-  ospf6_lsa_slot_register_intra_prefix ();
-  ospf6_lsa_slot_register_as_external ();
-#endif /*0*/
-
-  hook.name = "LSADatabaseHook";
-  hook.hook_add = ospf6_lsa_add_hook;
-  hook.hook_change = ospf6_lsa_change_hook;
-  hook.hook_remove = ospf6_lsa_remove_hook;
-  ospf6_hook_register (&hook, &database_hook);
+  ospf6_lstype[0].name = "Unknown";
+  ospf6_lstype[0].reoriginate = ospf6_unknown_reoriginate;
+  ospf6_lstype[0].show = ospf6_unknown_show;
 }
 
+
+
+DEFUN (debug_ospf6_lsa_sendrecv,
+       debug_ospf6_lsa_sendrecv_cmd,
+       "debug ospf6 lsa (send|recv|originate|timer|database|memory|all)",
+       DEBUG_STR
+       OSPF6_STR
+       "Debug Link State Advertisements (LSAs)\n"
+       "Debug Sending LSAs\n"
+       "Debug Receiving LSAs\n"
+       "Debug Originating LSAs\n"
+       "Debug Timer Event of LSAs\n"
+       "Debug LSA Database\n"
+       "Debug Memory of LSAs\n"
+       "Debug LSAs all\n"
+      )
+{
+  unsigned char level = 0;
+
+  if (argc)
+    {
+      if (! strncmp (argv[0], "s", 1))
+        level = OSPF6_DEBUG_LSA_SEND;
+      else if (! strncmp (argv[0], "r", 1))
+        level = OSPF6_DEBUG_LSA_RECV;
+      else if (! strncmp (argv[0], "o", 1))
+        level = OSPF6_DEBUG_LSA_ORIGINATE;
+      else if (! strncmp (argv[0], "t", 1))
+        level = OSPF6_DEBUG_LSA_TIMER;
+      else if (! strncmp (argv[0], "d", 1))
+        level = OSPF6_DEBUG_LSA_DATABASE;
+      else if (! strncmp (argv[0], "m", 1))
+        level = OSPF6_DEBUG_LSA_MEMORY;
+      else if (! strncmp (argv[0], "a", 1))
+        {
+          level = OSPF6_DEBUG_LSA_SEND | OSPF6_DEBUG_LSA_RECV |
+                  OSPF6_DEBUG_LSA_ORIGINATE | OSPF6_DEBUG_LSA_TIMER |
+                  OSPF6_DEBUG_LSA_DATABASE | OSPF6_DEBUG_LSA_MEMORY;
+        }
+    }
+  else
+    {
+      level = OSPF6_DEBUG_LSA_SEND | OSPF6_DEBUG_LSA_RECV |
+              OSPF6_DEBUG_LSA_ORIGINATE | OSPF6_DEBUG_LSA_TIMER;
+    }
+
+  OSPF6_DEBUG_LSA_ON (level);
+  return CMD_SUCCESS;
+}
+
+ALIAS (debug_ospf6_lsa_sendrecv,
+       debug_ospf6_lsa_cmd,
+       "debug ospf6 lsa",
+       NO_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Debug Link State Advertisements (LSAs)\n"
+      );
+
+DEFUN (no_debug_ospf6_lsa_sendrecv,
+       no_debug_ospf6_lsa_sendrecv_cmd,
+       "no debug ospf6 lsa (send|recv|originate|timer|database|memory|all)",
+       NO_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Debug Link State Advertisements (LSAs)\n"
+       "Debug Sending LSAs\n"
+       "Debug Receiving LSAs\n"
+       "Debug Originating LSAs\n"
+       "Debug Timer Event of LSAs\n"
+       "Debug LSA Database\n"
+       "Debug Memory of LSAs\n"
+       "Debug LSAs all\n"
+      )
+{
+  unsigned char level = 0;
+
+  if (argc)
+    {
+      if (! strncmp (argv[0], "s", 1))
+        level = OSPF6_DEBUG_LSA_SEND;
+      else if (! strncmp (argv[0], "r", 1))
+        level = OSPF6_DEBUG_LSA_RECV;
+      else if (! strncmp (argv[0], "o", 1))
+        level = OSPF6_DEBUG_LSA_ORIGINATE;
+      else if (! strncmp (argv[0], "t", 1))
+        level = OSPF6_DEBUG_LSA_TIMER;
+      else if (! strncmp (argv[0], "d", 1))
+        level = OSPF6_DEBUG_LSA_DATABASE;
+      else if (! strncmp (argv[0], "m", 1))
+        level = OSPF6_DEBUG_LSA_MEMORY;
+      else if (! strncmp (argv[0], "a", 1))
+        {
+          level = OSPF6_DEBUG_LSA_SEND | OSPF6_DEBUG_LSA_RECV |
+                  OSPF6_DEBUG_LSA_ORIGINATE | OSPF6_DEBUG_LSA_TIMER |
+                  OSPF6_DEBUG_LSA_DATABASE | OSPF6_DEBUG_LSA_MEMORY;
+        }
+    }
+  else
+    {
+      level = OSPF6_DEBUG_LSA_SEND | OSPF6_DEBUG_LSA_RECV |
+              OSPF6_DEBUG_LSA_ORIGINATE | OSPF6_DEBUG_LSA_TIMER;
+    }
+
+  OSPF6_DEBUG_LSA_OFF (level);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_ospf6_lsa_sendrecv,
+       no_debug_ospf6_lsa_cmd,
+       "no debug ospf6 lsa",
+       NO_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Debug Link State Advertisements (LSAs)\n"
+      );
+
+int
+config_write_ospf6_debug_lsa (struct vty *vty)
+{
+  if (conf_debug_ospf6_lsa == OSPF6_DEBUG_LSA_ALL)
+    vty_out (vty, "debug ospf6 lsa all%s", VTY_NEWLINE);
+  else
+    {
+      if (conf_debug_ospf6_lsa == OSPF6_DEBUG_LSA_DEFAULT)
+        vty_out (vty, "debug ospf6 lsa%s", VTY_NEWLINE);
+      else
+        {
+          if (IS_OSPF6_DEBUG_LSA (SEND))
+            vty_out (vty, "debug ospf6 lsa send%s", VTY_NEWLINE);
+          if (IS_OSPF6_DEBUG_LSA (RECV))
+            vty_out (vty, "debug ospf6 lsa recv%s", VTY_NEWLINE);
+          if (IS_OSPF6_DEBUG_LSA (ORIGINATE))
+            vty_out (vty, "debug ospf6 lsa originate%s", VTY_NEWLINE);
+          if (IS_OSPF6_DEBUG_LSA (TIMER))
+            vty_out (vty, "debug ospf6 lsa timer%s", VTY_NEWLINE);
+        }
+
+      if (IS_OSPF6_DEBUG_LSA (DATABASE))
+        vty_out (vty, "debug ospf6 lsa database%s", VTY_NEWLINE);
+      if (IS_OSPF6_DEBUG_LSA (MEMORY))
+        vty_out (vty, "debug ospf6 lsa memory%s", VTY_NEWLINE);
+    }
+
+  return 0;
+}
+
+void
+install_element_ospf6_debug_lsa ()
+{
+  install_element (ENABLE_NODE, &debug_ospf6_lsa_cmd);
+  install_element (ENABLE_NODE, &debug_ospf6_lsa_sendrecv_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf6_lsa_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf6_lsa_sendrecv_cmd);
+  install_element (CONFIG_NODE, &debug_ospf6_lsa_cmd);
+  install_element (CONFIG_NODE, &debug_ospf6_lsa_sendrecv_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf6_lsa_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf6_lsa_sendrecv_cmd);
+}
+
+
diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h
index 02ad7c6..8b9d5f3 100644
--- a/ospf6d/ospf6_lsa.h
+++ b/ospf6d/ospf6_lsa.h
@@ -1,6 +1,5 @@
 /*
- * LSA function
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -23,176 +22,57 @@
 #ifndef OSPF6_LSA_H
 #define OSPF6_LSA_H
 
-#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)
+/* Debug option */
+extern unsigned char conf_debug_ospf6_lsa;
+#define OSPF6_DEBUG_LSA_SEND      0x01
+#define OSPF6_DEBUG_LSA_RECV      0x02
+#define OSPF6_DEBUG_LSA_ORIGINATE 0x04
+#define OSPF6_DEBUG_LSA_TIMER     0x08
+#define OSPF6_DEBUG_LSA_DATABASE  0x10
+#define OSPF6_DEBUG_LSA_MEMORY    0x80
+#define OSPF6_DEBUG_LSA_ALL       0x9f
+#define OSPF6_DEBUG_LSA_DEFAULT   0x0f
+#define OSPF6_DEBUG_LSA_ON(level) \
+  (conf_debug_ospf6_lsa |= (level))
+#define OSPF6_DEBUG_LSA_OFF(level) \
+  (conf_debug_ospf6_lsa &= ~(level))
+#define IS_OSPF6_DEBUG_LSA(e) \
+  (conf_debug_ospf6_lsa & OSPF6_DEBUG_LSA_ ## e)
 
 /* LSA definition */
 
-#define MAXLSASIZE   1024
-
-#define OSPF6_LSA_MAXAGE           3600    /* 1 hour */
-#define OSPF6_LSA_CHECKAGE         300     /* 5 min */
-#define OSPF6_LSA_MAXAGEDIFF       900     /* 15 min */
+#define OSPF6_MAX_LSASIZE      4096
 
 /* Type */
-#define OSPF6_LSA_TYPE_NONE             0x0000
-#define OSPF6_LSA_TYPE_ROUTER           0x2001
-#define OSPF6_LSA_TYPE_NETWORK          0x2002
-#define OSPF6_LSA_TYPE_INTER_PREFIX     0x2003
-#define OSPF6_LSA_TYPE_INTER_ROUTER     0x2004
-#define OSPF6_LSA_TYPE_AS_EXTERNAL      0x4005
-#define OSPF6_LSA_TYPE_GROUP_MEMBERSHIP 0x2006
-#define OSPF6_LSA_TYPE_TYPE_7           0x2007
-#define OSPF6_LSA_TYPE_LINK             0x0008
-#define OSPF6_LSA_TYPE_INTRA_PREFIX     0x2009
-#define OSPF6_LSA_TYPE_MAX              0x000a
-#define OSPF6_LSA_TYPE_SIZE             0x000b
+#define OSPF6_LSTYPE_UNKNOWN          0x0000
+#define OSPF6_LSTYPE_ROUTER           0x2001
+#define OSPF6_LSTYPE_NETWORK          0x2002
+#define OSPF6_LSTYPE_INTER_PREFIX     0x2003
+#define OSPF6_LSTYPE_INTER_ROUTER     0x2004
+#define OSPF6_LSTYPE_AS_EXTERNAL      0x4005
+#define OSPF6_LSTYPE_GROUP_MEMBERSHIP 0x2006
+#define OSPF6_LSTYPE_TYPE_7           0x2007
+#define OSPF6_LSTYPE_LINK             0x0008
+#define OSPF6_LSTYPE_INTRA_PREFIX     0x2009
+#define OSPF6_LSTYPE_SIZE             0x000a
 
 /* Masks for LS Type : RFC 2740 A.4.2.1 "LS type" */
 #define OSPF6_LSTYPE_UBIT_MASK        0x8000
 #define OSPF6_LSTYPE_SCOPE_MASK       0x6000
-#define OSPF6_LSTYPE_CODE_MASK        0x1fff
+#define OSPF6_LSTYPE_FCODE_MASK       0x1fff
 
-#define OSPF6_LSA_TYPESW_MASK         OSPF6_LSTYPE_CODE_MASK
-#define OSPF6_LSA_TYPESW(x) (ntohs((x)) & OSPF6_LSA_TYPESW_MASK)
-#define OSPF6_LSA_TYPESW_ISKNOWN(x) (OSPF6_LSA_TYPESW(x) < OSPF6_LSA_TYPE_MAX)
-
-/* lsa scope */
+/* LSA scope */
 #define OSPF6_LSA_SCOPE_LINKLOCAL  0x0000
 #define OSPF6_LSA_SCOPE_AREA       0x2000
 #define OSPF6_LSA_SCOPE_AS         0x4000
 #define OSPF6_LSA_SCOPE_RESERVED   0x6000
-#define OSPF6_LSA_IS_SCOPE_LINKLOCAL(x) \
-  (((x) & OSPF6_LSTYPE_SCOPE_MASK) == OSPF6_LSA_SCOPE_LINKLOCAL)
-#define OSPF6_LSA_IS_SCOPE_AREA(x) \
-  (((x) & OSPF6_LSTYPE_SCOPE_MASK) == OSPF6_LSA_SCOPE_AREA)
-#define OSPF6_LSA_IS_SCOPE_AS(x) \
-  (((x) & OSPF6_LSTYPE_SCOPE_MASK) == OSPF6_LSA_SCOPE_AS)
 
-/* NOTE that all LSAs are kept NETWORK BYTE ORDER */
-
-/* Router-LSA */
-struct ospf6_router_lsa
-{
-  u_char bits;
-  u_char options[3];
-  /* followed by ospf6_router_lsd(s) */
-};
-
-#define OSPF6_ROUTER_LSA_BIT_B     (1 << 0)
-#define OSPF6_ROUTER_LSA_BIT_E     (1 << 1)
-#define OSPF6_ROUTER_LSA_BIT_V     (1 << 2)
-#define OSPF6_ROUTER_LSA_BIT_W     (1 << 3)
-
-#define OSPF6_ROUTER_LSA_SET(x,y)    ((x)->bits |=  (y))
-#define OSPF6_ROUTER_LSA_ISSET(x,y)  ((x)->bits &   (y))
-#define OSPF6_ROUTER_LSA_CLEAR(x,y)  ((x)->bits &= ~(y))
-#define OSPF6_ROUTER_LSA_CLEAR_ALL_BITS(x)  ((x)->bits = 0)
-
-/* Link State Description in Router-LSA */
-struct ospf6_router_lsd
-{
-  u_char    type;
-  u_char    reserved;
-  u_int16_t metric;                /* output cost */
-  u_int32_t interface_id;
-  u_int32_t neighbor_interface_id;
-  u_int32_t neighbor_router_id;
-};
-
-#define OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT       1
-#define OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK    2
-#define OSPF6_ROUTER_LSD_TYPE_STUB_NETWORK       3
-#define OSPF6_ROUTER_LSD_TYPE_VIRTUAL_LINK       4
-
-/* Network-LSA */
-struct ospf6_network_lsa
-{
-  u_char reserved;
-  u_char options[3];
-  /* followed by ospf6_netowrk_lsd(s) */
-};
-
-/* Link State Description in Router-LSA */
-struct ospf6_network_lsd
-{
-  u_int32_t adv_router;
-};
-
-/* Link-LSA */
-struct ospf6_link_lsa
-{
-  u_char          llsa_rtr_pri;
-  u_char          llsa_options[3];
-  struct in6_addr llsa_linklocal;
-  u_int32_t       llsa_prefix_num;
-  /* followed by prefix(es) */
-};
-
-/* Intra-Area-Prefix-LSA */
-struct ospf6_intra_area_prefix_lsa
-{
-  u_int16_t prefix_number;
-  u_int16_t refer_lstype;
-  u_int32_t refer_lsid;
-  u_int32_t refer_advrtr;
-};
-
-/* AS-External-LSA */
-struct ospf6_as_external_lsa
-{
-  u_char    ase_bits;
-  u_char    ase_pre_metric; /* 1st byte of metric */
-  u_int16_t ase_metric;     /* 2nd, 3rd byte of metric */
-#if 1
-  struct ospf6_prefix ospf6_prefix;
-#else
-  u_char    ase_prefix_len;
-  u_char    ase_prefix_opt;
-  u_int16_t ase_refer_lstype;
-  /* followed by one address prefix */
-#endif
-  /* followed by none or one forwarding address */
-  /* followed by none or one external route tag */
-  /* followed by none or one referenced LS-ID */
-};
-#define ASE_LSA_BIT_T     (1 << 0)
-#define ASE_LSA_BIT_F     (1 << 1)
-#define ASE_LSA_BIT_E     (1 << 2)
-
-#define ASE_LSA_SET(x,y)    ((x)->ase_bits |=  (y))
-#define ASE_LSA_ISSET(x,y)  ((x)->ase_bits &   (y))
-#define ASE_LSA_CLEAR(x,y)  ((x)->ase_bits &= ~(y))
+#define OSPF6_LSA_SCOPE(type) \
+  (ntohs (type) & OSPF6_LSTYPE_SCOPE_MASK)
 
 /* LSA Header */
-struct ospf6_lsa_hdr
-{
-  u_int16_t lsh_age;      /* LS age */
-  u_int16_t lsh_type;     /* LS type */
-  u_int32_t lsh_id;       /* Link State ID */
-  u_int32_t lsh_advrtr;   /* Advertising Router */
-  u_int32_t lsh_seqnum;   /* LS sequence number */
-  u_int16_t lsh_cksum;    /* LS checksum */
-  u_int16_t lsh_len;      /* length */
-};
 struct ospf6_lsa_header
 {
-  u_int16_t age;       /* LS age */
-  u_int16_t type;      /* LS type */
-  u_int32_t ls_id;     /* Link State ID */
-  u_int32_t advrtr;    /* Advertising Router */
-  u_int32_t seqnum;    /* LS sequence number */
-  u_int16_t checksum;  /* LS checksum */
-  u_int16_t length;    /* LSA length */
-};
-struct ospf6_lsa_header__
-{
   u_int16_t age;        /* LS age */
   u_int16_t type;       /* LS type */
   u_int32_t id;         /* Link State ID */
@@ -202,225 +82,175 @@
   u_int16_t length;     /* LSA length */
 };
 
-#define OSPF6_LSA_NEXT(x) ((struct ospf6_lsa_header *) \
-                             ((char *)(x) + ntohs ((x)->length)))
-
-#define OSPF6_LSA_HEADER_END(header) \
-  ((void *)((char *)(header) + sizeof (struct ospf6_lsa_header)))
+#define OSPF6_LSA_HEADER_END(h) \
+  ((caddr_t)(h) + sizeof (struct ospf6_lsa_header))
+#define OSPF6_LSA_SIZE(h) \
+  (ntohs (((struct ospf6_lsa_header *) (h))->length))
+#define OSPF6_LSA_END(h) \
+  ((caddr_t)(h) + ntohs (((struct ospf6_lsa_header *) (h))->length))
+#define OSPF6_LSA_IS_TYPE(t, L) \
+  ((L)->header->type == htons (OSPF6_LSTYPE_ ## t) ? 1 : 0)
+#define OSPF6_LSA_IS_SAME(L1, L2) \
+  ((L1)->header->adv_router == (L2)->header->adv_router && \
+   (L1)->header->id == (L2)->header->id && \
+   (L1)->header->type == (L2)->header->type)
+#define OSPF6_LSA_IS_MATCH(t, i, a, L) \
+  ((L)->header->adv_router == (a) && (L)->header->id == (i) && \
+   (L)->header->type == (t))
+#define OSPF6_LSA_IS_DIFFER(L1, L2)  ospf6_lsa_is_differ (L1, L2)
+#define OSPF6_LSA_IS_MAXAGE(L) (ospf6_lsa_age_current (L) == MAXAGE)
+#define OSPF6_LSA_IS_CHANGED(L1, L2) ospf6_lsa_is_changed (L1, L2)
 
 struct ospf6_lsa
 {
-  char                   str[256];  /* dump string */
+  char                 name[64];   /* dump string */
 
-  u_long                 lock;      /* reference counter */
-  int                    summary;   /* indicate this is LS header only */
-  void                  *scope;     /* pointer of scoped data structure */
-  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 */
+  struct ospf6_lsa    *prev;
+  struct ospf6_lsa    *next;
+
+  unsigned char        lock;       /* reference counter */
+  unsigned char        flag;       /* special meaning (e.g. floodback) */
+
+  struct timeval       birth;      /* tv_sec when LS age 0 */
+  struct timeval       installed;  /* used by MinLSArrival check */
+  struct timeval       originated; /* used by MinLSInterval check */
+
+  struct thread       *expire;
+  struct thread       *refresh;    /* For self-originated LSA */
+
+  void                *scope;      /* pointer to scope data structure */
+  int                  headeronly; /* indicate this is LS header only */
+
+  unsigned long        refcnt;
+  struct ospf6_lsa    *refsrc;
 
   /* lsa instance */
-  struct ospf6_lsa_hdr  *lsa_hdr;
-  struct ospf6_lsa_header__ *header;
-
-  /* statistics */
-  u_long turnover_num;
-  u_long turnover_total;
-  u_long turnover_min;
-  u_long turnover_max;
+  struct ospf6_lsa_header *header;
 };
 
-struct ospf6_lsa_slot
+#define OSPF6_LSA_FLOODBACK  0x01
+#define OSPF6_LSA_DUPLICATE  0x02
+#define OSPF6_LSA_IMPLIEDACK 0x04
+#define OSPF6_LSA_REFRESH    0x08
+
+struct ospf6_lstype
 {
-  struct ospf6_lsa_slot *prev;
-  struct ospf6_lsa_slot *next;
-
-  u_int16_t  type;
-  char      *name;
-
-  int (*func_print)        (struct ospf6_lsa *lsa);
-  int (*func_show)         (struct vty *vty, struct ospf6_lsa *lsa);
-  int (*func_refresh)      (void *lsa);
-
-  int (*database_add)      (void *lsa);
-  int (*database_remove)   (void *lsa);
-
-  struct ospf6_hook_master database_hook;
-
-  struct ospf6_hook hook_neighbor;
-  struct ospf6_hook hook_interface;
-  struct ospf6_hook hook_area;
-  struct ospf6_hook hook_top;
-  struct ospf6_hook hook_database;
-  struct ospf6_hook hook_route;
+  char *name;
+  int (*reoriginate) (struct ospf6_lsa *);
+  int (*show) (struct vty *, struct ospf6_lsa *);
 };
 
-#define OSPF6_LSA_FLAG_FLOODBACK  0x01
-#define OSPF6_LSA_FLAG_DUPLICATE  0x02
-#define OSPF6_LSA_FLAG_IMPLIEDACK 0x04
-#define OSPF6_LSA_FLAG_REFRESH    0x08
+extern struct ospf6_lstype ospf6_lstype[OSPF6_LSTYPE_SIZE];
+#define OSPF6_LSTYPE_INDEX(type) \
+  (((type) & OSPF6_LSTYPE_FCODE_MASK) < OSPF6_LSTYPE_SIZE ? \
+   ((type) & OSPF6_LSTYPE_FCODE_MASK) : OSPF6_LSTYPE_UNKNOWN)
 
-/* Back pointer check, Is X's reference field bound to Y ? */
-#define x_ipl(x) ((struct intra_area_prefix_lsa *)LSH_NEXT((x)->lsa_hdr))
-#define is_reference_network_ok(x,y) \
-          ((x_ipl(x))->intra_prefix_refer_lstype == (y)->lsa_hdr->lsh_type &&\
-           (x_ipl(x))->intra_prefix_refer_lsid == (y)->lsa_hdr->lsh_id &&\
-           (x_ipl(x))->intra_prefix_refer_advrtr == (y)->lsa_hdr->lsh_advrtr)
-  /* referencing router's ifid must be 0,
-     see draft-ietf-ospf-ospfv6-06.txt */
-#define is_reference_router_ok(x,y) \
-          ((x_ipl(x))->intra_prefix_refer_lstype == (y)->lsa_hdr->lsh_type &&\
-           (x_ipl(x))->intra_prefix_refer_lsid == htonl (0) &&\
-           (x_ipl(x))->intra_prefix_refer_advrtr == (y)->lsa_hdr->lsh_advrtr)
+#if 0
+extern char *ospf6_lstype_str[OSPF6_LSTYPE_SIZE];
+#define OSPF6_LSTYPE_NAME(type) \
+  ((ntohs (type) & OSPF6_LSTYPE_FCODE_MASK) < OSPF6_LSTYPE_SIZE ? \
+   ospf6_lstype_str[ntohs (type) & OSPF6_LSTYPE_FCODE_MASK] :     \
+   ospf6_lstype_str[OSPF6_LSTYPE_UNKNOWN])
+#else /*0*/
+#define OSPF6_LSTYPE_NAME(type) (ospf6_lstype_name (type))
+#endif /*0*/
 
-/* MaxAge check.  */
-/* ospf6_lsa_is_maxage (struct ospf6_lsa *lsa) */
-#define IS_LSA_MAXAGE(L)      (ospf6_lsa_age_current (L) == OSPF6_LSA_MAXAGE)
+/* Macro for LSA Origination */
+/* void (CONTINUE_IF_...) (struct prefix *addr); */
 
-struct ospf6_lsa_slot *ospf6_lsa_slot_get (u_int16_t type);
-int ospf6_lsa_slot_register (struct ospf6_lsa_slot *src);
-int ospf6_lsa_slot_unregister (u_int16_t type);
-
-extern struct ospf6_lsa_slot *slot_head;
-#define CALL_FOREACH_LSA_HOOK(hook,func,data) \
-  if (ospf6)\
-    {\
-      struct ospf6_lsa_slot *slot;\
-      for (slot = slot_head; slot; slot = slot->next)\
-        {\
-          if (slot->hook.func)\
-            (*slot->hook.func) (data);\
-        }\
-    }
-#define CALL_LSA_FUNC(type,func,data) \
-  if (ospf6)\
-    {\
-      struct ospf6_lsa_slot *slot;\
-      slot = ospf6_lsa_slot_get (type);\
-      if (slot && slot->func)\
-        {\
-          (*slot->func) (data);\
-        }\
-      else\
-        {\
-          zlog_warn ("LSA: No slot for type %#x: %s line:%d",\
-                     ntohs (type), __FILE__, __LINE__);\
-        }\
+#define CONTINUE_IF_ADDRESS_LINKLOCAL(addr)\
+  if (IN6_IS_ADDR_LINKLOCAL (&(addr)->u.prefix6))      \
+    {                                                  \
+      char buf[64];                                    \
+      prefix2str (addr, buf, sizeof (buf));            \
+      if (IS_OSPF6_DEBUG_LSA (ORIGINATE))              \
+        zlog_info ("Filter out Linklocal: %s", buf);   \
+      continue;                                        \
     }
 
-#define CALL_LSA_DATABASE_ADD(type,data) \
-  if (ospf6)\
-    {\
-      struct ospf6_lsa_slot *slot;\
-      slot = ospf6_lsa_slot_get (type);\
-      if (slot)\
-        {\
-          CALL_ADD_HOOK (&slot->database_hook, data);\
-        }\
-      else\
-        {\
-          zlog_warn ("LSA: No slot for type %#x: %s line:%d",\
-                     ntohs (type), __FILE__, __LINE__);\
-        }\
-    }
-#define CALL_LSA_DATABASE_CHANGE(type,data) \
-  if (ospf6)\
-    {\
-      struct ospf6_lsa_slot *slot;\
-      slot = ospf6_lsa_slot_get (type);\
-      if (slot)\
-        {\
-          CALL_CHANGE_HOOK (&slot->database_hook, data);\
-        }\
-      else\
-        {\
-          zlog_warn ("LSA: No slot for type %#x: %s line:%d",\
-                     ntohs (type), __FILE__, __LINE__);\
-        }\
-    }
-#define CALL_LSA_DATABASE_REMOVE(type,data) \
-  if (ospf6)\
-    {\
-      struct ospf6_lsa_slot *slot;\
-      slot = ospf6_lsa_slot_get (type);\
-      if (slot)\
-        {\
-          CALL_REMOVE_HOOK (&slot->database_hook, data);\
-        }\
-      else\
-        {\
-          zlog_warn ("LSA: No slot for type %#x: %s line:%d",\
-                     ntohs (type), __FILE__, __LINE__);\
-        }\
+#define CONTINUE_IF_ADDRESS_UNSPECIFIED(addr)          \
+  if (IN6_IS_ADDR_UNSPECIFIED (&(addr)->u.prefix6))    \
+    {                                                  \
+      char buf[64];                                    \
+      prefix2str (addr, buf, sizeof (buf));            \
+      if (IS_OSPF6_DEBUG_LSA (ORIGINATE))              \
+        zlog_info ("Filter out Unspecified: %s", buf); \
+      continue;                                        \
     }
 
-void ospf6_lsa_init ();
+#define CONTINUE_IF_ADDRESS_LOOPBACK(addr)             \
+  if (IN6_IS_ADDR_LOOPBACK (&(addr)->u.prefix6))       \
+    {                                                  \
+      char buf[64];                                    \
+      prefix2str (addr, buf, sizeof (buf));            \
+      if (IS_OSPF6_DEBUG_LSA (ORIGINATE))              \
+        zlog_info ("Filter out Loopback: %s", buf);    \
+      continue;                                        \
+    }
 
+#define CONTINUE_IF_ADDRESS_V4COMPAT(addr)             \
+  if (IN6_IS_ADDR_V4COMPAT (&(addr)->u.prefix6))       \
+    {                                                  \
+      char buf[64];                                    \
+      prefix2str (addr, buf, sizeof (buf));            \
+      if (IS_OSPF6_DEBUG_LSA (ORIGINATE))              \
+        zlog_info ("Filter out V4Compat: %s", buf);    \
+      continue;                                        \
+    }
+
+#define CONTINUE_IF_ADDRESS_V4MAPPED(addr)             \
+  if (IN6_IS_ADDR_V4MAPPED (&(addr)->u.prefix6))       \
+    {                                                  \
+      char buf[64];                                    \
+      prefix2str (addr, buf, sizeof (buf));            \
+      if (IS_OSPF6_DEBUG_LSA (ORIGINATE))              \
+        zlog_info ("Filter out V4Mapped: %s", buf);    \
+      continue;                                        \
+    }
+
+
 /* Function Prototypes */
+char *ospf6_lstype_name (u_int16_t type);
+int ospf6_lsa_is_differ (struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2);
+int ospf6_lsa_is_changed (struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2);
+u_int16_t ospf6_lsa_age_current (struct ospf6_lsa *);
+void ospf6_lsa_age_update_to_send (struct ospf6_lsa *, u_int32_t);
+void ospf6_lsa_premature_aging (struct ospf6_lsa *);
+int ospf6_lsa_compare (struct ospf6_lsa *, struct ospf6_lsa *);
 
-struct router_lsd *
-get_router_lsd (u_int32_t, struct ospf6_lsa *);
-unsigned long get_ifindex_to_router (u_int32_t, struct ospf6_lsa *);
+char *ospf6_lsa_printbuf (struct ospf6_lsa *lsa, char *buf, int size);
+void ospf6_lsa_header_print_raw (struct ospf6_lsa_header *header);
+void ospf6_lsa_header_print (struct ospf6_lsa *lsa);
+void ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa);
+void ospf6_lsa_show_summary_header (struct vty *vty);
+void ospf6_lsa_show_summary (struct vty *vty, struct ospf6_lsa *lsa);
+void ospf6_lsa_show_dump (struct vty *vty, struct ospf6_lsa *lsa);
+void ospf6_lsa_show_internal (struct vty *vty, struct ospf6_lsa *lsa);
 
-int ospf6_lsa_differ (struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2);
-int ospf6_lsa_match (u_int16_t, u_int32_t, u_int32_t,
-                     struct ospf6_lsa_header *);
+u_int32_t ospf6_lsa_new_seqnum (u_int16_t type, u_int32_t id,
+                                u_int32_t adv_router, void *scope);
 
-void ospf6_lsa_show (struct vty *, struct ospf6_lsa *);
-void ospf6_lsa_show_dump (struct vty *, struct ospf6_lsa *);
-void ospf6_lsa_show_summary (struct vty *, struct ospf6_lsa *);
-void ospf6_lsa_show_summary_header (struct vty *);
-
-struct ospf6_lsa *
-ospf6_lsa_create (struct ospf6_lsa_header *);
-struct ospf6_lsa *
-ospf6_lsa_summary_create (struct ospf6_lsa_header__ *);
-void
-ospf6_lsa_delete (struct ospf6_lsa *);
+struct ospf6_lsa *ospf6_lsa_create (struct ospf6_lsa_header *header);
+struct ospf6_lsa *ospf6_lsa_create_headeronly (struct ospf6_lsa_header *header);
+void ospf6_lsa_delete (struct ospf6_lsa *lsa);
+struct ospf6_lsa *ospf6_lsa_copy (struct ospf6_lsa *);
 
 void ospf6_lsa_lock (struct ospf6_lsa *);
 void ospf6_lsa_unlock (struct ospf6_lsa *);
 
-unsigned short ospf6_lsa_age_current (struct ospf6_lsa *);
-int ospf6_lsa_is_maxage (struct ospf6_lsa *);
-void ospf6_lsa_age_update_to_send (struct ospf6_lsa *, u_int32_t);
-void ospf6_lsa_premature_aging (struct ospf6_lsa *);
-
-int ospf6_lsa_check_recent (struct ospf6_lsa *, struct ospf6_lsa *);
-
-int
-ospf6_lsa_lsd_num (struct ospf6_lsa_header *lsa_header);
-void *
-ospf6_lsa_lsd_get (int index, struct ospf6_lsa_header *lsa_header);
-int
-ospf6_lsa_lsd_is_refer_ok (int index1, struct ospf6_lsa_header *lsa_header1,
-                           int index2, struct ospf6_lsa_header *lsa_header2);
-
+void ospf6_lsa_originate (struct ospf6_lsa *);
+void ospf6_lsa_re_originate (struct ospf6_lsa *lsa);
 int ospf6_lsa_expire (struct thread *);
 int ospf6_lsa_refresh (struct thread *);
 
-u_short ospf6_lsa_checksum (struct ospf6_lsa_header *);
+unsigned short ospf6_lsa_checksum (struct ospf6_lsa_header *);
+int ospf6_lsa_prohibited_duration (u_int16_t type, u_int32_t id,
+                                   u_int32_t adv_router, void *scope);
 
-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_init ();
 
-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 *);
+int config_write_ospf6_debug_lsa (struct vty *vty);
+void install_element_ospf6_debug_lsa ();
 
 #endif /* OSPF6_LSA_H */
 
diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c
index ad53eb4..97a278e 100644
--- a/ospf6d/ospf6_lsdb.c
+++ b/ospf6d/ospf6_lsdb.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2002 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -24,24 +24,14 @@
 #include "memory.h"
 #include "log.h"
 #include "command.h"
-#include "if.h"
+#include "prefix.h"
+#include "table.h"
 
-#include "ospf6_dump.h"
+#include "ospf6d.h"
+#include "ospf6_proto.h"
+#include "ospf6_lsa.h"
 #include "ospf6_lsdb.h"
 
-#include "ospf6_interface.h"
-#include "ospf6_area.h"
-#include "ospf6_top.h"
-
-#define OSPF6_LSDB_MATCH_TYPE        0x01
-#define OSPF6_LSDB_MATCH_ID          0x02
-#define OSPF6_LSDB_MATCH_ADV_ROUTER  0x04
-#define OSPF6_LSDB_SHOW_DUMP         0x08
-#define OSPF6_LSDB_SHOW_DETAIL       0x10
-
-struct ospf6_lsdb_hook_t hooks[0x2000];
-struct ospf6_lsdb_hook_t *ospf6_lsdb_hook = hooks;
-
 struct ospf6_lsdb *
 ospf6_lsdb_create ()
 {
@@ -68,656 +58,351 @@
 }
 
 static void
-ospf6_lsdb_set_key (struct prefix_ipv6 *key, int flag,
-                    u_int16_t type, u_int32_t id, u_int32_t adv_router)
+ospf6_lsdb_set_key (struct prefix_ipv6 *key, void *value, int len)
 {
-  int len = 0;
-  memset (key, 0, sizeof (struct prefix_ipv6));
+  assert (key->prefixlen % 8 == 0);
 
-  if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_TYPE))
-    {
-      len += 2;
-      if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_ADV_ROUTER))
-        {
-          len += 4;
-          if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_ID))
-            len += 4;
-        }
-    }
-
-  if (len > 0)
-    memcpy ((char *)&key->prefix, &type, 2);
-  if (len > 2)
-    memcpy ((char *)&key->prefix + 2, &adv_router, 4);
-  if (len > 6)
-    memcpy ((char *)&key->prefix + 6, &id, 4);
-
+  memcpy ((caddr_t) &key->prefix + key->prefixlen / 8,
+          (caddr_t) value, len);
   key->family = AF_INET6;
-  key->prefixlen = len * 8;
+  key->prefixlen += len * 8;
 }
 
+#ifndef NDEBUG
+static void
+_lsdb_count_assert (struct ospf6_lsdb *lsdb)
+{
+  struct ospf6_lsa *debug;
+  int num = 0;
+  for (debug = ospf6_lsdb_head (lsdb); debug;
+       debug = ospf6_lsdb_next (debug))
+    num++;
+
+  if (num == lsdb->count)
+    return;
+
+  if (IS_OSPF6_DEBUG_LSA (DATABASE))
+    {
+      zlog_info ("PANIC !! lsdb[%p]->count = %d, real = %d",
+                 lsdb, lsdb->count, num);
+      for (debug = ospf6_lsdb_head (lsdb); debug;
+           debug = ospf6_lsdb_next (debug))
+        zlog_info ("%p %p %s", debug->prev, debug->next, debug->name);
+      zlog_info ("DUMP END");
+    }
+  assert (num == lsdb->count);
+}
+#define ospf6_lsdb_count_assert(t) (_lsdb_count_assert (t))
+#else /*NDEBUG*/
+#define ospf6_lsdb_count_assert(t) ((void) 0)
+#endif /*NDEBUG*/
+
 void
 ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb)
 {
-  int flag;
   struct prefix_ipv6 key;
-  struct route_node *rn;
-  struct ospf6_lsa *old = NULL;
+  struct route_node *current, *nextnode, *prevnode;
+  struct ospf6_lsa *next, *prev, *old = NULL;
 
-  flag = OSPF6_LSDB_MATCH_TYPE | OSPF6_LSDB_MATCH_ID |
-         OSPF6_LSDB_MATCH_ADV_ROUTER;
-  ospf6_lsdb_set_key (&key, flag, lsa->header->type, lsa->header->id,
-                      lsa->header->adv_router);
+  memset (&key, 0, sizeof (key));
+  ospf6_lsdb_set_key (&key, &lsa->header->type, sizeof (lsa->header->type));
+  ospf6_lsdb_set_key (&key, &lsa->header->adv_router,
+                      sizeof (lsa->header->adv_router));
+  ospf6_lsdb_set_key (&key, &lsa->header->id, sizeof (lsa->header->id));
 
-  rn = route_node_get (lsdb->table, (struct prefix *) &key);
-  if (rn->info)
-    old = rn->info;
-  rn->info = lsa;
+  current = route_node_get (lsdb->table, (struct prefix *) &key);
+  old = current->info;
+  current->info = lsa;
   ospf6_lsa_lock (lsa);
 
   if (old)
-    ospf6_lsa_unlock (old);
+    {
+      if (old->prev)
+        old->prev->next = lsa;
+      if (old->next)
+        old->next->prev = lsa;
+      lsa->next = old->next;
+      lsa->prev = old->prev;
+    }
   else
-    lsdb->count++;
+    {
+      /* next link */
+      nextnode = current;
+      route_lock_node (nextnode);
+      do {
+        nextnode = route_next (nextnode);
+      } while (nextnode && nextnode->info == NULL);
+      if (nextnode == NULL)
+        lsa->next = NULL;
+      else
+        {
+          next = nextnode->info;
+          lsa->next = next;
+          next->prev = lsa;
+          route_unlock_node (nextnode);
+        }
+
+      /* prev link */
+      prevnode = current;
+      route_lock_node (prevnode);
+      do {
+        prevnode = route_prev (prevnode);
+      } while (prevnode && prevnode->info == NULL);
+      if (prevnode == NULL)
+        lsa->prev = NULL;
+      else
+        {
+          prev = prevnode->info;
+          lsa->prev = prev;
+          prev->next = lsa;
+          route_unlock_node (prevnode);
+        }
+
+      lsdb->count++;
+    }
+
+  if (old)
+    {
+      if (OSPF6_LSA_IS_CHANGED (old, lsa))
+        {
+          if (OSPF6_LSA_IS_MAXAGE (lsa))
+            {
+              if (lsdb->hook_remove)
+                {
+                  (*lsdb->hook_remove) (old);
+                  (*lsdb->hook_remove) (lsa);
+                }
+            }
+          else
+            {
+              if (lsdb->hook_remove)
+                (*lsdb->hook_remove) (old);
+              if (lsdb->hook_add)
+                (*lsdb->hook_add) (lsa);
+            }
+        }
+    }
+  else if (OSPF6_LSA_IS_MAXAGE (lsa))
+    {
+      if (lsdb->hook_remove)
+        (*lsdb->hook_remove) (lsa);
+    }
+  else
+    {
+      if (lsdb->hook_add)
+        (*lsdb->hook_add) (lsa);
+    }
+
+  if (old)
+    ospf6_lsa_unlock (old);
+
+  ospf6_lsdb_count_assert (lsdb);
 }
 
 void
 ospf6_lsdb_remove (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb)
 {
-  int flag;
+  struct route_node *node;
   struct prefix_ipv6 key;
-  struct route_node *rn;
-  struct ospf6_lsa *old;
 
-  flag = OSPF6_LSDB_MATCH_TYPE | OSPF6_LSDB_MATCH_ID |
-         OSPF6_LSDB_MATCH_ADV_ROUTER;
-  ospf6_lsdb_set_key (&key, flag, lsa->header->type, lsa->header->id,
-                      lsa->header->adv_router);
+  memset (&key, 0, sizeof (key));
+  ospf6_lsdb_set_key (&key, &lsa->header->type, sizeof (lsa->header->type));
+  ospf6_lsdb_set_key (&key, &lsa->header->adv_router,
+                      sizeof (lsa->header->adv_router));
+  ospf6_lsdb_set_key (&key, &lsa->header->id, sizeof (lsa->header->id));
 
-  rn = route_node_lookup (lsdb->table, (struct prefix *) &key);
-  if (! rn || ! rn->info)
-    {
-      zlog_warn ("LSDB: Can't remove: no such LSA: %s", lsa->str);
-      return;
-    }
+  node = route_node_lookup (lsdb->table, (struct prefix *) &key);
+  assert (node && node->info == lsa);
 
-  old = rn->info;
-  if (old != lsa)
-    {
-      zlog_warn ("LSDB: Can't remove: different instance: %s (%p <-> %p) %s",
-                 lsa->str, lsa, old, old->str);
-      return;
-    }
+  if (lsa->prev)
+    lsa->prev->next = lsa->next;
+  if (lsa->next)
+    lsa->next->prev = lsa->prev;
 
-  rn->info = NULL;
-  ospf6_lsa_unlock (old);
+  node->info = NULL;
   lsdb->count--;
-}
 
-static void
-ospf6_lsdb_lookup_node (struct ospf6_lsdb_node *node,
-                        u_int16_t type, u_int32_t id, u_int32_t adv_router,
-                        struct ospf6_lsdb *lsdb)
-{
-  int flag;
-  struct route_node *rn;
+  if (lsdb->hook_remove)
+    (*lsdb->hook_remove) (lsa);
 
-  memset (node, 0, sizeof (struct ospf6_lsdb_node));
-
-  flag = OSPF6_LSDB_MATCH_TYPE | OSPF6_LSDB_MATCH_ID |
-         OSPF6_LSDB_MATCH_ADV_ROUTER;
-  ospf6_lsdb_set_key (&node->key, flag, type, id, adv_router);
-
-  rn = route_node_lookup (lsdb->table, (struct prefix *) &node->key);
-  if (! rn || ! rn->info)
-    return;
-
-  node->node = rn;
-  node->next = route_next (rn);
-  node->lsa = rn->info;
-  if (node->next != NULL)
-    route_unlock_node (node->next);
-}
-
-struct ospf6_lsa *
-ospf6_lsdb_lookup_lsdb (u_int16_t type, u_int32_t id, u_int32_t adv_router,
-                        struct ospf6_lsdb *lsdb)
-{
-  struct ospf6_lsdb_node node;
-  ospf6_lsdb_lookup_node (&node, type, id, adv_router, lsdb);
-  return node.lsa;
-}
-
-/* Iteration function */
-void
-ospf6_lsdb_head (struct ospf6_lsdb_node *node, struct ospf6_lsdb *lsdb)
-{
-  struct route_node *rn;
-
-  memset (node, 0, sizeof (struct ospf6_lsdb_node));
-
-  rn = route_top (lsdb->table);
-  if (rn == NULL)
-    return;
-
-  while (rn && rn->info == NULL)
-    rn = route_next (rn);
-
-  if (rn && rn->info)
-    {
-      node->node = rn;
-      node->next = route_next (rn);
-      node->lsa = rn->info;
-      if (node->next != NULL)
-        route_unlock_node (node->next);
-    }
-}
-
-void
-ospf6_lsdb_type (struct ospf6_lsdb_node *node, u_int16_t type,
-                 struct ospf6_lsdb *lsdb)
-{
-  int flag;
-  struct route_node *rn;
-
-  memset (node, 0, sizeof (struct ospf6_lsdb_node));
-
-  flag = OSPF6_LSDB_MATCH_TYPE;
-  ospf6_lsdb_set_key (&node->key, flag, type, 0, 0);
-
-  /* get the closest radix node */
-  rn = route_node_get (lsdb->table, (struct prefix *) &node->key);
-
-  /* skip to the real existing lsdb entry */
-  while (rn && rn->info == NULL && rn->p.prefixlen >= node->key.prefixlen &&
-         prefix_match ((struct prefix *) &node->key, &rn->p))
-    rn = route_next (rn);
-
-  if (rn && rn->info)
-    {
-      node->node = rn;
-      node->next = route_next (rn);
-      node->lsa = rn->info;
-      if (node->next != NULL)
-        route_unlock_node (node->next);
-    }
-}
-
-void
-ospf6_lsdb_type_router (struct ospf6_lsdb_node *node,
-                        u_int16_t type, u_int32_t adv_router,
-                        struct ospf6_lsdb *lsdb)
-{
-  int flag;
-  struct route_node *rn;
-
-  memset (node, 0, sizeof (struct ospf6_lsdb_node));
-
-  flag = OSPF6_LSDB_MATCH_TYPE | OSPF6_LSDB_MATCH_ADV_ROUTER;
-  ospf6_lsdb_set_key (&node->key, flag, type, 0, adv_router);
-
-  /* get the closest radix node */
-  rn = route_node_get (lsdb->table, (struct prefix *) &node->key);
-
-  /* skip to the real existing lsdb entry */
-  while (rn && rn->info == NULL && rn->p.prefixlen >= node->key.prefixlen &&
-         prefix_match ((struct prefix *) &node->key, &rn->p))
-    rn = route_next (rn);
-
-  if (rn && rn->info)
-    {
-      node->node = rn;
-      node->next = route_next (rn);
-      node->lsa = rn->info;
-      if (node->next != NULL)
-        route_unlock_node (node->next);
-    }
-}
-
-void
-ospf6_lsdb_next (struct ospf6_lsdb_node *node)
-{
-  struct route_node *rn;
-
-  route_lock_node (node->node);
-  rn = route_next (node->node);
-
-  /* skip to the real existing lsdb entry */
-  while (rn && rn->info == NULL && rn->p.prefixlen >= node->key.prefixlen &&
-         prefix_match ((struct prefix *) &node->key, &rn->p))
-    rn = route_next (rn);
-
-  if (rn && rn->info && rn->p.prefixlen >= node->key.prefixlen &&
-      prefix_match ((struct prefix *) &node->key, &rn->p))
-    {
-      node->node = rn;
-      node->next = route_next (rn);
-      node->lsa = rn->info;
-      if (node->next != NULL)
-        route_unlock_node (node->next);
-    }
-  else
-    {
-      node->node = NULL;
-      node->next = NULL;
-      node->lsa = NULL;
-    }
+  ospf6_lsa_unlock (lsa);
+  route_unlock_node (node);
+  ospf6_lsdb_count_assert (lsdb);
 }
 
 struct ospf6_lsa *
 ospf6_lsdb_lookup (u_int16_t type, u_int32_t id, u_int32_t adv_router,
-                   void *scope)
+                   struct ospf6_lsdb *lsdb)
 {
-  struct ospf6_interface *o6i;
-  struct ospf6_area *o6a;
-  listnode i, j;
+  struct route_node *node;
+  struct prefix_ipv6 key;
 
-  if (scope == (void *) ospf6)
-    return ospf6_lsdb_lookup_lsdb (type, id, adv_router, ospf6->lsdb);
+  if (lsdb == NULL)
+    return NULL;
 
-  for (i = listhead (ospf6->area_list); i; nextnode (i))
-    {
-      o6a = getdata (i);
+  memset (&key, 0, sizeof (key));
+  ospf6_lsdb_set_key (&key, &type, sizeof (type));
+  ospf6_lsdb_set_key (&key, &adv_router, sizeof (adv_router));
+  ospf6_lsdb_set_key (&key, &id, sizeof (id));
 
-      if (scope == (void *) o6a)
-        return ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6a->lsdb);
-
-      for (j = listhead (o6a->if_list); j; nextnode (j))
-        {
-          o6i = getdata (j);
-
-          if (scope == (void *) o6i)
-            return ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6i->lsdb);
-        }
-    }
-
-  zlog_warn ("LSDB: Can't lookup: unknown scope, type %#hx", ntohs (type));
-  return NULL;
+  node = route_node_lookup (lsdb->table, (struct prefix *) &key);
+  if (node == NULL || node->info == NULL)
+    return NULL;
+  return (struct ospf6_lsa *) node->info;
 }
 
-void
-ospf6_lsdb_install (struct ospf6_lsa *new)
+/* Iteration function */
+struct ospf6_lsa *
+ospf6_lsdb_head (struct ospf6_lsdb *lsdb)
 {
-  struct ospf6_lsdb *lsdb;
-  struct ospf6_lsa *old;
-  int need_hook = 0;
-  void (*hook) (struct ospf6_lsa *, struct ospf6_lsa *);
+  struct route_node *node;
 
-  struct ospf6 *as = NULL;
-  struct ospf6_area *area = NULL;
-  struct ospf6_interface *linklocal = NULL;
-  hook = NULL;
+  node = route_top (lsdb->table);
+  if (node == NULL)
+    return NULL;
 
-  switch (ntohs (new->header->type) & OSPF6_LSTYPE_SCOPE_MASK)
+  /* skip to the existing lsdb entry */
+  while (node && node->info == NULL)
+    node = route_next (node);
+  if (node == NULL)
+    return NULL;
+
+  route_unlock_node (node);
+  if (node->info)
+    ospf6_lsa_lock ((struct ospf6_lsa *) node->info);
+  return (struct ospf6_lsa *) node->info;
+}
+
+struct ospf6_lsa *
+ospf6_lsdb_next (struct ospf6_lsa *lsa)
+{
+  struct ospf6_lsa *next = lsa->next;
+
+  ospf6_lsa_unlock (lsa);
+  if (next)
+    ospf6_lsa_lock (next);
+
+  return next;
+}
+
+/* Macro version of check_bit (). */
+#define CHECK_BIT(X,P) ((((u_char *)(X))[(P) / 8]) >> (7 - ((P) % 8)) & 1)
+
+struct ospf6_lsa *
+ospf6_lsdb_type_router_head (u_int16_t type, u_int32_t adv_router,
+                             struct ospf6_lsdb *lsdb)
+{
+  struct route_node *node;
+  struct prefix_ipv6 key;
+  struct ospf6_lsa *lsa;
+
+  memset (&key, 0, sizeof (key));
+  ospf6_lsdb_set_key (&key, &type, sizeof (type));
+  ospf6_lsdb_set_key (&key, &adv_router, sizeof (adv_router));
+
+  node = lsdb->table->top;
+
+  /* Walk down tree. */
+  while (node && node->p.prefixlen <= key.prefixlen &&
+	 prefix_match (&node->p, (struct prefix *) &key))
+    node = node->link[CHECK_BIT(&key.prefix, node->p.prefixlen)];
+
+  if (node)
+    route_lock_node (node);
+  while (node && node->info == NULL)
+    node = route_next (node);
+
+  if (node == NULL)
+    return NULL;
+  else
+    route_unlock_node (node);
+
+  if (! prefix_match ((struct prefix *) &key, &node->p))
+    return NULL;
+
+  lsa = node->info;
+  ospf6_lsa_lock (lsa);
+
+  return lsa;
+}
+
+struct ospf6_lsa *
+ospf6_lsdb_type_router_next (u_int16_t type, u_int32_t adv_router,
+                             struct ospf6_lsa *lsa)
+{
+  struct ospf6_lsa *next = lsa->next;
+
+  if (next)
     {
-      case OSPF6_LSA_SCOPE_LINKLOCAL:
-        linklocal = (struct ospf6_interface *) new->scope;
-        lsdb = linklocal->lsdb;
-        break;
-      case OSPF6_LSA_SCOPE_AREA:
-        area = (struct ospf6_area *) new->scope;
-        lsdb = area->lsdb;
-        break;
-      case OSPF6_LSA_SCOPE_AS:
-        as = (struct ospf6 *) new->scope;
-        lsdb = as->lsdb;
-        break;
-      default:
-        zlog_warn ("LSDB: Can't install: scope unknown: %s", new->str);
-        return;
+      if (next->header->type != type ||
+          next->header->adv_router != adv_router)
+        next = NULL;
     }
 
-  /* whether schedule calculation or not */
-  old = ospf6_lsdb_lookup_lsdb (new->header->type, new->header->id,
-                                new->header->adv_router, lsdb);
+  if (next)
+    ospf6_lsa_lock (next);
+  ospf6_lsa_unlock (lsa);
+  return next;
+}
 
-  if (! old || ospf6_lsa_differ (old, new))
-    need_hook++;
+struct ospf6_lsa *
+ospf6_lsdb_type_head (u_int16_t type, struct ospf6_lsdb *lsdb)
+{
+  struct route_node *node;
+  struct prefix_ipv6 key;
+  struct ospf6_lsa *lsa;
 
-  /* log */
-  if (IS_OSPF6_DUMP_LSDB)
-    zlog_info ("LSDB: Install: %s %s", new->str,
-               ((IS_LSA_MAXAGE (new)) ? "(MaxAge)" : ""));
+  memset (&key, 0, sizeof (key));
+  ospf6_lsdb_set_key (&key, &type, sizeof (type));
 
-  if (old)
-    ospf6_lsa_lock (old);
+  /* Walk down tree. */
+  node = lsdb->table->top;
+  while (node && node->p.prefixlen <= key.prefixlen &&
+	 prefix_match (&node->p, (struct prefix *) &key))
+    node = node->link[CHECK_BIT(&key.prefix, node->p.prefixlen)];
 
-  ospf6_lsdb_add (new, lsdb);
-  gettimeofday (&new->installed, NULL);
+  if (node)
+    route_lock_node (node);
+  while (node && node->info == NULL)
+    node = route_next (node);
 
-  hook = ospf6_lsdb_hook[ntohs (new->header->type) &
-                         OSPF6_LSTYPE_CODE_MASK].hook;
-  if (need_hook && hook)
-    (*hook) (old, new);
+  if (node == NULL)
+    return NULL;
+  else
+    route_unlock_node (node);
 
-  /* old LSA should be freed here */
-  if (old)
-    ospf6_lsa_unlock (old);
+  if (! prefix_match ((struct prefix *) &key, &node->p))
+    return NULL;
+
+  lsa = node->info;
+  ospf6_lsa_lock (lsa);
+
+  return lsa;
+}
+
+struct ospf6_lsa *
+ospf6_lsdb_type_next (u_int16_t type, struct ospf6_lsa *lsa)
+{
+  struct ospf6_lsa *next = lsa->next;
+
+  if (next)
+    {
+      if (next->header->type != type)
+        next = NULL;
+    }
+
+  if (next)
+    ospf6_lsa_lock (next);
+  ospf6_lsa_unlock (lsa);
+  return next;
 }
 
 void
 ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb)
 {
-  struct ospf6_lsdb_node node;
-  for (ospf6_lsdb_head (&node, lsdb); ! ospf6_lsdb_is_end (&node);
-       ospf6_lsdb_next (&node))
-    ospf6_lsdb_remove (node.lsa, lsdb);
-}
-
-void
-ospf6_lsdb_remove_maxage (struct ospf6_lsdb *lsdb)
-{
-  struct ospf6_lsdb_node node;
   struct ospf6_lsa *lsa;
-
-  for (ospf6_lsdb_head (&node, lsdb); ! ospf6_lsdb_is_end (&node);
-       ospf6_lsdb_next (&node))
-    {
-      lsa = node.lsa;
-
-      /* contiue if it's not MaxAge */
-      if (! IS_LSA_MAXAGE (lsa))
-        continue;
-
-      /* continue if it's referenced by some retrans-lists */
-      if (lsa->lock != 1)
-        continue;
-
-      if (IS_OSPF6_DUMP_LSDB)
-        zlog_info ("Remove MaxAge LSA: %s", lsa->str);
-
-      ospf6_lsdb_remove (lsa, lsdb);
-    }
-}
-
-
-
-/* vty functions */
-
-static int
-ospf6_lsdb_match (int flag, u_int16_t type, u_int32_t id,
-                  u_int32_t adv_router, struct ospf6_lsa *lsa)
-{
-  if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_TYPE) &&
-      lsa->header->type != type)
-    return 0;
-
-  if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_ID) &&
-      lsa->header->id != id)
-    return 0;
-
-  if (CHECK_FLAG (flag, OSPF6_LSDB_MATCH_ADV_ROUTER) &&
-      lsa->header->adv_router != adv_router)
-    return 0;
-
-  return 1;
-}
-
-int
-show_ipv6_ospf6_lsdb (struct vty *vty, int argc, char **argv,
-                      struct ospf6_lsdb *lsdb)
-{
-  u_int flag;
-  u_int16_t type = 0;
-  u_int32_t id, adv_router;
-  int ret;
-  struct ospf6_lsdb_node node;
-  char invalid[32], *invalidp;
-  int l_argc = argc;
-  char **l_argv = argv;
-
-  flag = 0;
-  memset (invalid, 0, sizeof (invalid));
-  invalidp = invalid;
-
-  /* chop tail if the words is 'dump' or 'summary' */
-  if (l_argc > 0 && ! strcmp (l_argv[l_argc - 1], "dump"))
-    {
-      SET_FLAG (flag, OSPF6_LSDB_SHOW_DUMP);
-      l_argc --;
-    }
-  else if (l_argc > 0 && ! strcmp (l_argv[l_argc - 1], "detail"))
-    {
-      SET_FLAG (flag, OSPF6_LSDB_SHOW_DETAIL);
-      l_argc --;
-    }
-
-  if (l_argc > 0)
-    {
-      SET_FLAG (flag, OSPF6_LSDB_MATCH_TYPE);
-      if (! strncmp (l_argv[0], "r", 1))
-        type = htons (OSPF6_LSA_TYPE_ROUTER);
-      if (! strncmp (l_argv[0], "n", 1))
-        type = htons (OSPF6_LSA_TYPE_NETWORK);
-      if (! strncmp (l_argv[0], "a", 1))
-        type = htons (OSPF6_LSA_TYPE_AS_EXTERNAL);
-      if (! strcmp (l_argv[0], "intra-prefix"))
-        type = htons (OSPF6_LSA_TYPE_INTRA_PREFIX);
-      if (! strcmp (l_argv[0], "inter-router"))
-        type = htons (OSPF6_LSA_TYPE_INTER_ROUTER);
-      if (! strcmp (l_argv[0], "inter-prefix"))
-        type = htons (OSPF6_LSA_TYPE_INTER_PREFIX);
-      if (! strncmp (l_argv[0], "l", 1))
-        type = htons (OSPF6_LSA_TYPE_LINK);
-      if (! strncmp (l_argv[0], "0x", 2) && strlen (l_argv[0]) == 6)
-        type = htons ((short) strtol (l_argv[0], (char **)NULL, 16));
-      if (! strncmp (l_argv[0], "*", 1))
-        UNSET_FLAG (flag, OSPF6_LSDB_MATCH_TYPE);
-    }
-
-  if (l_argc > 1)
-    {
-      SET_FLAG (flag, OSPF6_LSDB_MATCH_ID);
-      if (! strncmp (l_argv[1], "*", 1))
-        UNSET_FLAG (flag, OSPF6_LSDB_MATCH_ID);
-      else
-        {
-          ret = inet_pton (AF_INET, l_argv[1], &id);
-          if (ret != 1)
-            {
-              id = htonl (strtoul (l_argv[1], &invalidp, 10));
-              if (invalid[0] != '\0')
-                {
-                  vty_out (vty, "Link State ID is not parsable: %s%s",
-                           l_argv[1], VTY_NEWLINE);
-                  return CMD_SUCCESS;
-                }
-            }
-        }
-    }
-
-  if (l_argc > 2)
-    {
-      SET_FLAG (flag, OSPF6_LSDB_MATCH_ADV_ROUTER);
-      if (! strncmp (l_argv[2], "*", 1))
-        UNSET_FLAG (flag, OSPF6_LSDB_MATCH_ADV_ROUTER);
-      else
-        {
-          ret = inet_pton (AF_INET, l_argv[2], &adv_router);
-          if (ret != 1)
-            {
-              adv_router = htonl (strtoul (l_argv[2], &invalidp, 10));
-              if (invalid[0] != '\0')
-                {
-                  vty_out (vty, "Advertising Router is not parsable: %s%s",
-                           l_argv[2], VTY_NEWLINE);
-                  return CMD_SUCCESS;
-                }
-            }
-        }
-    }
-
-  if (! CHECK_FLAG (flag, OSPF6_LSDB_SHOW_DETAIL))
-    ospf6_lsa_show_summary_header (vty);
-
-  for (ospf6_lsdb_head (&node, lsdb); ! ospf6_lsdb_is_end (&node);
-       ospf6_lsdb_next (&node))
-    {
-      if (! ospf6_lsdb_match (flag, type, id, adv_router, node.lsa))
-        continue;
-
-      if (CHECK_FLAG (flag, OSPF6_LSDB_SHOW_DUMP))
-        ospf6_lsa_show_dump (vty, node.lsa);
-      else if (CHECK_FLAG (flag, OSPF6_LSDB_SHOW_DETAIL))
-        ospf6_lsa_show (vty, node.lsa);
-      else
-        ospf6_lsa_show_summary (vty, node.lsa);
-    }
-
-  return CMD_SUCCESS;
-}
-
-DEFUN (show_ipv6_ospf6_database,
-       show_ipv6_ospf6_database_cmd,
-       "show ipv6 ospf6 database",
-       SHOW_STR
-       IP6_STR
-       OSPF6_STR
-       "LSA Database\n"
-       )
-{
-  struct ospf6_area *o6a;
-  struct ospf6_interface *o6i;
-  listnode i, j;
-
-  /* call show function for each of LSAs in the LSDBs */
-
-  for (i = listhead (ospf6->area_list); i; nextnode (i))
-    {
-      o6a = (struct ospf6_area *) getdata (i);
-
-      /* LinkLocal LSDBs */
-      for (j = listhead (o6a->if_list); j; nextnode (j))
-        {
-          o6i = (struct ospf6_interface *) getdata (j);
-
-          vty_out (vty, "%s", VTY_NEWLINE);
-          vty_out (vty, "                Interface %s (Area: %s):%s",
-                   o6i->interface->name, o6a->str, VTY_NEWLINE);
-          vty_out (vty, "%s", VTY_NEWLINE);
-          show_ipv6_ospf6_lsdb (vty, argc, argv, o6i->lsdb);
-        }
-
-      /* Area LSDBs */
-      vty_out (vty, "%s", VTY_NEWLINE);
-      vty_out (vty, "                Area %s:%s", o6a->str, VTY_NEWLINE);
-      vty_out (vty, "%s", VTY_NEWLINE);
-      show_ipv6_ospf6_lsdb (vty, argc, argv, o6a->lsdb);
-    }
-
-  /* AS LSDBs */
-  vty_out (vty, "%s", VTY_NEWLINE);
-  vty_out (vty, "                AS:%s", VTY_NEWLINE);
-  vty_out (vty, "%s", VTY_NEWLINE);
-  show_ipv6_ospf6_lsdb (vty, argc, argv, ospf6->lsdb);
-
-  return CMD_SUCCESS;
-}
-
-ALIAS (show_ipv6_ospf6_database,
-       show_ipv6_ospf6_database_type_cmd,
-       "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*|HEX|dump|detail)",
-       SHOW_STR
-       IP6_STR
-       OSPF6_STR
-       "LSA Database\n"
-       "Router-LSA\n"
-       "Network-LSA\n"
-       "AS-External-LSA\n"
-       "Intra-Area-Prefix-LSA\n"
-       "Inter-Area-Router-LSA\n"
-       "Inter-Area-Prefix-LSA\n"
-       "Link-LSA\n"
-       "All LS Type\n"
-       "Specify LS Type by Hex\n"
-       "Dump raw LSA data in Hex\n"
-       "show detail of LSAs\n"
-       )
-
-ALIAS (show_ipv6_ospf6_database,
-       show_ipv6_ospf6_database_type_id_cmd,
-       "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*|HEX) (A.B.C.D|*|dump|detail)",
-       SHOW_STR
-       IP6_STR
-       OSPF6_STR
-       "LSA Database\n"
-       "Router-LSA\n"
-       "Network-LSA\n"
-       "AS-External-LSA\n"
-       "Intra-Area-Prefix-LSA\n"
-       "Inter-Area-Router-LSA\n"
-       "Inter-Area-Prefix-LSA\n"
-       "Link-LSA\n"
-       "All LS Type\n"
-       "Specify LS Type by Hex\n"
-       "Link State ID\n"
-       "All Link State ID\n"
-       "Dump raw LSA data in Hex\n"
-       "show detail of LSAs\n"
-       )
-
-ALIAS (show_ipv6_ospf6_database,
-       show_ipv6_ospf6_database_type_id_adv_router_cmd,
-       "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*|HEX) (A.B.C.D|*) (A.B.C.D|*|dump|detail)",
-       SHOW_STR
-       IP6_STR
-       OSPF6_STR
-       "LSA Database\n"
-       "Router-LSA\n"
-       "Network-LSA\n"
-       "AS-External-LSA\n"
-       "Intra-Area-Prefix-LSA\n"
-       "Inter-Area-Router-LSA\n"
-       "Inter-Area-Prefix-LSA\n"
-       "Link-LSA\n"
-       "All LS Type\n"
-       "Specify LS Type by Hex\n"
-       "Link State ID\n"
-       "All Link State ID\n"
-       "Advertising Router\n"
-       "All Advertising Router\n"
-       "Dump raw LSA data in Hex\n"
-       "show detail of LSAs\n"
-       )
-
-ALIAS (show_ipv6_ospf6_database,
-       show_ipv6_ospf6_database_type_id_adv_router_dump_cmd,
-       "show ipv6 ospf6 database (router|network|as-external|intra-prefix|inter-prefix|inter-router|link|*|HEX) (A.B.C.D|*) (A.B.C.D|*) (dump|detail|)",
-       SHOW_STR
-       IP6_STR
-       OSPF6_STR
-       "LSA Database\n"
-       "Router-LSA\n"
-       "Network-LSA\n"
-       "AS-External-LSA\n"
-       "Intra-Area-Prefix-LSA\n"
-       "Inter-Area-Router-LSA\n"
-       "Inter-Area-Prefix-LSA\n"
-       "Link-LSA\n"
-       "All LS Type\n"
-       "Specify LS Type by Hex\n"
-       "Link State ID\n"
-       "All Link State ID\n"
-       "Advertising Router\n"
-       "All Advertising Router\n"
-       "Dump raw LSA data in Hex\n"
-       "show detail of LSAs\n"
-       )
-
-void
-ospf6_lsdb_init ()
-{
-  install_element (VIEW_NODE, &show_ipv6_ospf6_database_cmd);
-  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_cmd);
-  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_cmd);
-  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_adv_router_cmd);
-  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_adv_router_dump_cmd);
-
-  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_cmd);
-  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_cmd);
-  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_cmd);
-  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_adv_router_cmd);
-  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_adv_router_dump_cmd);
+  for (lsa = ospf6_lsdb_head (lsdb); lsa; lsa = ospf6_lsdb_next (lsa))
+    ospf6_lsdb_remove (lsa, lsdb);
 }
 
 
diff --git a/ospf6d/ospf6_lsdb.h b/ospf6d/ospf6_lsdb.h
index 50eedc8..94dfcb6 100644
--- a/ospf6d/ospf6_lsdb.h
+++ b/ospf6d/ospf6_lsdb.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2002 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -25,64 +25,146 @@
 #include "prefix.h"
 #include "table.h"
 
-#include "ospf6_prefix.h"
-#include "ospf6_lsa.h"
-
-struct ospf6_lsdb_node
-{
-  struct prefix_ipv6 key;
-
-  struct route_node *node;
-  struct route_node *next;
-
-  struct ospf6_lsa *lsa;
-};
-
 struct ospf6_lsdb
 {
   struct route_table *table;
   u_int32_t count;
-  void (*hook) (struct ospf6_lsa *);
+  void (*hook_add) (struct ospf6_lsa *);
+  void (*hook_remove) (struct ospf6_lsa *);
 };
 
-/* int  ospf6_lsdb_is_end (struct ospf6_lsdb_node *lsdb_node); */
-#define ospf6_lsdb_is_end(lsdb_node) ((lsdb_node)->node == NULL ? 1 : 0)
+#define LSDB_FOREACH_LSA(vty, func, lsdb)                             \
+  do {                                                                \
+    struct ospf6_lsa *lsa;                                            \
+    for (lsa = ospf6_lsdb_head (lsdb); lsa;                           \
+         lsa = ospf6_lsdb_next (lsa))                                 \
+      {                                                               \
+        (*(func)) (vty, lsa);                                         \
+      }                                                               \
+  } while (0)
+#define LSDB_FOREACH_LSA_T(vty, func, lsdb, type)                     \
+  do {                                                                \
+    struct ospf6_lsa *lsa;                                            \
+    for (lsa = ospf6_lsdb_type_head (type, lsdb); lsa;                \
+         lsa = ospf6_lsdb_type_next (type, lsa))                      \
+      {                                                               \
+        (*(func)) (vty, lsa);                                         \
+      }                                                               \
+  } while (0)
+#define LSDB_FOREACH_LSA_I(vty, func, lsdb, id)                       \
+  do {                                                                \
+    struct ospf6_lsa *lsa;                                            \
+    for (lsa = ospf6_lsdb_head (lsdb); lsa;                           \
+         lsa = ospf6_lsdb_next (lsa))                                 \
+      {                                                               \
+        if (lsa->header->id != id)                                    \
+          continue;                                                   \
+        (*(func)) (vty, lsa);                                         \
+      }                                                               \
+  } while (0)
+#define LSDB_FOREACH_LSA_R(vty, func, lsdb, router)                   \
+  do {                                                                \
+    struct ospf6_lsa *lsa;                                            \
+    for (lsa = ospf6_lsdb_head (lsdb); lsa;                           \
+         lsa = ospf6_lsdb_next (lsa))                                 \
+      {                                                               \
+        if (lsa->header->adv_router != router)                        \
+          continue;                                                   \
+        (*(func)) (vty, lsa);                                         \
+      }                                                               \
+  } while (0)
+#define LSDB_FOREACH_LSA_TI(vty, func, lsdb, type, id)                \
+  do {                                                                \
+    struct ospf6_lsa *lsa;                                            \
+    for (lsa = ospf6_lsdb_type_head (type, lsdb); lsa;                \
+         lsa = ospf6_lsdb_type_next (type, lsa))                      \
+      {                                                               \
+        if (lsa->header->id != id)                                    \
+          continue;                                                   \
+        (*(func)) (vty, lsa);                                         \
+      }                                                               \
+  } while (0)
+#define LSDB_FOREACH_LSA_TR(vty, func, lsdb, type, router)            \
+  do {                                                                \
+    struct ospf6_lsa *lsa;                                            \
+    for (lsa = ospf6_lsdb_type_router_head (type, router, lsdb); lsa; \
+         lsa = ospf6_lsdb_type_router_next (type, router, lsa))       \
+      {                                                               \
+        (*(func)) (vty, lsa);                                         \
+      }                                                               \
+  } while (0)
+#define LSDB_FOREACH_LSA_IR(vty, func, lsdb, id, router)              \
+  do {                                                                \
+    struct ospf6_lsa *lsa;                                            \
+    for (lsa = ospf6_lsdb_head (lsdb); lsa;                           \
+         lsa = ospf6_lsdb_next (lsa))                                 \
+      {                                                               \
+        if (lsa->header->adv_router != router)                        \
+          continue;                                                   \
+        if (lsa->header->id != id)                                    \
+          continue;                                                   \
+        (*(func)) (vty, lsa);                                         \
+      }                                                               \
+  } while (0)
+#define LSDB_FOREACH_LSA_TIR(vty, func, lsdb, type, id, router)       \
+  do {                                                                \
+    struct ospf6_lsa *lsa;                                            \
+    lsa = ospf6_lsdb_lookup (type, id, router, lsdb);                 \
+    if (lsa)                                                          \
+      (*(func)) (vty, lsa);                                           \
+  } while (0)
 
-/* global holding hooks for each LS type */
-struct ospf6_lsdb_hook_t
-{
-  void (*hook) (struct ospf6_lsa *old, struct ospf6_lsa *new);
-};
-extern struct ospf6_lsdb_hook_t *ospf6_lsdb_hook;
+#define OSPF6_LSDB_MAXAGE_REMOVER(lsdb)                                  \
+  do {                                                                   \
+    struct ospf6_lsa *lsa;                                               \
+    for (lsa = ospf6_lsdb_head (lsdb); lsa; lsa = ospf6_lsdb_next (lsa)) \
+      {                                                                  \
+        if (! OSPF6_LSA_IS_MAXAGE (lsa))                                 \
+          continue;                                                      \
+        if (lsa->refcnt != 0)                                            \
+          continue;                                                      \
+        if (IS_OSPF6_DEBUG_LSA (TIMER))                                  \
+          zlog_info (" remove maxage %s", lsa->name);                    \
+        ospf6_lsdb_remove (lsa, lsdb);                                   \
+      }                                                                  \
+  } while (0)
 
 /* Function Prototypes */
-struct ospf6_lsdb * ospf6_lsdb_create ();
+struct ospf6_lsdb *ospf6_lsdb_create ();
 void ospf6_lsdb_delete (struct ospf6_lsdb *lsdb);
 
-void ospf6_lsdb_remove_maxage (struct ospf6_lsdb *lsdb);
-
-struct ospf6_lsa *
-ospf6_lsdb_lookup (u_int16_t type, u_int32_t id, u_int32_t adv_router,
-                   void *scope);
-
-void ospf6_lsdb_install (struct ospf6_lsa *new);
-
-void ospf6_lsdb_head (struct ospf6_lsdb_node *node, struct ospf6_lsdb *lsdb);
-void ospf6_lsdb_type (struct ospf6_lsdb_node *node, u_int16_t type,
-                      struct ospf6_lsdb *lsdb);
-void ospf6_lsdb_type_router (struct ospf6_lsdb_node *node, u_int16_t type,
-                             u_int32_t adv_router, struct ospf6_lsdb *lsdb);
-void ospf6_lsdb_next (struct ospf6_lsdb_node *node);
+struct ospf6_lsa *ospf6_lsdb_lookup (u_int16_t type, u_int32_t id,
+                                     u_int32_t adv_router,
+                                     struct ospf6_lsdb *lsdb);
 
 void ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb);
 void ospf6_lsdb_remove (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb);
+
+struct ospf6_lsa *ospf6_lsdb_head (struct ospf6_lsdb *lsdb);
+struct ospf6_lsa *ospf6_lsdb_next (struct ospf6_lsa *lsa);
+
+struct ospf6_lsa *ospf6_lsdb_type_router_head (u_int16_t type,
+                                               u_int32_t adv_router,
+                                               struct ospf6_lsdb *lsdb);
+struct ospf6_lsa *ospf6_lsdb_type_router_next (u_int16_t type,
+                                               u_int32_t adv_router,
+                                               struct ospf6_lsa *lsa);
+
+struct ospf6_lsa *ospf6_lsdb_type_head (u_int16_t type,
+                                        struct ospf6_lsdb *lsdb);
+struct ospf6_lsa *ospf6_lsdb_type_next (u_int16_t type,
+                                        struct ospf6_lsa *lsa);
+
 void ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb);
 
-struct ospf6_lsa *
-ospf6_lsdb_lookup_lsdb (u_int16_t type, u_int32_t id, u_int32_t adv_router,
-                        struct ospf6_lsdb *lsdb);
+int ospf6_lsdb_show (struct vty *vty, int argc, char **argv,
+                     struct ospf6_lsdb *lsdb);
 
+#if 0
 void ospf6_lsdb_init ();
+void ospf6_lsdb_remove_maxage (struct ospf6_lsdb *lsdb);
+#endif
 
 #endif /* OSPF6_LSDB_H */
 
+
diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c
index 3b7cfc9..4dfcdee 100644
--- a/ospf6d/ospf6_main.c
+++ b/ospf6d/ospf6_main.c
@@ -20,32 +20,30 @@
  */
 
 #include <zebra.h>
+
 #include "getopt.h"
 #include "thread.h"
 #include "log.h"
-#include <lib/version.h>
+#include "version.h"
 #include "command.h"
 #include "vty.h"
 #include "memory.h"
+#include "if.h"
+#include "filter.h"
+#include "prefix.h"
+#include "plist.h"
 #include "privs.h"
 
 #include "ospf6d.h"
-#include "ospf6_network.h"
-
-void ospf6_init ();
-void ospf6_terminate ();
-void nexthop_init ();
-int ospf6_receive (struct thread *);
-
-extern int ospf6_sock;
 
 /* Default configuration file name for ospf6d. */
 #define OSPF6_DEFAULT_CONFIG       "ospf6d.conf"
+
 /* Default port values. */
 #define OSPF6_VTY_PORT             2606
 
 /* ospf6d privileges */
-zebra_capabilities_t _caps_p [] = 
+zebra_capabilities_t _caps_p [] =
 {
   ZCAP_RAW,
   ZCAP_BIND
@@ -75,7 +73,6 @@
   { "pid_file",    required_argument, NULL, 'i'},
   { "vty_addr",    required_argument, NULL, 'A'},
   { "vty_port",    required_argument, NULL, 'P'},
-  { "user",        required_argument, NULL, 'u'},
   { "version",     no_argument,       NULL, 'v'},
   { "help",        no_argument,       NULL, 'h'},
   { 0 }
@@ -86,6 +83,7 @@
 char config_default[] = SYSCONFDIR OSPF6_DEFAULT_CONFIG;
 
 /* ospf6d program name. */
+char *progname;
 
 /* is daemon? */
 int daemon_mode = 0;
@@ -96,19 +94,6 @@
 /* Process ID saved for use by init system */
 char *pid_file = PATH_OSPF6D_PID;
 
-/* for reload */
-
-#ifdef MAXPATHLEN
-char _cwd[MAXPATHLEN];
-#else
-char _cwd[64];
-#endif
-
-char _progpath[64];
-int _argc;
-char **_argv;
-char **_envp;
-
 /* Help information display. */
 static void
 usage (char *progname, int status)
@@ -124,43 +109,20 @@
 -i, --pid_file     Set process identifier file name\n\
 -A, --vty_addr     Set vty's bind address\n\
 -P, --vty_port     Set vty's port number\n\
--u, --user         User and group to run as\n\
 -v, --version      Print program version\n\
 -h, --help         Display this help and exit\n\
 \n\
-Report bugs to yasu@sfc.wide.ad.jp\n", progname);
+Report bugs to zebra@zebra.org\n", progname);
     }
 
   exit (status);
 }
-
-
-void
-_reload ()
-{
-  zlog_notice ("OSPF6d (Zebra-%s ospf6d-%s) reloaded",
-               QUAGGA_VERSION, OSPF6_DAEMON_VERSION);
-  ospf6_zebra_finish ();
-  vty_finish ();
-  execve (_progpath, _argv, _envp);
-}
-
-void
-terminate (int i)
-{
-  ospf6_delete (ospf6);
-  unlink (PATH_OSPF6D_PID);
-  zlog_notice ("OSPF6d (Zebra-%s ospf6d-%s) terminated",
-               QUAGGA_VERSION, OSPF6_DAEMON_VERSION);
-  exit (i);
-}
 
 /* SIGHUP handler. */
 void 
 sighup (int sig)
 {
   zlog_info ("SIGHUP received");
-  _reload ();
 }
 
 /* SIGINT handler. */
@@ -168,7 +130,7 @@
 sigint (int sig)
 {
   zlog_info ("SIGINT received");
-  terminate (0);
+  exit (0);
 }
 
 /* SIGTERM handler. */
@@ -176,7 +138,7 @@
 sigterm (int sig)
 {
   zlog_info ("SIGTERM received");
-  terminate (0);
+  exit (0);
 }
 
 /* SIGUSR1 handler. */
@@ -229,8 +191,8 @@
 #endif
   signal_set (SIGUSR1, sigusr1);
 }
-
-/* Main routine of ospf6d. Treatment of argument and start ospf finite
+
+/* Main routine of ospf6d. Treatment of argument and starting ospf finite
    state machine is handled here. */
 int
 main (int argc, char *argv[], char *envp[])
@@ -238,9 +200,8 @@
   char *p;
   int opt;
   char *vty_addr = NULL;
-  int vty_port = OSPF6_VTY_PORT;
+  int vty_port = 0;
   char *config_file = NULL;
-  char *progname;
   struct thread thread;
   int flag;
 
@@ -250,16 +211,6 @@
   /* Preserve name of myself. */
   progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
 
-  /* for reload */
-  _argc = argc;
-  _argv = argv;
-  _envp = envp;
-  getcwd (_cwd, sizeof (_cwd));
-  if (*argv[0] == '.')
-    snprintf (_progpath, sizeof (_progpath), "%s/%s", _cwd, _argv[0]);
-  else
-    snprintf (_progpath, sizeof (_progpath), "%s", argv[0]);
-
   /* Command line argument treatment. */
   while (1) 
     {
@@ -287,14 +238,14 @@
         case 'P':
          /* Deal with atoi() returning 0 on failure, and ospf6d not
              listening on ospf6d port... */
-          if (strcmp(optarg, "0") == 0) 
+          if (strcmp(optarg, "0") == 0)
             {
               vty_port = 0;
               break;
-            } 
+            }
           vty_port = atoi (optarg);
           vty_port = (vty_port ? vty_port : OSPF6_VTY_PORT);
-	  break;
+          break;
         case 'u':
           ospf6d_privs.user = ospf6d_privs.group = optarg;
           break;
@@ -318,17 +269,25 @@
   if (! daemon_mode)
     flag = ZLOG_STDOUT;
   else
-    flag = ZLOG_NOLOG;
+    flag = 0;
 
   zlog_default = openzlog (progname, flag, ZLOG_OSPF6,
-			   LOG_CONS|LOG_NDELAY|LOG_PID,
-			   LOG_DAEMON);
-	zprivs_init (&ospf6d_privs);
+                           LOG_CONS|LOG_NDELAY|LOG_PERROR|LOG_PID,
+                           LOG_DAEMON);
+  zprivs_init (&ospf6d_privs);
+  /* initialize zebra libraries */
   signal_init ();
   cmd_init (1);
   vty_init (master);
-  ospf6_init ();
   memory_init ();
+  if_init ();
+  access_list_init ();
+  prefix_list_init ();
+
+  /* initialize ospf6 */
+  ospf6_init ();
+
+  /* sort command vector */
   sort_node ();
 
   /* parse config file */
@@ -344,18 +303,13 @@
   pid_output (pid_file);
 #endif
 
-  /* Make ospf protocol socket. */
-  ospf6_serv_sock ();
-  thread_add_read (master, ospf6_receive, NULL, ospf6_sock);
+  /* Make ospf6 vty socket. */
+  vty_serv_sock (vty_addr,
+                 vty_port ? vty_port : OSPF6_VTY_PORT, OSPF6_VTYSH_PATH);
 
-  /* Make ospf vty socket. */
-  vty_serv_sock (vty_addr, vty_port, OSPF6_VTYSH_PATH);
-
-#ifdef DEBUG
   /* Print start message */
-  zlog_notice ("OSPF6d (Zebra-%s ospf6d-%s) starts",
+  zlog_notice ("OSPF6d (Quagga-%s ospf6d-%s) starts",
                QUAGGA_VERSION, OSPF6_DAEMON_VERSION);
-#endif
 
   /* Start finite state machine, here we go! */
   while (thread_fetch (master, &thread))
@@ -363,9 +317,9 @@
 
   /* Log in case thread failed */
   zlog_warn ("Thread failed");
-  terminate (0);
 
   /* Not reached. */
   exit (0);
 }
 
+
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index 0e74b65..21b799e 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -19,1954 +19,2056 @@
  * Boston, MA 02111-1307, USA.  
  */
 
+#include <zebra.h>
+
+#include "log.h"
+#include "vty.h"
+#include "command.h"
+#include "thread.h"
+#include "linklist.h"
+
 #include "ospf6d.h"
+#include "ospf6_proto.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+#include "ospf6_network.h"
+#include "ospf6_message.h"
 
-int
-is_ospf6_message_dump (u_char type)
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_interface.h"
+
+#include "ospf6_flood.h"
+
+unsigned char conf_debug_ospf6_message[6] = {0x03, 0, 0, 0, 0, 0};
+char *ospf6_message_type_str[] =
+  { "Unknown", "Hello", "DbDesc", "LSReq", "LSUpdate", "LSAck" };
+
+/* print functions */
+
+static void
+ospf6_header_print (struct ospf6_header *oh)
 {
-  if (type > OSPF6_MESSAGE_TYPE_LSACK)
-    type = OSPF6_MESSAGE_TYPE_UNKNOWN;
+  char router_id[16], area_id[16];
+  inet_ntop (AF_INET, &oh->router_id, router_id, sizeof (router_id));
+  inet_ntop (AF_INET, &oh->area_id, area_id, sizeof (area_id));
 
-  switch (type)
-    {
-      case OSPF6_MESSAGE_TYPE_UNKNOWN:
-          return 1;
-        break;
-      case OSPF6_MESSAGE_TYPE_HELLO:
-        if (IS_OSPF6_DUMP_HELLO)
-          return 1;
-        break;
-      case OSPF6_MESSAGE_TYPE_DBDESC:
-        if (IS_OSPF6_DUMP_DBDESC)
-          return 1;
-        break;
-      case OSPF6_MESSAGE_TYPE_LSREQ:
-        if (IS_OSPF6_DUMP_LSREQ)
-          return 1;
-        break;
-      case OSPF6_MESSAGE_TYPE_LSUPDATE:
-        if (IS_OSPF6_DUMP_LSUPDATE)
-          return 1;
-        break;
-      case OSPF6_MESSAGE_TYPE_LSACK:
-        if (IS_OSPF6_DUMP_LSACK)
-          return 1;
-        break;
-      default:
-        break;
-    }
-  return 0;
+  zlog_info ("    OSPFv%d Type:%d Len:%hu Router-ID:%s",
+             oh->version, oh->type, ntohs (oh->length), router_id);
+  zlog_info ("    Area-ID:%s Cksum:%hx Instance-ID:%d",
+             area_id, ntohs (oh->checksum), oh->instance_id);
 }
-#define IS_OSPF6_DUMP_MESSAGE(x) (is_ospf6_message_dump(x))
-
-char *ospf6_message_type_string[] =
-{
-  "Unknown", "Hello", "DbDesc", "LSReq", "LSUpdate", "LSAck", NULL
-};
 
 void
-ospf6_message_log_lsa_header (struct ospf6_lsa_header *lsa_header)
+ospf6_hello_print (struct ospf6_header *oh)
 {
-  char buf_id[16], buf_router[16], typebuf[32];
-
-  inet_ntop (AF_INET, &lsa_header->advrtr, buf_router, sizeof (buf_router));
-  inet_ntop (AF_INET, &lsa_header->ls_id, buf_id, sizeof (buf_id));
-  zlog_info ("   [%s ID=%s Adv=%s]",
-             ospf6_lsa_type_string (lsa_header->type, typebuf,
-                                    sizeof (typebuf)),
-             buf_id, buf_router);
-  zlog_info ("    Age=%hu SeqNum=%#lx Cksum=%#hx Len=%hu",
-             ntohs (lsa_header->age), (u_long)ntohl (lsa_header->seqnum),
-             ntohs (lsa_header->checksum), ntohs (lsa_header->length));
-}
-
-static void
-ospf6_message_log_unknown (struct iovec *message)
-{
-  zlog_info ("Message:  Unknown");
-}
-
-static void
-ospf6_message_log_hello (struct iovec *message)
-{
-  struct ospf6_header *ospf6_header;
-  u_int16_t length_left;
   struct ospf6_hello *hello;
-  char dr_str[16], bdr_str[16];
-  char *start, *end, *current;
+  char options[16];
+  char drouter[16], bdrouter[16], neighbor[16];
+  char *p;
 
-  /* calculate length */
-  ospf6_header = (struct ospf6_header *) message[0].iov_base;
-  length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
-  length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ?
-                 length_left : iov_totallen (message) - sizeof (struct ospf6_header));
+  ospf6_header_print (oh);
+  assert (oh->type == OSPF6_MESSAGE_TYPE_HELLO);
 
-  hello = (struct ospf6_hello *) message[1].iov_base;
+  hello = (struct ospf6_hello *)
+    ((caddr_t) oh + sizeof (struct ospf6_header));
 
-  inet_ntop (AF_INET, &hello->dr, dr_str, sizeof (dr_str));
-  inet_ntop (AF_INET, &hello->bdr, bdr_str, sizeof (bdr_str));
+  inet_ntop (AF_INET, &hello->drouter, drouter, sizeof (drouter));
+  inet_ntop (AF_INET, &hello->bdrouter, bdrouter, sizeof (bdrouter));
+  ospf6_options_printbuf (hello->options, options, sizeof (options));
 
-  zlog_info ("    IFID:%ld Priority:%d Option:%s",
-             (u_long)ntohl (hello->interface_id), hello->rtr_pri, "xxx");
-  zlog_info ("    HelloInterval:%hu Deadinterval:%hu",
-             ntohs (hello->hello_interval),
-             ntohs (hello->router_dead_interval));
-  zlog_info ("    DR:%s BDR:%s", dr_str, bdr_str);
+  zlog_info ("    I/F-Id:%ld Priority:%d Option:%s",
+             (u_long) ntohl (hello->interface_id), hello->priority, options);
+  zlog_info ("    HelloInterval:%hu DeadInterval:%hu",
+             ntohs (hello->hello_interval), ntohs (hello->dead_interval));
+  zlog_info ("    DR:%s BDR:%s", drouter, bdrouter);
 
-  start = (char *) (hello + 1);
-  if (start >= (char *) message[1].iov_base + message[1].iov_len)
-    start = message[2].iov_base;
-  end = (char *) start + (length_left - sizeof (struct ospf6_hello));
-
-  for (current = start; current < end; current += sizeof (u_int32_t))
+  for (p = (char *) ((caddr_t) hello + sizeof (struct ospf6_hello));
+       p + sizeof (u_int32_t) <= OSPF6_MESSAGE_END (oh);
+       p += sizeof (u_int32_t))
     {
-      char neighbor[16];
-      inet_ntop (AF_INET, current, neighbor, sizeof (neighbor));
+      inet_ntop (AF_INET, (void *) p, neighbor, sizeof (neighbor));
       zlog_info ("    Neighbor: %s", neighbor);
     }
+
+  if (p != OSPF6_MESSAGE_END (oh))
+    zlog_info ("Trailing garbage exists");
 }
 
-static void
-ospf6_message_log_dbdesc (struct iovec *message)
+void
+ospf6_dbdesc_print (struct ospf6_header *oh)
 {
-  struct ospf6_header *ospf6_header;
-  u_int16_t length_left;
   struct ospf6_dbdesc *dbdesc;
-  int i;
-  char buffer[16];
-  struct ospf6_lsa_header *lsa_header;
+  char options[16];
+  char *p;
 
-  /* calculate length */
-  ospf6_header = (struct ospf6_header *) message[0].iov_base;
-  length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
-  length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ?
-                 length_left : iov_totallen (message) - sizeof (struct ospf6_header));
+  ospf6_header_print (oh);
+  assert (oh->type == OSPF6_MESSAGE_TYPE_DBDESC);
 
-  dbdesc = (struct ospf6_dbdesc *) message[1].iov_base;
-  ospf6_options_string (dbdesc->options, buffer, sizeof (buffer));
+  dbdesc = (struct ospf6_dbdesc *)
+    ((caddr_t) oh + sizeof (struct ospf6_header));
 
-  zlog_info ("    Option:%s IFMTU:%hu", buffer, ntohs (dbdesc->ifmtu));
-  zlog_info ("    Bits:%s%s%s SeqNum:%#lx",
-             (DD_IS_IBIT_SET (dbdesc->bits) ? "I" : "-"),
-             (DD_IS_MBIT_SET (dbdesc->bits) ? "M" : "-"),
-             (DD_IS_MSBIT_SET (dbdesc->bits) ? "m" : "s"),
-             (u_long)ntohl (dbdesc->seqnum));
+  ospf6_options_printbuf (dbdesc->options, options, sizeof (options));
 
-  for (lsa_header = (struct ospf6_lsa_header *) (dbdesc + 1);
-       (char *)(lsa_header + 1) <= (char *)(message[1].iov_base + message[1].iov_len) &&
-       (char *)(lsa_header + 1) <= (char *)dbdesc + length_left;
-       lsa_header++)
-    ospf6_message_log_lsa_header (lsa_header);
+  zlog_info ("    MBZ: %#x Option: %s IfMTU: %hu",
+             dbdesc->reserved1, options, ntohs (dbdesc->ifmtu));
+  zlog_info ("    MBZ: %#x Bits: %s%s%s SeqNum: %#lx",
+             dbdesc->reserved2,
+             (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_IBIT) ? "I" : "-"),
+             (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MBIT) ? "M" : "-"),
+             (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT) ? "m" : "s"),
+             (u_long) ntohl (dbdesc->seqnum));
 
-  length_left -= message[1].iov_len;
-  for (i = 2; message[i].iov_base; i++)
-    {
-      for (lsa_header = (struct ospf6_lsa_header *) message[i].iov_base;
-           (char *)(lsa_header + 1) <= (char *) (message[i].iov_base +
-                                                 message[i].iov_len) &&
-           (char *)(lsa_header + 1) <= (char *) (message[i].iov_base + length_left);
-           lsa_header++)
-        ospf6_message_log_lsa_header (lsa_header);
-      length_left -= message[i].iov_len;
-    }
+  for (p = (char *) ((caddr_t) dbdesc + sizeof (struct ospf6_dbdesc));
+       p + sizeof (struct ospf6_lsa_header) <= OSPF6_MESSAGE_END (oh);
+       p += sizeof (struct ospf6_lsa_header))
+    ospf6_lsa_header_print_raw ((struct ospf6_lsa_header *) p);
+
+  if (p != OSPF6_MESSAGE_END (oh))
+    zlog_info ("Trailing garbage exists");
 }
 
-static void
-ospf6_message_log_lsreq (struct iovec *message)
+void
+ospf6_lsreq_print (struct ospf6_header *oh)
 {
-  struct ospf6_header *ospf6_header;
-  u_int16_t length_left;
-  int i;
-  struct ospf6_lsreq *lsreq;
-  char buf_router[16], buf_id[16], buf_type[16];
+  char id[16], adv_router[16];
+  char *p;
 
-  /* calculate length */
-  ospf6_header = (struct ospf6_header *) message[0].iov_base;
-  length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
-  length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ?
-                 length_left : iov_totallen (message) - sizeof (struct ospf6_header));
+  ospf6_header_print (oh);
+  assert (oh->type == OSPF6_MESSAGE_TYPE_LSREQ);
 
-  for (i = 1; message[i].iov_base; i++)
+  for (p = (char *) ((caddr_t) oh + sizeof (struct ospf6_header));
+       p + sizeof (struct ospf6_lsreq_entry) <= OSPF6_MESSAGE_END (oh);
+       p += sizeof (struct ospf6_lsreq_entry))
     {
-      for (lsreq = (struct ospf6_lsreq *) message[i].iov_base;
-           (char *)(lsreq + 1) <= (char *) (message[i].iov_base + message[i].iov_len) &&
-           (char *)(lsreq + 1) <= (char *) (message[i].iov_base + length_left);
-           lsreq++)
-        {
-          inet_ntop (AF_INET, &lsreq->adv_router, buf_router, sizeof (buf_router));
-          inet_ntop (AF_INET, &lsreq->id, buf_id, sizeof (buf_id));
-          zlog_info ("    [%s ID=%s Adv=%s]",
-                     ospf6_lsa_type_string (lsreq->type, buf_type,
-                                            sizeof (buf_type)),
-                     buf_id, buf_router);
-        }
-      length_left -= message[i].iov_len;
+      struct ospf6_lsreq_entry *e = (struct ospf6_lsreq_entry *) p;
+      inet_ntop (AF_INET, &e->adv_router, adv_router, sizeof (adv_router));
+      inet_ntop (AF_INET, &e->id, id, sizeof (id));
+      zlog_info ("    [%s Id:%s Adv:%s]",
+                 OSPF6_LSTYPE_NAME (e->type), id, adv_router);
     }
+
+  if (p != OSPF6_MESSAGE_END (oh))
+    zlog_info ("Trailing garbage exists");
 }
 
-static void
-ospf6_message_log_lsupdate (struct iovec *message)
+void
+ospf6_lsupdate_print (struct ospf6_header *oh)
 {
-  struct ospf6_header *ospf6_header;
-  u_int16_t length_left;
-  int i, lsanum;
   struct ospf6_lsupdate *lsupdate;
-  struct ospf6_lsa_header *lsa_header;
+  u_long num;
+  char *p;
 
-  /* calculate length */
-  ospf6_header = (struct ospf6_header *) message[0].iov_base;
-  length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
-  length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ?
-                 length_left : iov_totallen (message) - sizeof (struct ospf6_header));
+  ospf6_header_print (oh);
+  assert (oh->type == OSPF6_MESSAGE_TYPE_LSUPDATE);
 
-  lsupdate = (struct ospf6_lsupdate *) message[1].iov_base;
-  lsanum = ntohl (lsupdate->lsupdate_num);
+  lsupdate = (struct ospf6_lsupdate *)
+    ((caddr_t) oh + sizeof (struct ospf6_header));
 
-  zlog_info ("    Number of LSA: #%d", lsanum);
+  num = ntohl (lsupdate->lsa_number);
+  zlog_info ("    Number of LSA: %ld", num);
 
-  for (lsa_header = (struct ospf6_lsa_header *) (lsupdate + 1);
-       (char *)lsa_header < (char *)(message[1].iov_base + message[1].iov_len) &&
-       (char *)lsa_header < (char *)(message[1].iov_base + length_left);
-       lsa_header = OSPF6_LSA_NEXT (lsa_header))
-    ospf6_message_log_lsa_header (lsa_header);
-  length_left -= message[1].iov_len;
-
-  for (i = 2; message[i].iov_base; i++)
+  for (p = (char *) ((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate));
+       p < OSPF6_MESSAGE_END (oh) &&
+       p + OSPF6_LSA_SIZE (p) <= OSPF6_MESSAGE_END (oh);
+       p += OSPF6_LSA_SIZE (p))
     {
+      ospf6_lsa_header_print_raw ((struct ospf6_lsa_header *) p);
+      if (OSPF6_LSA_SIZE (p) < sizeof (struct ospf6_lsa_header))
+        {
+          zlog_info ("    Malformed LSA length, quit printing");
+          break;
+        }
+    }
 
-      for (lsa_header = (struct ospf6_lsa_header *) message[i].iov_base;
-           (char *)lsa_header < (char *) (message[i].iov_base + message[i].iov_len) &&
-           (char *)lsa_header < (char *) (message[i].iov_base + length_left);
-           lsa_header = OSPF6_LSA_NEXT (lsa_header))
-        ospf6_message_log_lsa_header (lsa_header);
-      length_left -= message[i].iov_len;
+  if (p != OSPF6_MESSAGE_END (oh))
+    {
+      char buf[32];
+
+      int num = 0;
+      memset (buf, 0, sizeof (buf));
+
+      zlog_info ("    Trailing garbage exists");
+      while (p < OSPF6_MESSAGE_END (oh))
+        {
+          snprintf (buf, sizeof (buf), "%s %2x", buf, *p++);
+          num++;
+          if (num == 8)
+            {
+              zlog_info ("    %s", buf);
+              memset (buf, 0, sizeof (buf));
+              num = 0;
+            }
+        }
+      if (num)
+        zlog_info ("    %s", buf);
     }
 }
 
-static void
-ospf6_message_log_lsack (struct iovec *message)
+void
+ospf6_lsack_print (struct ospf6_header *oh)
 {
-  struct ospf6_header *ospf6_header;
-  u_int16_t length_left;
-  struct ospf6_lsa_header *lsa_header;
-  int i;
+  char *p;
 
-  /* calculate length */
-  ospf6_header = (struct ospf6_header *) message[0].iov_base;
-  length_left = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
-  length_left = (length_left < iov_totallen (message) - sizeof (struct ospf6_header) ?
-                 length_left : iov_totallen (message) - sizeof (struct ospf6_header));
+  ospf6_header_print (oh);
+  assert (oh->type == OSPF6_MESSAGE_TYPE_LSACK);
 
-  for (i = 1; message[i].iov_base; i++)
-    {
-      for (lsa_header = (struct ospf6_lsa_header *) message[i].iov_base;
-           (char *)(lsa_header + 1) <= (char *) (message[i].iov_base +
-                                                 message[i].iov_len) &&
-           (char *)(lsa_header + 1) <= (char *) (message[i].iov_base + length_left);
-           lsa_header++)
-        ospf6_message_log_lsa_header (lsa_header);
-      length_left -= message[i].iov_len;
-    }
+  for (p = (char *) ((caddr_t) oh + sizeof (struct ospf6_header));
+       p + sizeof (struct ospf6_lsa_header) <= OSPF6_MESSAGE_END (oh);
+       p += sizeof (struct ospf6_lsa_header))
+    ospf6_lsa_header_print_raw ((struct ospf6_lsa_header *) p);
+
+  if (p != OSPF6_MESSAGE_END (oh))
+    zlog_info ("Trailing garbage exists");
 }
 
-struct {
-  void (*message_log) (struct iovec *);
-} ospf6_message_log_body [] =
+/* Receive function */
+#define MSG_OK    0
+#define MSG_NG    1
+static int
+ospf6_header_examin (struct in6_addr *src, struct in6_addr *dst,
+                     struct ospf6_interface *oi, struct ospf6_header *oh)
 {
-  {ospf6_message_log_unknown},
-  {ospf6_message_log_hello},
-  {ospf6_message_log_dbdesc},
-  {ospf6_message_log_lsreq},
-  {ospf6_message_log_lsupdate},
-  {ospf6_message_log_lsack},
-};
-
-static void
-ospf6_message_log (struct iovec *message)
-{
-  struct ospf6_header *o6h;
-  char router_id[16], area_id[16];
   u_char type;
+  type = OSPF6_MESSAGE_TYPE_CANONICAL (oh->type);
 
-  assert (message[0].iov_len == sizeof (struct ospf6_header));
-  o6h = (struct ospf6_header *) message[0].iov_base;
-
-  inet_ntop (AF_INET, &o6h->router_id, router_id, sizeof (router_id));
-  inet_ntop (AF_INET, &o6h->area_id, area_id, sizeof (area_id));
-
-  zlog_info ("    OSPFv%d Type:%d Len:%hu RouterID:%s",
-             o6h->version, o6h->type, ntohs (o6h->len), router_id);
-  zlog_info ("    AreaID:%s Cksum:%hx InstanceID:%d",
-             area_id, ntohs (o6h->cksum), o6h->instance_id);
-
-  type = (OSPF6_MESSAGE_TYPE_UNKNOWN < o6h->type &&
-          o6h->type <= OSPF6_MESSAGE_TYPE_LSACK ?
-          o6h->type : OSPF6_MESSAGE_TYPE_UNKNOWN);
-  (* ospf6_message_log_body[type].message_log) (&message[0]);
-}
-
-int
-ospf6_opt_is_mismatch (unsigned char opt, char *options1, char *options2)
-{
-  return (OSPF6_OPT_ISSET (options1, opt) ^ OSPF6_OPT_ISSET (options2, opt));
-}
-
-
-void
-ospf6_process_unknown (struct iovec *message,
-                       struct in6_addr *src,
-                       struct in6_addr *dst,
-                       struct ospf6_interface *o6i,
-                       u_int32_t router_id)
-{
-  zlog_warn ("unknown message type, drop");
-}
-
-void
-ospf6_process_hello (struct iovec *message,
-                     struct in6_addr *src,
-                     struct in6_addr *dst,
-                     struct ospf6_interface *o6i,
-                     u_int32_t router_id)
-{
-  struct ospf6_header *ospf6_header;
-  u_int16_t length;
-  struct ospf6_hello *hello;
-  char changes = 0;
-#define CHANGE_RTRPRI (1 << 0)
-#define CHANGE_DR     (1 << 1)
-#define CHANGE_BDR    (1 << 2)
-  int twoway = 0, backupseen = 0, nbchange = 0;
-  u_int32_t *router_id_ptr;
-  int i, seenrtrnum = 0, router_id_space = 0;
-  char strbuf[64];
-  struct ospf6_neighbor *o6n = NULL;
-
-  /* assert interface */
-  assert (o6i);
-
-  /* caluculate length */
-  ospf6_header = (struct ospf6_header *) message[0].iov_base;
-  length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
-  length = (length < message[1].iov_len ? length : message[1].iov_len);
-
-  /* set hello pointer */
-  hello = (struct ospf6_hello *) message[1].iov_base;
-
-  /* find neighbor. if cannot be found, create */
-  o6n = ospf6_neighbor_lookup (router_id, o6i);
-  if (!o6n)
+  /* version check */
+  if (oh->version != OSPFV3_VERSION)
     {
-      o6n = ospf6_neighbor_create (router_id, o6i);
-      o6n->ifid = ntohl (hello->interface_id);
-      o6n->prevdr = o6n->dr = hello->dr;
-      o6n->prevbdr = o6n->bdr = hello->bdr;
-      o6n->priority = hello->rtr_pri;
-      memcpy (&o6n->hisaddr, src, sizeof (struct in6_addr));
+      if (IS_OSPF6_DEBUG_MESSAGE (type, RECV))
+        zlog_info ("Message with unknown version");
+      return MSG_NG;
     }
 
+  /* Area-ID check */
+  if (oh->area_id != oi->area->area_id)
+    {
+      if (oh->area_id == 0)
+        {
+          if (IS_OSPF6_DEBUG_MESSAGE (type, RECV))
+            zlog_info ("Message may be via Virtual Link: not supported");
+          return MSG_NG;
+        }
+
+      if (IS_OSPF6_DEBUG_MESSAGE (type, RECV))
+        zlog_info ("Area-ID mismatch");
+      return MSG_NG;
+    }
+
+  /* Instance-ID check */
+  if (oh->instance_id != oi->instance_id)
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (type, RECV))
+        zlog_info ("Instance-ID mismatch");
+      return MSG_NG;
+    }
+
+  /* Router-ID check */
+  if (oh->router_id == oi->area->ospf6->router_id)
+    zlog_warn ("Detect duplicate Router-ID");
+
+  return MSG_OK;
+}
+
+void
+ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst,
+                  struct ospf6_interface *oi, struct ospf6_header *oh)
+{
+  struct ospf6_hello *hello;
+  struct ospf6_neighbor *on;
+  char *p;
+  int twoway = 0;
+  int neighborchange = 0;
+  int backupseen = 0;
+
+  if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK)
+    return;
+
+  hello = (struct ospf6_hello *)
+    ((caddr_t) oh + sizeof (struct ospf6_header));
+
   /* HelloInterval check */
-  if (ntohs (hello->hello_interval) != o6i->hello_interval)
+  if (ntohs (hello->hello_interval) != oi->hello_interval)
     {
-      zlog_warn ("HelloInterval mismatch with %s", o6n->str);
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("HelloInterval mismatch");
       return;
     }
 
   /* RouterDeadInterval check */
-  if (ntohs (hello->router_dead_interval)
-      != o6i->dead_interval)
+  if (ntohs (hello->dead_interval) != oi->dead_interval)
     {
-      zlog_warn ("RouterDeadInterval mismatch with %s", o6n->str);
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("RouterDeadInterval mismatch");
       return;
     }
 
-  /* check options */
-  /* Ebit */
-  if (ospf6_opt_is_mismatch (OSPF6_OPT_E, hello->options, o6i->area->options))
+  /* E-bit check */
+  if (OSPF6_OPT_ISSET (hello->options, OSPF6_OPT_E) !=
+      OSPF6_OPT_ISSET (oi->area->options, OSPF6_OPT_E))
     {
-      zlog_warn ("Ebit mismatch with %s", o6n->str);
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("E-bit mismatch");
       return;
     }
 
-  /* RouterPriority set */
-  if (o6n->priority != hello->rtr_pri)
+  /* Find neighbor, create if not exist */
+  on = ospf6_neighbor_lookup (oh->router_id, oi);
+  if (on == NULL)
     {
-      o6n->priority = hello->rtr_pri;
-      if (IS_OSPF6_DUMP_HELLO)
-        zlog_info ("%s: RouterPriority changed", o6n->str);
-      changes |= CHANGE_RTRPRI;
-    }
-
-  /* DR set */
-  if (o6n->dr != hello->dr)
-    {
-      /* save previous dr, set current */
-      o6n->prevdr = o6n->dr;
-      o6n->dr = hello->dr;
-      inet_ntop (AF_INET, &o6n->dr, strbuf, sizeof (strbuf));
-      if (IS_OSPF6_DUMP_HELLO)
-        zlog_info ("%s declare %s as DR", o6n->str, strbuf);
-      changes |= CHANGE_DR;
-    }
-
-  /* BDR set */
-  if (o6n->bdr != hello->bdr)
-    {
-      /* save previous bdr, set current */
-      o6n->prevbdr = o6n->bdr;
-      o6n->bdr = hello->bdr;
-      inet_ntop (AF_INET, &o6n->bdr, strbuf, sizeof (strbuf));
-      if (IS_OSPF6_DUMP_HELLO)
-        zlog_info ("%s declare %s as BDR", o6n->str, strbuf);
-      changes |= CHANGE_BDR;
+      on = ospf6_neighbor_create (oh->router_id, oi);
+      on->prev_drouter = on->drouter = hello->drouter;
+      on->prev_bdrouter = on->bdrouter = hello->bdrouter;
+      on->priority = hello->priority;
+      on->ifindex = ntohl (hello->interface_id);
+      memcpy (&on->linklocal_addr, src, sizeof (struct in6_addr));
     }
 
   /* TwoWay check */
-  router_id_space = length - sizeof (struct ospf6_hello);
-  seenrtrnum = router_id_space / sizeof (u_int32_t);
-  router_id_ptr = (u_int32_t *) (hello + 1);
-  for (i = 0; i < seenrtrnum; i++)
+  for (p = (char *) ((caddr_t) hello + sizeof (struct ospf6_hello));
+       p + sizeof (u_int32_t) <= OSPF6_MESSAGE_END (oh);
+       p += sizeof (u_int32_t))
     {
-      if (*router_id_ptr == o6i->area->ospf6->router_id)
+      u_int32_t *router_id = (u_int32_t *) p;
+
+      if (*router_id == oi->area->ospf6->router_id)
         twoway++;
-      router_id_ptr++;
     }
 
-  /* execute neighbor events */
-  thread_execute (master, hello_received, o6n, 0);
-  if (twoway)
-    thread_execute (master, twoway_received, o6n, 0);
-  else
-    thread_execute (master, oneway_received, o6n, 0);
+  if (p != OSPF6_MESSAGE_END (oh))
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Trailing garbage ignored");
+    }
+
+  /* RouterPriority check */
+  if (on->priority != hello->priority)
+    {
+      on->priority = hello->priority;
+      neighborchange++;
+    }
+
+  /* DR check */
+  if (on->drouter != hello->drouter)
+    {
+      on->prev_drouter = on->drouter;
+      on->drouter = hello->drouter;
+      if (on->prev_drouter == on->router_id || on->drouter == on->router_id)
+        neighborchange++;
+    }
+
+  /* BDR check */
+  if (on->bdrouter != hello->bdrouter)
+    {
+      on->prev_bdrouter = on->bdrouter;
+      on->bdrouter = hello->bdrouter;
+      if (on->prev_bdrouter == on->router_id || on->bdrouter == on->router_id)
+        neighborchange++;
+    }
 
   /* BackupSeen check */
-  if (o6i->state == IFS_WAITING)
+  if (oi->state == OSPF6_INTERFACE_WAITING)
     {
-      if (hello->dr == hello->bdr &&
-          hello->dr == o6n->router_id)
-        zlog_warn ("*** DR Election of %s is illegal", o6n->str);
-
-      if (hello->bdr == o6n->router_id)
+      if (hello->bdrouter == on->router_id)
         backupseen++;
-      else if (hello->dr == o6n->router_id && hello->bdr == 0)
+      else if (hello->drouter == on->router_id && hello->bdrouter == htonl (0))
         backupseen++;
     }
 
-  /* NeighborChange check */
-  if (changes & CHANGE_RTRPRI)
-    nbchange++;
-  if (changes & CHANGE_DR)
-    if (o6n->prevdr == o6n->router_id || o6n->dr == o6n->router_id)
-      nbchange++;
-  if (changes & CHANGE_BDR)
-    if (o6n->prevbdr == o6n->router_id || o6n->bdr == o6n->router_id)
-      nbchange++;
+  /* Execute neighbor events */
+  thread_execute (master, hello_received, on, 0);
+  if (twoway)
+    thread_execute (master, twoway_received, on, 0);
+  else
+    thread_execute (master, oneway_received, on, 0);
 
-  /* schedule interface events */
+  /* Schedule interface events */
   if (backupseen)
-    thread_add_event (master, backup_seen, o6i, 0);
-  if (nbchange)
-    thread_add_event (master, neighbor_change, o6i, 0);
-
-  return;
+    thread_add_event (master, backup_seen, oi, 0);
+  if (neighborchange)
+    thread_add_event (master, neighbor_change, oi, 0);
 }
 
-int
-ospf6_dbdesc_is_master (struct ospf6_neighbor *o6n)
+static void
+ospf6_dbdesc_recv_master (struct ospf6_header *oh,
+                          struct ospf6_neighbor *on)
 {
-  char buf[128];
-
-  if (o6n->router_id == ospf6->router_id)
-    {
-      inet_ntop (AF_INET6, &o6n->hisaddr, buf, sizeof (buf));
-      zlog_warn ("Message: Neighbor router-id conflicts: %s: %s",
-                 o6n->str, buf);
-      return -1;
-    }
-  else if (ntohl (o6n->router_id) > ntohl (ospf6->router_id))
-    return 0;
-  return 1;
-}
-
-int
-ospf6_dbdesc_is_duplicate (struct ospf6_dbdesc *received,
-                           struct ospf6_dbdesc *last_received)
-{
-  if (memcmp (received->options, last_received->options, 3) != 0)
-    return 0;
-  if (received->ifmtu != last_received->ifmtu)
-    return 0;
-  if (received->bits != last_received->bits)
-    return 0;
-  if (received->seqnum != last_received->seqnum)
-    return 0;
-  return 1;
-}
-
-void
-ospf6_process_dbdesc_master (struct iovec *message, struct ospf6_neighbor *o6n)
-{
-  struct ospf6_header *ospf6_header;
-  u_int16_t length, lsa_count;
   struct ospf6_dbdesc *dbdesc;
-  struct ospf6_lsa_header *lsa_header;
+  char *p;
 
-  /* caluculate length */
-  ospf6_header = (struct ospf6_header *) message[0].iov_base;
-  length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
-  length = (length < message[1].iov_len ? length : message[1].iov_len);
+  dbdesc = (struct ospf6_dbdesc *)
+    ((caddr_t) oh + sizeof (struct ospf6_header));
 
-  /* set database description pointer */
-  dbdesc = (struct ospf6_dbdesc *) message[1].iov_base;
-
-  switch (o6n->state)
+  if (on->state < OSPF6_NEIGHBOR_INIT)
     {
-      case NBS_DOWN:
-      case NBS_ATTEMPT:
-      case NBS_TWOWAY:
-        if (IS_OSPF6_DUMP_DBDESC)
-          zlog_info ("DbDesc from %s Ignored: state less than Init",
-                     o6n->str);
-        return;
-
-      case NBS_INIT:
-        thread_execute (master, twoway_received, o6n, 0);
-        if (o6n->state != NBS_EXSTART)
-          {
-            if (IS_OSPF6_DUMP_DBDESC)
-              zlog_info ("DbDesc from %s Ignored: state less than ExStart",
-                         o6n->str);
-            return;
-          }
-        /* else fall through to ExStart */
-      case NBS_EXSTART:
-        if (DDBIT_IS_SLAVE (dbdesc->bits) &&
-            !DDBIT_IS_INITIAL (dbdesc->bits) &&
-            ntohl (dbdesc->seqnum) == o6n->dbdesc_seqnum)
-          {
-            ospf6_neighbor_dbex_init (o6n);
-
-            if (o6n->thread_rxmt_dbdesc)
-              thread_cancel (o6n->thread_rxmt_dbdesc);
-            o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
-
-            thread_add_event (master, negotiation_done, o6n, 0);
-          }
-        else
-          {
-            if (IS_OSPF6_DUMP_DBDESC)
-              zlog_info ("  negotiation failed with %s", o6n->str);
-            return;
-          }
-        break;
-
-      case NBS_EXCHANGE:
-        /* duplicate dbdesc dropped by master */
-        if (!memcmp (dbdesc, &o6n->last_dd,
-                     sizeof (struct ospf6_dbdesc)))
-          {
-            if (IS_OSPF6_DUMP_DBDESC)
-              zlog_info ("  duplicate dbdesc, drop");
-            return;
-          }
-
-        /* check Initialize bit and Master/Slave bit */
-        if (DDBIT_IS_INITIAL (dbdesc->bits))
-          {
-            if (IS_OSPF6_DUMP_DBDESC)
-              zlog_info ("Initialize bit mismatch");
-            thread_add_event (master, seqnumber_mismatch, o6n, 0);
-            return;
-          }
-        if (DDBIT_IS_MASTER (dbdesc->bits))
-          {
-            if (IS_OSPF6_DUMP_DBDESC)
-              zlog_info ("Master/Slave bit mismatch");
-            thread_add_event (master, seqnumber_mismatch, o6n, 0);
-            return;
-          }
-
-        /* dbdesc option check */
-        if (memcmp (dbdesc->options, o6n->last_dd.options,
-                    sizeof (dbdesc->options)))
-          {
-            if (IS_OSPF6_DUMP_DBDESC)
-              zlog_info ("dbdesc option field changed");
-            thread_add_event (master, seqnumber_mismatch, o6n, 0);
-            return;
-          }
-
-        /* dbdesc sequence number check */
-        if (ntohl (dbdesc->seqnum) != o6n->dbdesc_seqnum)
-          {
-            if (IS_OSPF6_DUMP_DBDESC)
-              zlog_warn ("*** dbdesc seqnumber mismatch: %d expected",
-                         o6n->dbdesc_seqnum);
-            thread_add_event (master, seqnumber_mismatch, o6n, 0);
-            return;
-          }
-        break;
-
-      case NBS_LOADING:
-      case NBS_FULL:
-        /* duplicate dbdesc dropped by master */
-        if (ospf6_dbdesc_is_duplicate (dbdesc, &o6n->last_dd))
-          {
-            if (IS_OSPF6_DUMP_DBDESC)
-              zlog_info ("  duplicate dbdesc, drop");
-            return;
-          }
-        else
-          {
-            if (IS_OSPF6_DUMP_DBDESC)
-              zlog_info ("  not duplicate dbdesc in state %s",
-                         ospf6_neighbor_state_string[o6n->state]);
-            thread_add_event (master, seqnumber_mismatch, o6n, 0);
-            return;
-          }
-        break; /* not reached */
-
-      default:
-        assert (0);
-        break; /* not reached */
-    }
-
-  /* process LSA headers */
-  lsa_count = 0;
-  for (lsa_header = (struct ospf6_lsa_header *) (dbdesc + 1);
-       (char *)(lsa_header + 1) <= (char *)dbdesc + length;
-       lsa_header++)
-    {
-      if (ospf6_dbex_check_dbdesc_lsa_header (lsa_header, o6n) < 0)
-        {
-          thread_add_event (master, seqnumber_mismatch, o6n, 0);
-          return;
-        }
-      lsa_count ++;
-    }
-
-  /* increment dbdesc seqnum */
-  o6n->dbdesc_seqnum++;
-
-  /* cancel transmission/retransmission thread */
-  if (o6n->thread_send_dbdesc)
-    thread_cancel (o6n->thread_send_dbdesc);
-  o6n->thread_send_dbdesc = (struct thread *) NULL;
-  if (o6n->thread_rxmt_dbdesc)
-    thread_cancel (o6n->thread_rxmt_dbdesc);
-  o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
-
-  /* more bit check */
-  if (!DD_IS_MBIT_SET (dbdesc->bits) && !DD_IS_MBIT_SET (o6n->dbdesc_bits))
-    thread_add_event (master, exchange_done, o6n, 0);
-  else
-    o6n->thread_send_dbdesc =
-      thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
-
-  /* save last received dbdesc */
-  memcpy (&o6n->last_dd, dbdesc, sizeof (struct ospf6_dbdesc));
-
-  /* statistics */
-  o6n->lsa_receive[OSPF6_MESSAGE_TYPE_DBDESC] += lsa_count;
-
-  return;
-}
-
-void
-ospf6_process_dbdesc_slave (struct iovec *message, struct ospf6_neighbor *o6n)
-{
-  struct ospf6_header *ospf6_header;
-  u_int16_t length, lsa_count;
-  struct ospf6_dbdesc *dbdesc;
-  struct ospf6_lsa_header *lsa_header;
-
-  /* caluculate length */
-  ospf6_header = (struct ospf6_header *) message[0].iov_base;
-  length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
-  length = (length < message[1].iov_len ? length : message[1].iov_len);
-
-  /* set database description pointer */
-  dbdesc = (struct ospf6_dbdesc *) message[1].iov_base;
-
-  switch (o6n->state)
-    {
-      case NBS_DOWN:
-      case NBS_ATTEMPT:
-      case NBS_TWOWAY:
-        return;
-      case NBS_INIT:
-        thread_execute (master, twoway_received, o6n, 0);
-        if (o6n->state != NBS_EXSTART)
-          {
-            return;
-          }
-        /* else fall through to ExStart */
-      case NBS_EXSTART:
-        if (DD_IS_IBIT_SET (dbdesc->bits) &&
-            DD_IS_MBIT_SET (dbdesc->bits) &&
-            DD_IS_MSBIT_SET (dbdesc->bits))
-          {
-            /* Master/Slave bit set to slave */
-            DD_MSBIT_CLEAR (o6n->dbdesc_bits);
-            /* Initialize bit clear */
-            DD_IBIT_CLEAR (o6n->dbdesc_bits);
-            /* sequence number set to master's */
-            o6n->dbdesc_seqnum = ntohl (dbdesc->seqnum);
-            ospf6_neighbor_dbex_init (o6n);
-
-            if (o6n->thread_rxmt_dbdesc)
-              thread_cancel (o6n->thread_rxmt_dbdesc);
-            o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
-
-            thread_add_event (master, negotiation_done, o6n, 0);
-          }
-        else
-          {
-            if (IS_OSPF6_DUMP_DBDESC)
-              zlog_info ("negotiation failed");
-            return;
-          }
-        break;
-
-      case NBS_EXCHANGE:
-        /* duplicate dbdesc dropped by master */
-        if (!memcmp (dbdesc, &o6n->last_dd,
-                     sizeof (struct ospf6_dbdesc)))
-          {
-            if (IS_OSPF6_DUMP_DBDESC)
-              zlog_info ("  duplicate dbdesc, retransmit dbdesc");
-
-            if (o6n->thread_rxmt_dbdesc)
-              thread_cancel (o6n->thread_rxmt_dbdesc);
-            o6n->thread_rxmt_dbdesc =
-              thread_add_event (master, ospf6_send_dbdesc_rxmt, o6n, 0);
-
-            return;
-          }
-
-        /* check Initialize bit and Master/Slave bit */
-        if (DDBIT_IS_INITIAL (dbdesc->bits))
-          {
-            if (IS_OSPF6_DUMP_DBDESC)
-              zlog_info ("Initialize bit mismatch");
-            thread_add_event (master, seqnumber_mismatch, o6n, 0);
-            return;
-          }
-        if (DDBIT_IS_SLAVE (dbdesc->bits))
-          {
-            if (IS_OSPF6_DUMP_DBDESC)
-              zlog_info ("Master/Slave bit mismatch");
-            thread_add_event (master, seqnumber_mismatch, o6n, 0);
-            return;
-          }
-
-        /* dbdesc option check */
-        if (memcmp (dbdesc->options, o6n->last_dd.options,
-                    sizeof (dbdesc->options)))
-          {
-            if (IS_OSPF6_DUMP_DBDESC)
-              zlog_info ("dbdesc option field changed");
-            thread_add_event (master, seqnumber_mismatch, o6n, 0);
-            return;
-          }
-
-        /* dbdesc sequence number check */
-        if (ntohl (dbdesc->seqnum) != o6n->dbdesc_seqnum + 1)
-          {
-            if (IS_OSPF6_DUMP_DBDESC)
-              zlog_warn ("*** dbdesc seqnumber mismatch: %d expected",
-                         o6n->dbdesc_seqnum + 1);
-            thread_add_event (master, seqnumber_mismatch, o6n, 0);
-            return;
-          }
-        break;
-
-      case NBS_LOADING:
-      case NBS_FULL:
-        /* duplicate dbdesc cause slave to retransmit */
-        if (ospf6_dbdesc_is_duplicate (dbdesc, &o6n->last_dd))
-          {
-            if (IS_OSPF6_DUMP_DBDESC)
-              zlog_info ("  duplicate dbdesc, retransmit");
-
-            if (o6n->thread_rxmt_dbdesc)
-              thread_cancel (o6n->thread_rxmt_dbdesc);
-            o6n->thread_rxmt_dbdesc =
-              thread_add_event (master, ospf6_send_dbdesc_rxmt, o6n, 0);
-
-            return;
-          }
-        else
-          {
-            if (IS_OSPF6_DUMP_DBDESC)
-              zlog_info ("  not duplicate dbdesc in state %s",
-                         ospf6_neighbor_state_string[o6n->state]);
-            thread_add_event (master, seqnumber_mismatch, o6n, 0);
-            return;
-          }
-        break; /* not reached */
-
-      default:
-        assert (0);
-        break; /* not reached */
-    }
-
-  /* process LSA headers */
-  lsa_count = 0;
-  for (lsa_header = (struct ospf6_lsa_header *) (dbdesc + 1);
-       (char *)(lsa_header + 1) <= (char *)dbdesc + length;
-       lsa_header++)
-    {
-      if (ospf6_dbex_check_dbdesc_lsa_header (lsa_header, o6n) < 0)
-        {
-          thread_add_event (master, seqnumber_mismatch, o6n, 0);
-          return;
-        }
-      lsa_count ++;
-    }
-
-  /* set dbdesc seqnum to master's */
-  o6n->dbdesc_seqnum = ntohl (dbdesc->seqnum);
-
-  if (o6n->thread_send_dbdesc)
-    thread_cancel (o6n->thread_send_dbdesc);
-  o6n->thread_send_dbdesc =
-    thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
-
-  /* save last received dbdesc */
-  memcpy (&o6n->last_dd, dbdesc, sizeof (struct ospf6_dbdesc));
-
-  /* statistics */
-  o6n->lsa_receive[OSPF6_MESSAGE_TYPE_DBDESC] += lsa_count;
-
-  return;
-}
-
-void
-ospf6_process_dbdesc (struct iovec *message,
-                      struct in6_addr *src,
-                      struct in6_addr *dst,
-                      struct ospf6_interface *o6i,
-                      u_int32_t router_id)
-{
-  struct ospf6_header *ospf6_header;
-  u_int16_t length;
-  struct ospf6_neighbor *o6n;
-  struct ospf6_dbdesc *dbdesc;
-  int Im_master = 0;
-
-  /* assert interface */
-  assert (o6i);
-
-  /* caluculate length */
-  ospf6_header = (struct ospf6_header *) message[0].iov_base;
-  length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
-  length = (length < message[1].iov_len ? length : message[1].iov_len);
-
-  /* set database description pointer */
-  dbdesc = (struct ospf6_dbdesc *) message[1].iov_base;
-
-  /* find neighbor. if cannot be found, reject this message */
-  o6n = ospf6_neighbor_lookup (router_id, o6i);
-  if (!o6n)
-    {
-      if (IS_OSPF6_DUMP_DBDESC)
-        zlog_info ("neighbor not found, reject");
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Neighbor state less than Init, ignore");
       return;
     }
 
-  if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr)))
+  switch (on->state)
     {
-      if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
-        zlog_info ("From Secondary I/F of the neighbor: ignore");
+    case OSPF6_NEIGHBOR_TWOWAY:
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Neighbor state is 2-Way, ignore");
+      return;
+
+    case OSPF6_NEIGHBOR_INIT:
+      thread_execute (master, twoway_received, on, 0);
+      if (on->state != OSPF6_NEIGHBOR_EXSTART)
+        {
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("Neighbor state is not ExStart, ignore");
+          return;
+        }
+      /* else fall through to ExStart */
+
+    case OSPF6_NEIGHBOR_EXSTART:
+      /* if neighbor obeys us as our slave, schedule negotiation_done
+         and process LSA Headers. Otherwise, ignore this message */
+      if (! CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT) &&
+          ! CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_IBIT) &&
+          ntohl (dbdesc->seqnum) == on->dbdesc_seqnum)
+        {
+          /* execute NegotiationDone */
+          thread_execute (master, negotiation_done, on, 0);
+
+          /* Record neighbor options */
+          memcpy (on->options, dbdesc->options, sizeof (on->options));
+        }
+      else
+        {
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("Negotiation failed");
+          return;
+        }
+      /* fall through to exchange */
+
+    case OSPF6_NEIGHBOR_EXCHANGE:
+      if (! memcmp (dbdesc, &on->dbdesc_last, sizeof (struct ospf6_dbdesc)))
+        {
+          /* Duplicated DatabaseDescription is dropped by master */
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("Duplicated dbdesc discarded by Master, ignore");
+          return;
+        }
+
+      if (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT))
+        {
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("Master/Slave bit mismatch");
+          thread_add_event (master, seqnumber_mismatch, on, 0);
+          return;
+        }
+
+      if (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_IBIT))
+        {
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("Initialize bit mismatch");
+          thread_add_event (master, seqnumber_mismatch, on, 0);
+          return;
+        }
+
+      if (memcmp (on->options, dbdesc->options, sizeof (on->options)))
+        {
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("Option field mismatch");
+          thread_add_event (master, seqnumber_mismatch, on, 0);
+          return;
+        }
+
+      if (ntohl (dbdesc->seqnum) != on->dbdesc_seqnum)
+        {
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("Sequence number mismatch (%#lx expected)",
+                       (u_long) on->dbdesc_seqnum);
+          thread_add_event (master, seqnumber_mismatch, on, 0);
+          return;
+        }
+      break;
+
+    case OSPF6_NEIGHBOR_LOADING:
+    case OSPF6_NEIGHBOR_FULL:
+      if (! memcmp (dbdesc, &on->dbdesc_last, sizeof (struct ospf6_dbdesc)))
+        {
+          /* Duplicated DatabaseDescription is dropped by master */
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("Duplicated dbdesc discarded by Master, ignore");
+          return;
+        }
+
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Not duplicate dbdesc in state %s",
+                   ospf6_neighbor_state_str[on->state]);
+      thread_add_event (master, seqnumber_mismatch, on, 0);
+      return;
+
+    default:
+      assert (0);
+      break;
+    }
+
+  /* Process LSA headers */
+  for (p = (char *) ((caddr_t) dbdesc + sizeof (struct ospf6_dbdesc));
+       p + sizeof (struct ospf6_lsa_header) <= OSPF6_MESSAGE_END (oh);
+       p += sizeof (struct ospf6_lsa_header))
+    {
+      struct ospf6_lsa *his, *mine;
+      struct ospf6_lsdb *lsdb = NULL;
+
+      his = ospf6_lsa_create_headeronly ((struct ospf6_lsa_header *) p);
+      his->scope = ospf6_get_lsa_scope (his->header->type, on);
+      lsdb = ospf6_get_scoped_lsdb (his->header->type, his->scope);
+      if (lsdb == NULL)
+        {
+          zlog_warn ("Can't decide scoped LSDB");
+          ospf6_lsa_delete (his);
+          thread_add_event (master, seqnumber_mismatch, on, 0);
+          return;
+        }
+
+      if (ntohs (his->header->type) == OSPF6_LSTYPE_AS_EXTERNAL &&
+          ospf6_area_is_stub (on->ospf6_if->area))
+        {
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("E-bit mismatch with LSA Headers");
+          ospf6_lsa_delete (his);
+          thread_add_event (master, seqnumber_mismatch, on, 0);
+          return;
+        }
+
+      mine = ospf6_lsdb_lookup (his->header->type, his->header->id,
+                                his->header->adv_router, lsdb);
+      if (mine == NULL || ospf6_lsa_compare (his, mine) < 0)
+        {
+          if (IS_OSPF6_DEBUG_LSA (RECV) || IS_OSPF6_DEBUG_LSA (DATABASE))
+            zlog_info ("Add %s's request-list: %s", on->name, his->name);
+          ospf6_lsdb_add (his, on->request_list);
+        }
+      else
+        ospf6_lsa_delete (his);
+    }
+
+  if (p != OSPF6_MESSAGE_END (oh))
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Trailing garbage ignored");
+    }
+
+  /* Increment sequence number */
+  on->dbdesc_seqnum ++;
+
+  /* schedule send lsreq */
+  if (on->thread_send_lsreq == NULL)
+    on->thread_send_lsreq =
+      thread_add_event (master, ospf6_lsreq_send, on, 0);
+
+  THREAD_OFF (on->thread_send_dbdesc);
+
+  /* More bit check */
+  if (! CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MBIT) &&
+      ! CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT))
+    thread_add_event (master, exchange_done, on, 0);
+  else
+    on->thread_send_dbdesc =
+      thread_add_event (master, ospf6_dbdesc_send_newone, on, 0);
+
+  /* save last received dbdesc */
+  memcpy (&on->dbdesc_last, dbdesc, sizeof (struct ospf6_dbdesc));
+}
+
+static void
+ospf6_dbdesc_recv_slave (struct ospf6_header *oh,
+                         struct ospf6_neighbor *on)
+{
+  struct ospf6_dbdesc *dbdesc;
+  char *p;
+
+  dbdesc = (struct ospf6_dbdesc *)
+    ((caddr_t) oh + sizeof (struct ospf6_header));
+
+  if (on->state < OSPF6_NEIGHBOR_INIT)
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Neighbor state less than Init, ignore");
       return;
     }
 
-  /* interface mtu check */
-    /* xxx */
-
-  /* check am I master */
-  Im_master = ospf6_dbdesc_is_master (o6n);
-  if (Im_master < 0)
+  switch (on->state)
     {
-      return; /* can't decide which is master, return */
+    case OSPF6_NEIGHBOR_TWOWAY:
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Neighbor state is 2-Way, ignore");
+      return;
+
+    case OSPF6_NEIGHBOR_INIT:
+      thread_execute (master, twoway_received, on, 0);
+      if (on->state != OSPF6_NEIGHBOR_EXSTART)
+        {
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("Neighbor state is not ExStart, ignore");
+          return;
+        }
+      /* else fall through to ExStart */
+
+    case OSPF6_NEIGHBOR_EXSTART:
+      /* If the neighbor is Master, act as Slave. Schedule negotiation_done
+         and process LSA Headers. Otherwise, ignore this message */
+      if (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_IBIT) &&
+          CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MBIT) &&
+          CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT) &&
+          ntohs (oh->length) == sizeof (struct ospf6_header) +
+                                sizeof (struct ospf6_dbdesc))
+        {
+          /* set the master/slave bit to slave */
+          UNSET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT);
+
+          /* set the DD sequence number to one specified by master */
+          on->dbdesc_seqnum = ntohl (dbdesc->seqnum);
+
+          /* schedule NegotiationDone */
+          thread_execute (master, negotiation_done, on, 0);
+
+          /* Record neighbor options */
+          memcpy (on->options, dbdesc->options, sizeof (on->options));
+        }
+      else
+        {
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("Negotiation failed");
+          return;
+        }
+      break;
+
+    case OSPF6_NEIGHBOR_EXCHANGE:
+      if (! memcmp (dbdesc, &on->dbdesc_last, sizeof (struct ospf6_dbdesc)))
+        {
+          /* Duplicated DatabaseDescription causes slave to retransmit */
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("Duplicated dbdesc causes retransmit");
+          THREAD_OFF (on->thread_send_dbdesc);
+          on->thread_send_dbdesc =
+            thread_add_event (master, ospf6_dbdesc_send, on, 0);
+          return;
+        }
+
+      if (! CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT))
+        {
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("Master/Slave bit mismatch");
+          thread_add_event (master, seqnumber_mismatch, on, 0);
+          return;
+        }
+
+      if (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_IBIT))
+        {
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("Initialize bit mismatch");
+          thread_add_event (master, seqnumber_mismatch, on, 0);
+          return;
+        }
+
+      if (memcmp (on->options, dbdesc->options, sizeof (on->options)))
+        {
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("Option field mismatch");
+          thread_add_event (master, seqnumber_mismatch, on, 0);
+          return;
+        }
+
+      if (ntohl (dbdesc->seqnum) != on->dbdesc_seqnum + 1)
+        {
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("Sequence number mismatch (%#lx expected)",
+                       (u_long) on->dbdesc_seqnum + 1);
+          thread_add_event (master, seqnumber_mismatch, on, 0);
+          return;
+        }
+      break;
+
+    case OSPF6_NEIGHBOR_LOADING:
+    case OSPF6_NEIGHBOR_FULL:
+      if (! memcmp (dbdesc, &on->dbdesc_last, sizeof (struct ospf6_dbdesc)))
+        {
+          /* Duplicated DatabaseDescription causes slave to retransmit */
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("Duplicated dbdesc causes retransmit");
+          THREAD_OFF (on->thread_send_dbdesc);
+          on->thread_send_dbdesc =
+            thread_add_event (master, ospf6_dbdesc_send, on, 0);
+          return;
+        }
+
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Not duplicate dbdesc in state %s",
+                   ospf6_neighbor_state_str[on->state]);
+      thread_add_event (master, seqnumber_mismatch, on, 0);
+      return;
+
+    default:
+      assert (0);
+      break;
     }
 
-  if (Im_master)
-    ospf6_process_dbdesc_master (message, o6n);
-  else
-    ospf6_process_dbdesc_slave (message, o6n);
+  /* Process LSA headers */
+  for (p = (char *) ((caddr_t) dbdesc + sizeof (struct ospf6_dbdesc));
+       p + sizeof (struct ospf6_lsa_header) <= OSPF6_MESSAGE_END (oh);
+       p += sizeof (struct ospf6_lsa_header))
+    {
+      struct ospf6_lsa *his, *mine;
+      struct ospf6_lsdb *lsdb = NULL;
 
-  return;
+      his = ospf6_lsa_create_headeronly ((struct ospf6_lsa_header *) p);
+      his->scope = ospf6_get_lsa_scope (his->header->type, on);
+      lsdb = ospf6_get_scoped_lsdb (his->header->type, his->scope);
+      if (lsdb == NULL)
+        {
+          zlog_warn ("Can't decide scoped LSDB");
+          ospf6_lsa_delete (his);
+          thread_add_event (master, seqnumber_mismatch, on, 0);
+          return;
+        }
+
+      if (ntohs (his->header->type) == OSPF6_LSTYPE_AS_EXTERNAL &&
+          ospf6_area_is_stub (on->ospf6_if->area))
+        {
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("E-bit mismatch with LSA Headers");
+          ospf6_lsa_delete (his);
+          thread_add_event (master, seqnumber_mismatch, on, 0);
+          return;
+        }
+
+      mine = ospf6_lsdb_lookup (his->header->type, his->header->id,
+                                his->header->adv_router, lsdb);
+      if (mine == NULL || ospf6_lsa_compare (his, mine) < 0)
+        {
+          if (IS_OSPF6_DEBUG_LSA (RECV) || IS_OSPF6_DEBUG_LSA (DATABASE))
+            zlog_info ("Add %s to request-list of %s", his->name, on->name);
+          ospf6_lsdb_add (his, on->request_list);
+        }
+      else
+        ospf6_lsa_delete (his);
+    }
+
+  if (p != OSPF6_MESSAGE_END (oh))
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Trailing garbage ignored");
+    }
+
+  /* Set sequence number to Master's */
+  on->dbdesc_seqnum = ntohl (dbdesc->seqnum);
+
+  /* schedule send lsreq */
+  if (on->thread_send_lsreq == NULL)
+    on->thread_send_lsreq =
+      thread_add_event (master, ospf6_lsreq_send, on, 0);
+
+  THREAD_OFF (on->thread_send_dbdesc);
+  on->thread_send_dbdesc =
+    thread_add_event (master, ospf6_dbdesc_send_newone, on, 0);
+
+  /* save last received dbdesc */
+  memcpy (&on->dbdesc_last, dbdesc, sizeof (struct ospf6_dbdesc));
 }
 
 void
-ospf6_process_lsreq (struct iovec *message,
-                     struct in6_addr *src,
-                     struct in6_addr *dst,
-                     struct ospf6_interface *o6i,
-                     u_int32_t router_id)
+ospf6_dbdesc_recv (struct in6_addr *src, struct in6_addr *dst,
+                   struct ospf6_interface *oi, struct ospf6_header *oh)
 {
-  struct ospf6_header *ospf6_header;
-  u_int16_t length;
-  struct ospf6_neighbor *o6n;
-  struct ospf6_lsreq *lsreq;
-  struct iovec response[OSPF6_MESSAGE_IOVEC_SIZE];
+  struct ospf6_neighbor *on;
+  struct ospf6_dbdesc *dbdesc;
+
+  if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK)
+    return;
+
+  on = ospf6_neighbor_lookup (oh->router_id, oi);
+  if (on == NULL)
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Neighbor not found, ignore");
+      return;
+    }
+
+  if (memcmp (src, &on->linklocal_addr, sizeof (struct in6_addr)))
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Seems to be from Secondary I/F of the neighbor, ignore");
+      return;
+    }
+
+  dbdesc = (struct ospf6_dbdesc *)
+    ((caddr_t) oh + sizeof (struct ospf6_header));
+
+  /* Interface MTU check */
+  if (ntohs (dbdesc->ifmtu) != oi->ifmtu)
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("I/F MTU mismatch");
+      return;
+    }
+
+  if (dbdesc->reserved1 || dbdesc->reserved2)
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Non-0 reserved field in %s's DbDesc, correct",
+                   on->name);
+      dbdesc->reserved1 = 0;
+      dbdesc->reserved2 = 0;
+    }
+
+  if (ntohl (oh->router_id) < ntohl (ospf6->router_id))
+    ospf6_dbdesc_recv_master (oh, on);
+  else if (ntohl (ospf6->router_id) < ntohl (oh->router_id))
+    ospf6_dbdesc_recv_slave (oh, on);
+  else
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Can't decide which is master, ignore");
+    }
+}
+
+void
+ospf6_lsreq_recv (struct in6_addr *src, struct in6_addr *dst,
+                  struct ospf6_interface *oi, struct ospf6_header *oh)
+{
+  struct ospf6_neighbor *on;
+  char *p;
+  struct ospf6_lsreq_entry *e;
+  void *scope = NULL;
+  struct ospf6_lsdb *lsdb = NULL;
   struct ospf6_lsa *lsa;
-  unsigned long lsanum = 0;
-  struct ospf6_lsupdate lsupdate;
-  char buf_id[16], buf_router[16], buf_type[16];
 
-  /* assert interface */
-  assert (o6i);
+  if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK)
+    return;
 
-  /* caluculate length */
-  ospf6_header = (struct ospf6_header *) message[0].iov_base;
-  length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
-  length = (length < message[1].iov_len ? length : message[1].iov_len);
-
-  /* find neighbor. if cannot be found, reject this message */
-  o6n = ospf6_neighbor_lookup (router_id, o6i);
-  if (!o6n)
+  on = ospf6_neighbor_lookup (oh->router_id, oi);
+  if (on == NULL)
     {
-      if (IS_OSPF6_DUMP_LSREQ)
-        zlog_info ("  neighbor not found, reject");
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Neighbor not found, ignore");
       return;
     }
 
-  if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr)))
+  if (memcmp (src, &on->linklocal_addr, 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_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Seems to be from Secondary I/F of the neighbor, ignore");
       return;
     }
 
-  /* In states other than ExChange, Loading, or Full, the packet
-     should be ignored. */
-  if (o6n->state != NBS_EXCHANGE && o6n->state != NBS_LOADING
-      && o6n->state != NBS_FULL)
+  if (on->state != OSPF6_NEIGHBOR_EXCHANGE &&
+      on->state != OSPF6_NEIGHBOR_LOADING &&
+      on->state != OSPF6_NEIGHBOR_FULL)
     {
-      if (IS_OSPF6_DUMP_LSREQ)
-        zlog_info ("  neighbor state less than Exchange, reject");
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Neighbor state less than Exchange, ignore");
       return;
     }
 
-  /* Initialize response LSUpdate packet */
-  OSPF6_MESSAGE_CLEAR (response);
-  memset (&lsupdate, 0, sizeof (struct ospf6_lsupdate));
-  OSPF6_MESSAGE_ATTACH (response, &lsupdate, sizeof (struct ospf6_lsupdate));
-
-  /* process each request */
-  lsanum = 0;
-  for (lsreq = (struct ospf6_lsreq *) message[1].iov_base;
-       (char *)(lsreq + 1) <= (char *)(message[1].iov_base + length);
-       lsreq++)
+  /* Process each request */
+  for (p = (char *) ((caddr_t) oh + sizeof (struct ospf6_header));
+       p + sizeof (struct ospf6_lsreq_entry) <= OSPF6_MESSAGE_END (oh);
+       p += sizeof (struct ospf6_lsreq_entry))
     {
-      inet_ntop (AF_INET, &lsreq->adv_router, buf_router, sizeof (buf_router));
-      inet_ntop (AF_INET, &lsreq->id, buf_id, sizeof (buf_id));
+      e = (struct ospf6_lsreq_entry *) p;
+      scope = ospf6_get_lsa_scope (e->type, on);
+      lsdb = ospf6_get_scoped_lsdb (e->type, scope);
 
-      /* find instance of database copy */
-      lsa = ospf6_lsdb_lookup (lsreq->type, lsreq->id, lsreq->adv_router,
-                               ospf6_lsa_get_scope (lsreq->type, o6i));
-
-      if (!lsa)
+      /* Find database copy */
+      lsa = ospf6_lsdb_lookup (e->type, e->id, e->adv_router, lsdb);
+      if (lsa == NULL)
         {
-          if (IS_OSPF6_DUMP_LSREQ)
-            zlog_info ("BadLSReq: %s requests [%s ID=%s Adv=%s] not found",
-                       o6n->str, ospf6_lsa_type_string (lsreq->type, buf_type,
-                                                        sizeof (buf_type)),
-                       buf_id, buf_router);
-          thread_add_event (master, bad_lsreq, o6n, 0);
+          char id[16], adv_router[16];
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            {
+              inet_ntop (AF_INET, &e->id, id, sizeof (id));
+              inet_ntop (AF_INET, &e->adv_router, adv_router,
+                     sizeof (adv_router));
+              zlog_info ("Can't find requested [%s Id:%s Adv:%s]",
+                         OSPF6_LSTYPE_NAME (e->type), id, adv_router);
+            }
+          thread_add_event (master, bad_lsreq, on, 0);
           return;
         }
 
-      /* I/F MTU check */
-      if (sizeof (struct ospf6_header) + sizeof (struct ospf6_lsupdate)
-          + iov_totallen (response) + ntohs (lsa->header->length)
-          > o6i->ifmtu)
-        break;
-
-      OSPF6_MESSAGE_ATTACH (response, lsa->header, ntohs (lsa->header->length));
-      lsanum++;
+      if (IS_OSPF6_DEBUG_LSA (DATABASE))
+        zlog_info ("Add copy of %s to lsupdate_list of %s",
+                   lsa->name, on->name);
+      ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->lsupdate_list);
     }
 
-  /* send response LSUpdate to this request */
-  if (lsanum)
+  if (p != OSPF6_MESSAGE_END (oh))
     {
-      lsupdate.lsupdate_num = htonl (lsanum);
-
-      ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, response,
-                          &o6n->hisaddr, o6i->if_id);
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Trailing garbage ignored");
     }
 
-  /* statistics */
-  o6n->lsa_receive[OSPF6_MESSAGE_TYPE_LSREQ]
-    += length / sizeof (struct ospf6_lsreq);
+  /* schedule send lsupdate */
+  THREAD_OFF (on->thread_send_lsupdate);
+  on->thread_send_lsupdate =
+    thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0);
 }
 
 void
-ospf6_process_lsupdate (struct iovec *message,
-                        struct in6_addr *src,
-                        struct in6_addr *dst,
-                        struct ospf6_interface *o6i,
-                        u_int32_t router_id)
+ospf6_lsupdate_recv (struct in6_addr *src, struct in6_addr *dst,
+                     struct ospf6_interface *oi, struct ospf6_header *oh)
 {
-  struct ospf6_header *ospf6_header;
-  u_int16_t length;
+  struct ospf6_neighbor *on;
   struct ospf6_lsupdate *lsupdate;
-  struct ospf6_neighbor *o6n;
-  unsigned long lsanum;
-  struct ospf6_lsa_header *lsa_header;
+  unsigned long num;
+  char *p;
 
-  /* assert interface */
-  assert (o6i);
+  if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK)
+    return;
 
-  /* caluculate length */
-  ospf6_header = (struct ospf6_header *) message[0].iov_base;
-  length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
-  length = (length < message[1].iov_len ? length : message[1].iov_len);
-
-  /* find neighbor. if cannot be found, reject this message */
-  o6n = ospf6_neighbor_lookup (router_id, o6i);
-  if (! o6n)
+  on = ospf6_neighbor_lookup (oh->router_id, oi);
+  if (on == NULL)
     {
-      if (IS_OSPF6_DUMP_LSUPDATE)
-        zlog_info ("  neighbor not found, reject");
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Neighbor not found, ignore");
       return;
     }
 
-  if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr)))
+  if (memcmp (src, &on->linklocal_addr, 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_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Seems to be from Secondary I/F of the neighbor, ignore");
       return;
     }
 
-  /* if neighbor state less than ExChange, reject this message */
-  if (o6n->state < NBS_EXCHANGE)
+  if (on->state != OSPF6_NEIGHBOR_EXCHANGE &&
+      on->state != OSPF6_NEIGHBOR_LOADING &&
+      on->state != OSPF6_NEIGHBOR_FULL)
     {
-      if (IS_OSPF6_DUMP_LSUPDATE)
-        zlog_info ("  neighbor state less than Exchange, reject");
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Neighbor state less than Exchange, ignore");
       return;
     }
 
-  /* set linkstate update pointer */
-  lsupdate = (struct ospf6_lsupdate *) message[1].iov_base;
+  lsupdate = (struct ospf6_lsupdate *)
+    ((caddr_t) oh + sizeof (struct ospf6_header));
 
-  /* save linkstate update info */
-  lsanum = ntohl (lsupdate->lsupdate_num);
+  num = ntohl (lsupdate->lsa_number);
 
-  /* statistics */
-  o6n->ospf6_stat_received_lsa += lsanum;
-  o6n->ospf6_stat_received_lsupdate++;
+  /* Process LSAs */
+  for (p = (char *) ((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate));
+       p < OSPF6_MESSAGE_END (oh) &&
+       p + OSPF6_LSA_SIZE (p) <= OSPF6_MESSAGE_END (oh);
+       p += OSPF6_LSA_SIZE (p))
+    {
+      if (num == 0)
+        break;
+      if (OSPF6_LSA_SIZE (p) < sizeof (struct ospf6_lsa_header))
+        {
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("Malformed LSA length, quit processing");
+          break;
+        }
+
+      ospf6_receive_lsa ((struct ospf6_lsa_header *) p, on);
+      num--;
+    }
+
+  if (num != 0)
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Malformed LSA number or LSA length");
+    }
+  if (p != OSPF6_MESSAGE_END (oh))
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Trailing garbage ignored");
+    }
 
   /* RFC2328 Section 10.9: When the neighbor responds to these requests
      with the proper Link State Update packet(s), the Link state request
      list is truncated and a new Link State Request packet is sent. */
-
-  /* process LSAs */
-  for (lsa_header = (struct ospf6_lsa_header *) (lsupdate + 1);
-       lsanum && (char *)lsa_header < (char *)lsupdate + length;
-       lsanum--)
-    {
-      ospf6_dbex_receive_lsa (lsa_header, o6n);
-      lsa_header = OSPF6_LSA_NEXT (lsa_header);
-    }
-
   /* send new Link State Request packet if this LS Update packet
-     can be recognized as a response to our previous LS request */
-  if (! IN6_IS_ADDR_MULTICAST(dst) &&
-      (o6n->state == NBS_EXCHANGE || o6n->state == NBS_LOADING))
-    thread_add_event (master, ospf6_send_lsreq, o6n, 0);
-
-  return;
+     can be recognized as a response to our previous LS Request */
+  if (! IN6_IS_ADDR_MULTICAST (dst) &&
+      (on->state == OSPF6_NEIGHBOR_EXCHANGE ||
+       on->state == OSPF6_NEIGHBOR_LOADING))
+    {
+      THREAD_OFF (on->thread_send_lsreq);
+      on->thread_send_lsreq =
+        thread_add_event (master, ospf6_lsreq_send, on, 0);
+    }
 }
 
 void
-ospf6_process_lsack (struct iovec *message,
-                     struct in6_addr *src,
-                     struct in6_addr *dst,
-                     struct ospf6_interface *o6i,
-                     u_int32_t router_id)
+ospf6_lsack_recv (struct in6_addr *src, struct in6_addr *dst,
+                  struct ospf6_interface *oi, struct ospf6_header *oh)
 {
-  struct ospf6_header *ospf6_header;
-  u_int16_t length;
-  struct ospf6_neighbor *o6n;
-  struct ospf6_lsa_header *lsa_header;
-  struct ospf6_lsa *lsa, *copy, *rem;
+  struct ospf6_neighbor *on;
+  char *p;
+  struct ospf6_lsa *his, *mine;
+  struct ospf6_lsdb *lsdb = NULL;
 
-  /* assert interface */
-  assert (o6i);
+  assert (oh->type == OSPF6_MESSAGE_TYPE_LSACK);
+  if (ospf6_header_examin (src, dst, oi, oh) != MSG_OK)
+    return;
 
-  /* caluculate length */
-  ospf6_header = (struct ospf6_header *) message[0].iov_base;
-  length = ntohs (ospf6_header->len) - sizeof (struct ospf6_header);
-  length = (length < message[1].iov_len ? length : message[1].iov_len);
-
-  /* find neighbor. if cannot be found, reject this message */
-  o6n = ospf6_neighbor_lookup (router_id, o6i);
-  if (!o6n)
+  on = ospf6_neighbor_lookup (oh->router_id, oi);
+  if (on == NULL)
     {
-      if (IS_OSPF6_DUMP_LSACK)
-        zlog_info ("LSACK: neighbor not found, reject");
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Neighbor not found, ignore");
       return;
     }
 
-  if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr)))
+  if (memcmp (src, &on->linklocal_addr, sizeof (struct in6_addr)))
     {
-      if (IS_OSPF6_DUMP_LSACK)
-        zlog_info ("LSACK: From Secondary I/F of the neighbor: ignore");
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Seems to be from Secondary I/F of the neighbor, ignore");
       return;
     }
 
-  /* if neighbor state less than ExChange, reject this message */
-  if (o6n->state < NBS_EXCHANGE)
+  if (on->state != OSPF6_NEIGHBOR_EXCHANGE &&
+      on->state != OSPF6_NEIGHBOR_LOADING &&
+      on->state != OSPF6_NEIGHBOR_FULL)
     {
-      if (IS_OSPF6_DUMP_LSACK)
-        zlog_info ("LSACK: neighbor state less than Exchange, reject");
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Neighbor state less than Exchange, ignore");
       return;
     }
 
-  /* process each LSA header */
-  for (lsa_header = (struct ospf6_lsa_header *) message[1].iov_base;
-       (char *)(lsa_header + 1) <= (char *)(message[1].iov_base + length);
-       lsa_header++)
+  for (p = (char *) ((caddr_t) oh + sizeof (struct ospf6_header));
+       p + sizeof (struct ospf6_lsa_header) <= OSPF6_MESSAGE_END (oh);
+       p += sizeof (struct ospf6_lsa_header))
     {
-      /* find database copy */
-      copy = ospf6_lsdb_lookup (lsa_header->type, lsa_header->ls_id,
-                                lsa_header->advrtr,
-                                ospf6_lsa_get_scope (lsa_header->type, o6i));
+      his = ospf6_lsa_create_headeronly ((struct ospf6_lsa_header *) p);
+      his->scope = ospf6_get_lsa_scope (his->header->type, on);
+      lsdb = ospf6_get_scoped_lsdb (his->header->type, his->scope);
 
-      /* if no database copy */
-      if (!copy)
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV) ||
+          IS_OSPF6_DEBUG_LSA (SEND))
+        zlog_info ("%s acknowledged by %s", his->name, on->name);
+
+      /* Find database copy */
+      mine = ospf6_lsdb_lookup (his->header->type, his->header->id,
+                                his->header->adv_router, lsdb);
+      if (mine == NULL)
         {
-          if (IS_OSPF6_DUMP_LSACK)
-            zlog_info ("LSACK: no database copy, ignore");
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("No database copy");
+          ospf6_lsa_delete (his);
           continue;
         }
 
-      /* if not on his retrans list */
-      rem = ospf6_lsdb_lookup_lsdb (copy->header->type, copy->header->id,
-                                    copy->header->adv_router,
-                                    o6n->retrans_list);
-      if (rem == NULL)
+      /* Check if the LSA is on his retrans-list */
+      mine = ospf6_lsdb_lookup (his->header->type, his->header->id,
+                                his->header->adv_router, on->retrans_list);
+      if (mine == NULL)
         {
-          if (IS_OSPF6_DUMP_LSACK)
-            zlog_info ("LSACK: not on %s's retranslist, ignore", o6n->str);
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("Not on %s's retrans-list", on->name);
+          ospf6_lsa_delete (his);
           continue;
         }
 
-      /* create temporary LSA from Ack message */
-      lsa = ospf6_lsa_summary_create ((struct ospf6_lsa_header__ *) lsa_header);
-
-      /* if the same instance, remove from retrans list.
-         else, log and ignore */
-      if (ospf6_lsa_check_recent (lsa, copy) == 0)
-        ospf6_neighbor_retrans_remove (rem, o6n);
-      else
+      if (ospf6_lsa_compare (his, mine) != 0)
         {
-          /* Log the questionable acknowledgement,
+          /* Log this questionable acknowledgement,
              and examine the next one. */
-          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));
+          if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+            zlog_info ("Questionable acknowledgement");
+          ospf6_lsa_delete (his);
+          continue;
         }
 
-      /* release temporary LSA from Ack message */
-      ospf6_lsa_delete (lsa);
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV) ||
+          IS_OSPF6_DEBUG_LSA (SEND))
+        zlog_info ("Acknowledged, remove from %s's retrans-list",
+                   on->name);
+
+      if (OSPF6_LSA_IS_MAXAGE (mine))
+        ospf6_maxage_remove (on->ospf6_if->area->ospf6);
+
+      if (IS_OSPF6_DEBUG_LSA (DATABASE))
+        zlog_info ("remove %s from retrans_list of %s",
+                   mine->name, on->name);
+      ospf6_lsdb_remove (mine, on->retrans_list);
+      ospf6_lsa_delete (his);
     }
 
-  ospf6_maxage_remover ();
-  return;
+  if (p != OSPF6_MESSAGE_END (oh))
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Trailing garbage ignored");
+    }
 }
 
-struct {
-  void (*process) (struct iovec *, struct in6_addr *, struct in6_addr *,
-                   struct ospf6_interface *, u_int32_t);
-} ospf6_message_process_type [] =
-{
-  {ospf6_process_unknown},
-  {ospf6_process_hello},
-  {ospf6_process_dbdesc},
-  {ospf6_process_lsreq},
-  {ospf6_process_lsupdate},
-  {ospf6_process_lsack}
-};
-
-/* process ospf6 protocol header. then, call next process function
-   for each message type */
-static void 
-ospf6_message_process (struct iovec *message,
-                       struct in6_addr *src,
-                       struct in6_addr *dst,
-                       struct ospf6_interface *o6i)
-{
-  struct ospf6_header *ospf6_header = NULL;
-  u_char type;
-  u_int32_t router_id;
-  char srcname[64];
-
-  assert (o6i);
-  assert (src);
-  assert (dst);
-
-  /* set ospf6_hdr pointer to head of buffer */
-  ospf6_header = (struct ospf6_header *) message[0].iov_base;
-
-  /* version check */
-  if (ospf6_header->version != OSPF6_VERSION)
-    {
-      if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
-        zlog_info ("version mismatch, drop");
-      return;
-    }
-
-  /* area id check */
-  if (ospf6_header->area_id != o6i->area->area_id)
-    {
-      if (ospf6_header->area_id == 0)
-        {
-          if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
-            zlog_info ("virtual link not yet, drop");
-          return;
-        }
-
-      if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
-        zlog_info ("area id mismatch, drop");
-      return;
-    }
-
-  /* instance id check */
-  if (ospf6_header->instance_id != o6i->instance_id)
-    {
-      if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
-        zlog_info ("instance id mismatch, drop");
-      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)
-    {
-      inet_ntop (AF_INET6, src, srcname, sizeof (srcname));
-      zlog_warn ("*** Router-ID mismatch: from %s on %s",
-                 srcname, o6i->interface->name);
-      return;
-    }
-
-  /* octet statistics relies on some asumption:
-       on ethernet, no IPv6 Extention header, etc */
-#define OSPF6_IP6_HEADER_SIZE   40
-#define OSPF6_ETHER_HEADER_SIZE 14
-  o6i->message_stat[type].recv++;
-  o6i->message_stat[type].recv_octet += ntohs (ospf6_header->len)
-    + OSPF6_IP6_HEADER_SIZE + OSPF6_ETHER_HEADER_SIZE;
-
-  /* futher process */
-  (*ospf6_message_process_type[type].process) (&message[0], src, dst, o6i, router_id);
-
-  return;
-}
+char recvbuf[OSPF6_MESSAGE_BUFSIZ];
+char sendbuf[OSPF6_MESSAGE_BUFSIZ];
 
 int
 ospf6_receive (struct thread *thread)
 {
-  int sockfd;
+  int sockfd, len;
+  char srcname[64], dstname[64];
   struct in6_addr src, dst;
   unsigned int ifindex;
-  struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
-  struct ospf6_header ospf6_header;
-  char buffer[OSPF6_MESSAGE_RECEIVE_BUFSIZE];
-  struct ospf6_interface *o6i;
-  unsigned char type;
-
-  /* get socket */
-  sockfd = THREAD_FD (thread);
+  struct iovec iovector[2];
+  struct ospf6_interface *oi;
+  struct ospf6_header *oh;
 
   /* add next read thread */
+  sockfd = THREAD_FD (thread);
   thread_add_read (master, ospf6_receive, NULL, sockfd);
 
   /* initialize */
-  OSPF6_MESSAGE_CLEAR (message);
-  memset (&ospf6_header, 0, sizeof (struct ospf6_header));
-
-  OSPF6_MESSAGE_ATTACH (message, &ospf6_header, sizeof (struct ospf6_header));
-  OSPF6_MESSAGE_ATTACH (message, buffer, OSPF6_MESSAGE_RECEIVE_BUFSIZE);
+  memset (recvbuf, 0, sizeof (recvbuf));
+  iovector[0].iov_base = recvbuf;
+  iovector[0].iov_len = sizeof (recvbuf);
+  iovector[1].iov_base = NULL;
+  iovector[1].iov_len = 0;
 
   /* receive message */
-  ospf6_recvmsg (&src, &dst, &ifindex, message);
-
-  type = (OSPF6_MESSAGE_TYPE_UNKNOWN < ospf6_header.type &&
-          ospf6_header.type <= OSPF6_MESSAGE_TYPE_LSACK ?
-          ospf6_header.type : OSPF6_MESSAGE_TYPE_UNKNOWN);
-  o6i = ospf6_interface_lookup_by_index (ifindex);
-  if (!o6i || !o6i->area)
+  len = ospf6_recvmsg (&src, &dst, &ifindex, iovector);
+  if (len > sizeof (recvbuf))
     {
-      //zlog_warn ("*** received interface ospf6 disabled");
+      zlog_err ("Excess message read");
+      return 0;
+    }
+  else if (len < sizeof (struct ospf6_header))
+    {
+      zlog_err ("Deficient message read");
       return 0;
     }
 
-  /* if not passive, process message */
-  if (! CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE))
-    ospf6_message_process (message, &src, &dst, o6i);
-  else if (IS_OSPF6_DUMP_MESSAGE (type))
-    zlog_info ("Ignore message on passive interface %s",
-               o6i->interface->name);
+  oi = ospf6_interface_lookup_by_ifindex (ifindex);
+  if (oi == NULL || oi->area == NULL)
+    {
+      zlog_info ("Message received on disabled interface");
+      return 0;
+    }
+
+  oh = (struct ospf6_header *) recvbuf;
+
+  /* Log */
+  if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+    {
+      inet_ntop (AF_INET6, &src, srcname, sizeof (srcname));
+      inet_ntop (AF_INET6, &dst, dstname, sizeof (dstname));
+      zlog_info ("%s received on %s",
+                 OSPF6_MESSAGE_TYPE_NAME (oh->type), oi->interface->name);
+      zlog_info ("    src: %s", srcname);
+      zlog_info ("    dst: %s", dstname);
+      if (len != ntohs (oh->length))
+        zlog_info ("Message length does not match actually received: %d", len);
+
+      switch (oh->type)
+        {
+          case OSPF6_MESSAGE_TYPE_HELLO:
+            ospf6_hello_print (oh);
+            break;
+          case OSPF6_MESSAGE_TYPE_DBDESC:
+            ospf6_dbdesc_print (oh);
+            break;
+          case OSPF6_MESSAGE_TYPE_LSREQ:
+            ospf6_lsreq_print (oh);
+            break;
+          case OSPF6_MESSAGE_TYPE_LSUPDATE:
+            ospf6_lsupdate_print (oh);
+            break;
+          case OSPF6_MESSAGE_TYPE_LSACK:
+            ospf6_lsack_print (oh);
+            break;
+          default:
+            zlog_info ("Unknown message");
+            break;
+        }
+    }
+
+  if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE))
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV))
+        zlog_info ("Ignore message on passive interface %s",
+                   oi->interface->name);
+      return 0;
+    }
+
+  switch (oh->type)
+    {
+      case OSPF6_MESSAGE_TYPE_HELLO:
+        ospf6_hello_recv (&src, &dst, oi, oh);
+        break;
+
+      case OSPF6_MESSAGE_TYPE_DBDESC:
+        ospf6_dbdesc_recv (&src, &dst, oi, oh);
+        break;
+
+      case OSPF6_MESSAGE_TYPE_LSREQ:
+        ospf6_lsreq_recv (&src, &dst, oi, oh);
+        break;
+
+      case OSPF6_MESSAGE_TYPE_LSUPDATE:
+        ospf6_lsupdate_recv (&src, &dst, oi, oh);
+        break;
+
+      case OSPF6_MESSAGE_TYPE_LSACK:
+        ospf6_lsack_recv (&src, &dst, oi, oh);
+        break;
+
+      default:
+        if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+          zlog_info ("Unknown message");
+        break;
+    }
+
+  return 0;
+}
+
+void
+ospf6_send (struct in6_addr *src, struct in6_addr *dst,
+            struct ospf6_interface *oi, struct ospf6_header *oh)
+{
+  int len;
+  char srcname[64], dstname[64];
+  struct iovec iovector[2];
+
+  /* initialize */
+  iovector[0].iov_base = (caddr_t) oh;
+  iovector[0].iov_len = ntohs (oh->length);
+  iovector[1].iov_base = NULL;
+  iovector[1].iov_len = 0;
+
+  /* fill OSPF header */
+  oh->version = OSPFV3_VERSION;
+  /* message type must be set before */
+  /* message length must be set before */
+  oh->router_id = oi->area->ospf6->router_id;
+  oh->area_id = oi->area->area_id;
+  /* checksum is calculated by kernel */
+  oh->instance_id = oi->instance_id;
+  oh->reserved = 0;
+
+  /* Log */
+  if (IS_OSPF6_DEBUG_MESSAGE (oh->type, SEND))
+    {
+      inet_ntop (AF_INET6, dst, dstname, sizeof (dstname));
+      if (src)
+        inet_ntop (AF_INET6, src, srcname, sizeof (srcname));
+      else
+        memset (srcname, 0, sizeof (srcname));
+      zlog_info ("%s send on %s",
+                 OSPF6_MESSAGE_TYPE_NAME (oh->type), oi->interface->name);
+      zlog_info ("    src: %s", srcname);
+      zlog_info ("    dst: %s", dstname);
+
+      switch (oh->type)
+        {
+          case OSPF6_MESSAGE_TYPE_HELLO:
+            ospf6_hello_print (oh);
+            break;
+          case OSPF6_MESSAGE_TYPE_DBDESC:
+            ospf6_dbdesc_print (oh);
+            break;
+          case OSPF6_MESSAGE_TYPE_LSREQ:
+            ospf6_lsreq_print (oh);
+            break;
+          case OSPF6_MESSAGE_TYPE_LSUPDATE:
+            ospf6_lsupdate_print (oh);
+            break;
+          case OSPF6_MESSAGE_TYPE_LSACK:
+            ospf6_lsack_print (oh);
+            break;
+          default:
+            zlog_info ("Unknown message");
+            assert (0);
+            break;
+        }
+    }
+
+  /* send message */
+  len = ospf6_sendmsg (src, dst, &oi->interface->ifindex, iovector);
+  if (len != ntohs (oh->length))
+    zlog_err ("Could not send entire message");
+}
+
+int
+ospf6_hello_send (struct thread *thread)
+{
+  struct ospf6_interface *oi;
+  struct ospf6_header *oh;
+  struct ospf6_hello *hello;
+  char *p;
+  listnode node;
+  struct ospf6_neighbor *on;
+
+  oi = (struct ospf6_interface *) THREAD_ARG (thread);
+  oi->thread_send_hello = (struct thread *) NULL;
+
+  if (oi->state <= OSPF6_INTERFACE_DOWN)
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_HELLO, SEND))
+        zlog_info ("Unable to send Hello on down interface %s",
+                   oi->interface->name);
+      return 0;
+    }
+
+  /* set next thread */
+  oi->thread_send_hello = thread_add_timer (master, ospf6_hello_send,
+                                            oi, oi->hello_interval);
+
+  memset (sendbuf, 0, sizeof (sendbuf));
+  oh = (struct ospf6_header *) sendbuf;
+  hello = (struct ospf6_hello *)((caddr_t) oh + sizeof (struct ospf6_header));
+
+  hello->interface_id = htonl (oi->interface->ifindex);
+  hello->priority = oi->priority;
+  hello->options[0] = oi->area->options[0];
+  hello->options[1] = oi->area->options[1];
+  hello->options[2] = oi->area->options[2];
+  hello->hello_interval = htons (oi->hello_interval);
+  hello->dead_interval = htons (oi->dead_interval);
+  hello->drouter = oi->drouter;
+  hello->bdrouter = oi->bdrouter;
+
+  p = (char *)((caddr_t) hello + sizeof (struct ospf6_hello));
+
+  for (node = listhead (oi->neighbor_list); node; nextnode (node))
+    {
+      on = (struct ospf6_neighbor *) getdata (node);
+
+      if (on->state < OSPF6_NEIGHBOR_INIT)
+        continue;
+
+      if (p - sendbuf + sizeof (u_int32_t) > oi->ifmtu)
+        {
+          if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_HELLO, SEND))
+            zlog_info ("sending Hello message: exceeds I/F MTU");
+          break;
+        }
+
+      memcpy (p, &on->router_id, sizeof (u_int32_t));
+      p += sizeof (u_int32_t);
+    }
+
+  oh->type = OSPF6_MESSAGE_TYPE_HELLO;
+  oh->length = htons (p - sendbuf);
+
+  ospf6_send (oi->linklocal_addr, &allspfrouters6, oi, oh);
+  return 0;
+}
+
+int
+ospf6_dbdesc_send (struct thread *thread)
+{
+  struct ospf6_neighbor *on;
+  struct ospf6_header *oh;
+  struct ospf6_dbdesc *dbdesc;
+  char *p;
+  struct ospf6_lsa *lsa;
+
+  on = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  on->thread_send_dbdesc = (struct thread *) NULL;
+
+  if (on->state < OSPF6_NEIGHBOR_EXSTART)
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_DBDESC, SEND))
+        zlog_info ("Quit to send DbDesc to neighbor %s state %s",
+                   on->name, ospf6_neighbor_state_str[on->state]);
+      return 0;
+    }
+
+  /* set next thread if master */
+  if (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT))
+    on->thread_send_dbdesc =
+      thread_add_timer (master, ospf6_dbdesc_send, on,
+                        on->ospf6_if->rxmt_interval);
+
+  memset (sendbuf, 0, sizeof (sendbuf));
+  oh = (struct ospf6_header *) sendbuf;
+  dbdesc = (struct ospf6_dbdesc *)((caddr_t) oh +
+                                   sizeof (struct ospf6_header));
+
+  /* if this is initial one, initialize sequence number for DbDesc */
+  if (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT))
+    {
+      struct timeval tv;
+      if (gettimeofday (&tv, (struct timezone *) NULL) < 0)
+        tv.tv_sec = 1;
+      on->dbdesc_seqnum = tv.tv_sec;
+    }
+
+  dbdesc->options[0] = on->ospf6_if->area->options[0];
+  dbdesc->options[1] = on->ospf6_if->area->options[1];
+  dbdesc->options[2] = on->ospf6_if->area->options[2];
+  dbdesc->ifmtu = htons (on->ospf6_if->ifmtu);
+  dbdesc->bits = on->dbdesc_bits;
+  dbdesc->seqnum = htonl (on->dbdesc_seqnum);
+
+  /* if this is not initial one, set LSA headers in dbdesc */
+  p = (char *)((caddr_t) dbdesc + sizeof (struct ospf6_dbdesc));
+  if (! CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT))
+    {
+      for (lsa = ospf6_lsdb_head (on->dbdesc_list); lsa;
+           lsa = ospf6_lsdb_next (lsa))
+        {
+          ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay);
+
+          /* MTU check */
+          if (p - sendbuf + sizeof (struct ospf6_lsa_header) >
+              on->ospf6_if->ifmtu)
+            {
+              ospf6_lsa_unlock (lsa);
+              break;
+            }
+          memcpy (p, lsa->header, sizeof (struct ospf6_lsa_header));
+          p += sizeof (struct ospf6_lsa_header);
+        }
+    }
+
+  oh->type = OSPF6_MESSAGE_TYPE_DBDESC;
+  oh->length = htons (p - sendbuf);
+
+  ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr,
+              on->ospf6_if, oh);
+  return 0;
+}
+
+int
+ospf6_dbdesc_send_newone (struct thread *thread)
+{
+  struct ospf6_neighbor *on;
+  struct ospf6_lsa *lsa;
+  unsigned int size = 0;
+
+  on = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  if (IS_OSPF6_DEBUG_LSA (DATABASE))
+    zlog_info ("Remove entire dbdesc_list of %s: sending newone", on->name);
+  ospf6_lsdb_remove_all (on->dbdesc_list);
+
+  /* move LSAs from summary_list to dbdesc_list (within neighbor structure)
+     so that ospf6_send_dbdesc () can send those LSAs */
+  size = sizeof (struct ospf6_lsa_header) + sizeof (struct ospf6_dbdesc);
+  for (lsa = ospf6_lsdb_head (on->summary_list); lsa;
+       lsa = ospf6_lsdb_next (lsa))
+    {
+      if (size + sizeof (struct ospf6_lsa_header) > on->ospf6_if->ifmtu)
+        {
+          ospf6_lsa_unlock (lsa);
+          break;
+        }
+
+      if (IS_OSPF6_DEBUG_LSA (DATABASE))
+        zlog_info ("Move %s from summary_list to dbdesc_list of %s",
+                   lsa->name, on->name);
+      ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->dbdesc_list);
+      ospf6_lsdb_remove (lsa, on->summary_list);
+      size += sizeof (struct ospf6_lsa_header);
+    }
+
+  if (on->summary_list->count == 0)
+    UNSET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT);
+
+  /* If slave, More bit check must be done here */
+  if (! CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT) && /* Slave */
+      ! CHECK_FLAG (on->dbdesc_last.bits, OSPF6_DBDESC_MBIT) &&
+      ! CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT))
+    thread_add_event (master, exchange_done, on, 0);
+
+  thread_execute (master, ospf6_dbdesc_send, on, 0);
+  return 0;
+}
+
+int
+ospf6_lsreq_send (struct thread *thread)
+{
+  struct ospf6_neighbor *on;
+  struct ospf6_header *oh;
+  struct ospf6_lsreq_entry *e;
+  char *p;
+  struct ospf6_lsa *lsa;
+
+  on = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  on->thread_send_lsreq = (struct thread *) NULL;
+
+  /* LSReq will be sent only in ExStart or Loading */
+  if (on->state != OSPF6_NEIGHBOR_EXCHANGE &&
+      on->state != OSPF6_NEIGHBOR_LOADING)
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSREQ, SEND))
+        zlog_info ("Quit to send LSReq to neighbor %s state %s",
+                   on->name, ospf6_neighbor_state_str[on->state]);
+      return 0;
+    }
+
+  /* schedule loading_done if request list is empty */
+  if (on->request_list->count == 0)
+    {
+      thread_add_event (master, loading_done, on, 0);
+      return 0;
+    }
+
+  /* set next thread */
+  on->thread_send_lsreq =
+    thread_add_timer (master, ospf6_lsreq_send, on,
+                      on->ospf6_if->rxmt_interval);
+
+  memset (sendbuf, 0, sizeof (sendbuf));
+  oh = (struct ospf6_header *) sendbuf;
+
+  /* set Request entries in lsreq */
+  p = (char *)((caddr_t) oh + sizeof (struct ospf6_header));
+  for (lsa = ospf6_lsdb_head (on->request_list); lsa;
+       lsa = ospf6_lsdb_next (lsa))
+    {
+      /* MTU check */
+      if (p - sendbuf + sizeof (struct ospf6_lsreq_entry) > on->ospf6_if->ifmtu)
+        {
+          ospf6_lsa_unlock (lsa);
+          break;
+        }
+
+      e = (struct ospf6_lsreq_entry *) p;
+      e->type = lsa->header->type;
+      e->id = lsa->header->id;
+      e->adv_router = lsa->header->adv_router;
+      p += sizeof (struct ospf6_lsreq_entry);
+    }
+
+  oh->type = OSPF6_MESSAGE_TYPE_LSREQ;
+  oh->length = htons (p - sendbuf);
+
+  ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr,
+              on->ospf6_if, oh);
+  return 0;
+}
+
+int
+ospf6_lsupdate_send_neighbor (struct thread *thread)
+{
+  struct ospf6_neighbor *on;
+  struct ospf6_header *oh;
+  struct ospf6_lsupdate *lsupdate;
+  char *p;
+  int num;
+  struct ospf6_lsa *lsa;
+
+  on = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  on->thread_send_lsupdate = (struct thread *) NULL;
+
+  if (on->state < OSPF6_NEIGHBOR_EXCHANGE)
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSUPDATE, SEND))
+        zlog_info ("Quit to send LSUpdate to neighbor %s state %s",
+                   on->name, ospf6_neighbor_state_str[on->state]);
+      return 0;
+    }
+
+  /* if we have nothing to send, return */
+  if (on->lsupdate_list->count == 0 &&
+      on->retrans_list->count == 0)
+    return 0;
+
+  if (IS_OSPF6_DEBUG_LSA (SEND))
+    zlog_info ("LSA Send to %s", on->name);
+
+  memset (sendbuf, 0, sizeof (sendbuf));
+  oh = (struct ospf6_header *) sendbuf;
+  lsupdate = (struct ospf6_lsupdate *)
+    ((caddr_t) oh + sizeof (struct ospf6_header));
+
+  p = (char *)((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate));
+  num = 0;
+
+  /* lsupdate_list lists those LSA which doesn't need to be
+     retransmitted. remove those from the list */
+  for (lsa = ospf6_lsdb_head (on->lsupdate_list); lsa;
+       lsa = ospf6_lsdb_next (lsa))
+    {
+      /* MTU check */
+      if (p - sendbuf + OSPF6_LSA_SIZE (lsa->header) > on->ospf6_if->ifmtu)
+        {
+          ospf6_lsa_unlock (lsa);
+          break;
+        }
+
+      if (IS_OSPF6_DEBUG_LSA (SEND))
+        ospf6_lsa_header_print (lsa);
+
+      ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay);
+      memcpy (p, lsa->header, OSPF6_LSA_SIZE (lsa->header));
+      p += OSPF6_LSA_SIZE (lsa->header);
+      num++;
+
+      assert (lsa->lock == 2);
+      ospf6_lsdb_remove (lsa, on->lsupdate_list);
+    }
+
+  for (lsa = ospf6_lsdb_head (on->retrans_list); lsa;
+       lsa = ospf6_lsdb_next (lsa))
+    {
+      /* MTU check */
+      if (p - sendbuf + OSPF6_LSA_SIZE (lsa->header) > on->ospf6_if->ifmtu)
+        {
+          ospf6_lsa_unlock (lsa);
+          break;
+        }
+
+      if (IS_OSPF6_DEBUG_LSA (SEND))
+        ospf6_lsa_header_print (lsa);
+
+      ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay);
+      memcpy (p, lsa->header, OSPF6_LSA_SIZE (lsa->header));
+      p += OSPF6_LSA_SIZE (lsa->header);
+      num++;
+    }
+
+  lsupdate->lsa_number = htonl (num);
+
+  oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE;
+  oh->length = htons (p - sendbuf);
+
+  ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr,
+              on->ospf6_if, oh);
+
+  if (on->lsupdate_list->count != 0 ||
+      on->retrans_list->count != 0)
+    {
+      if (on->lsupdate_list->count != 0)
+        on->thread_send_lsupdate =
+          thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0);
+      else
+        on->thread_send_lsupdate =
+          thread_add_timer (master, ospf6_lsupdate_send_neighbor, on,
+                            on->ospf6_if->rxmt_interval);
+    }
+
+  return 0;
+}
+
+int
+ospf6_lsupdate_send_interface (struct thread *thread)
+{
+  struct ospf6_interface *oi;
+  struct ospf6_header *oh;
+  struct ospf6_lsupdate *lsupdate;
+  char *p;
+  int num;
+  struct ospf6_lsa *lsa;
+
+  oi = (struct ospf6_interface *) THREAD_ARG (thread);
+  oi->thread_send_lsupdate = (struct thread *) NULL;
+
+  if (oi->state <= OSPF6_INTERFACE_WAITING)
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSUPDATE, SEND))
+        zlog_info ("Quit to send LSUpdate to interface %s state %s",
+                   oi->interface->name, ospf6_interface_state_str[oi->state]);
+      return 0;
+    }
+
+  /* if we have nothing to send, return */
+  if (oi->lsupdate_list->count == 0)
+    return 0;
+
+  if (IS_OSPF6_DEBUG_LSA (SEND))
+    zlog_info ("LSA Send to %s", oi->interface->name);
+
+  memset (sendbuf, 0, sizeof (sendbuf));
+  oh = (struct ospf6_header *) sendbuf;
+  lsupdate = (struct ospf6_lsupdate *)((caddr_t) oh +
+                                       sizeof (struct ospf6_header));
+
+  p = (char *)((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate));
+  num = 0;
+
+  for (lsa = ospf6_lsdb_head (oi->lsupdate_list); lsa;
+       lsa = ospf6_lsdb_next (lsa))
+    {
+      /* MTU check */
+      if (p - sendbuf + OSPF6_LSA_SIZE (lsa->header) > oi->ifmtu)
+        {
+          ospf6_lsa_unlock (lsa);
+          break;
+        }
+
+      if (IS_OSPF6_DEBUG_LSA (SEND))
+        ospf6_lsa_header_print (lsa);
+
+      ospf6_lsa_age_update_to_send (lsa, oi->transdelay);
+      memcpy (p, lsa->header, OSPF6_LSA_SIZE (lsa->header));
+      p += OSPF6_LSA_SIZE (lsa->header);
+      num++;
+
+      assert (lsa->lock == 2);
+      ospf6_lsdb_remove (lsa, oi->lsupdate_list);
+    }
+
+  lsupdate->lsa_number = htonl (num);
+
+  oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE;
+  oh->length = htons (p - sendbuf);
+
+  if (oi->state == OSPF6_INTERFACE_DR ||
+      oi->state == OSPF6_INTERFACE_BDR)
+    ospf6_send (oi->linklocal_addr, &allspfrouters6, oi, oh);
+  else
+    ospf6_send (oi->linklocal_addr, &alldrouters6, oi, oh);
+
+  if (oi->lsupdate_list->count > 0)
+    {
+      oi->thread_send_lsupdate =
+        thread_add_event (master, ospf6_lsupdate_send_interface, oi, 0);
+    }
+
+  return 0;
+}
+
+int
+ospf6_lsack_send_neighbor (struct thread *thread)
+{
+  struct ospf6_neighbor *on;
+  struct ospf6_header *oh;
+  char *p;
+  struct ospf6_lsa *lsa;
+
+  on = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  on->thread_send_lsack = (struct thread *) NULL;
+
+  if (on->state < OSPF6_NEIGHBOR_EXCHANGE)
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSACK, SEND))
+        zlog_info ("Quit to send LSAck to neighbor %s state %s",
+                   on->name, ospf6_neighbor_state_str[on->state]);
+      return 0;
+    }
+
+  /* if we have nothing to send, return */
+  if (on->lsack_list->count == 0)
+    return 0;
+
+  memset (sendbuf, 0, sizeof (sendbuf));
+  oh = (struct ospf6_header *) sendbuf;
+
+  p = (char *)((caddr_t) oh + sizeof (struct ospf6_header));
+
+  for (lsa = ospf6_lsdb_head (on->lsack_list); lsa;
+       lsa = ospf6_lsdb_next (lsa))
+    {
+      /* MTU check */
+      if (p - sendbuf + sizeof (struct ospf6_lsa_header) > on->ospf6_if->ifmtu)
+        {
+          /* if we run out of packet size/space here,
+             better to try again soon. */
+          THREAD_OFF (on->thread_send_lsack);
+          on->thread_send_lsack =
+            thread_add_event (master, ospf6_lsack_send_neighbor, on, 0);
+
+          ospf6_lsa_unlock (lsa);
+          break;
+        }
+
+      ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay);
+      memcpy (p, lsa->header, sizeof (struct ospf6_lsa_header));
+      p += sizeof (struct ospf6_lsa_header);
+
+      assert (lsa->lock == 2);
+      ospf6_lsdb_remove (lsa, on->lsack_list);
+    }
+
+  oh->type = OSPF6_MESSAGE_TYPE_LSACK;
+  oh->length = htons (p - sendbuf);
+
+  ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr,
+              on->ospf6_if, oh);
+  return 0;
+}
+
+int
+ospf6_lsack_send_interface (struct thread *thread)
+{
+  struct ospf6_interface *oi;
+  struct ospf6_header *oh;
+  char *p;
+  struct ospf6_lsa *lsa;
+
+  oi = (struct ospf6_interface *) THREAD_ARG (thread);
+  oi->thread_send_lsack = (struct thread *) NULL;
+
+  if (oi->state <= OSPF6_INTERFACE_WAITING)
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSACK, SEND))
+        zlog_info ("Quit to send LSAck to interface %s state %s",
+                   oi->interface->name, ospf6_interface_state_str[oi->state]);
+      return 0;
+    }
+
+  /* if we have nothing to send, return */
+  if (oi->lsack_list->count == 0)
+    return 0;
+
+  memset (sendbuf, 0, sizeof (sendbuf));
+  oh = (struct ospf6_header *) sendbuf;
+
+  p = (char *)((caddr_t) oh + sizeof (struct ospf6_header));
+
+  for (lsa = ospf6_lsdb_head (oi->lsack_list); lsa;
+       lsa = ospf6_lsdb_next (lsa))
+    {
+      /* MTU check */
+      if (p - sendbuf + sizeof (struct ospf6_lsa_header) > oi->ifmtu)
+        {
+          /* if we run out of packet size/space here,
+             better to try again soon. */
+          THREAD_OFF (oi->thread_send_lsack);
+          oi->thread_send_lsack =
+            thread_add_event (master, ospf6_lsack_send_interface, oi, 0);
+
+          ospf6_lsa_unlock (lsa);
+          break;
+        }
+
+      ospf6_lsa_age_update_to_send (lsa, oi->transdelay);
+      memcpy (p, lsa->header, sizeof (struct ospf6_lsa_header));
+      p += sizeof (struct ospf6_lsa_header);
+
+      assert (lsa->lock == 2);
+      ospf6_lsdb_remove (lsa, oi->lsack_list);
+    }
+
+  oh->type = OSPF6_MESSAGE_TYPE_LSACK;
+  oh->length = htons (p - sendbuf);
+
+  if (oi->state == OSPF6_INTERFACE_DR ||
+      oi->state == OSPF6_INTERFACE_BDR)
+    ospf6_send (oi->linklocal_addr, &allspfrouters6, oi, oh);
+  else
+    ospf6_send (oi->linklocal_addr, &alldrouters6, oi, oh);
+
+  if (oi->thread_send_lsack == NULL && oi->lsack_list->count > 0)
+    {
+      oi->thread_send_lsack =
+        thread_add_event (master, ospf6_lsack_send_interface, oi, 0);
+    }
 
   return 0;
 }
 
 
-/* send section */
-int
-ospf6_message_length (struct iovec *message)
+/* Commands */
+DEFUN (debug_ospf6_message,
+       debug_ospf6_message_cmd,
+       "debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all)",
+       DEBUG_STR
+       OSPF6_STR
+       "Debug OSPFv3 message\n"
+       "Debug Unknown message\n"
+       "Debug Hello message\n"
+       "Debug Database Description message\n"
+       "Debug Link State Request message\n"
+       "Debug Link State Update message\n"
+       "Debug Link State Acknowledgement message\n"
+       "Debug All message\n"
+       )
 {
-  int i, length = 0;
-  for (i = 0; i < OSPF6_MESSAGE_IOVEC_SIZE; i++)
-    {
-      if (message[i].iov_base == NULL && message[i].iov_len == 0)
-        break;
-      length += message[i].iov_len;
-    }
-  return length;
-}
-#define OSPF6_MESSAGE_LENGTH(msg) \
-(ospf6_message_length (msg))
-
-void
-ospf6_message_send (unsigned char type, struct iovec *msg,
-                    struct in6_addr *dst, u_int ifindex)
-{
-  struct ospf6_interface *o6i;
-  struct ospf6_header ospf6_header;
-  char dst_name[64], src_name[64];
-  struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
-  int msg_len;
-
-  /* ospf6 interface lookup */
-  o6i = ospf6_interface_lookup_by_index (ifindex);
-  assert (o6i);
-
-  msg_len = OSPF6_MESSAGE_LENGTH (msg);
-
-  /* I/F MTU check */
-#if 0
-  if (msg_len + sizeof (struct ospf6_header) >= o6i->interface->mtu)
-#else
-  if (msg_len + sizeof (struct ospf6_header) >= o6i->ifmtu)
-#endif
-    {
-      /* If Interface MTU is 0, save the case
-         since zebra had been failed to get MTU from Kernel */
-      if (o6i->interface->mtu != 0)
-        {
-          zlog_warn ("Message: Send failed on %s: exceeds I/F MTU",
-                     o6i->interface->name);
-          zlog_warn ("Message:   while sending %s: Len:%d MTU:%d",
-                     ospf6_message_type_string[type],
-                     msg_len + sizeof (struct ospf6_header),
-                     o6i->ifmtu);
-          return;
-        }
-      else
-        {
-          zlog_warn ("Message: I/F MTU check ignored on %s",
-                     o6i->interface->name);
-        }
-    }
-
-  /* Initialize */
-  OSPF6_MESSAGE_CLEAR (message);
-
-  /* set OSPF header */
-  memset (&ospf6_header, 0, sizeof (ospf6_header));
-  ospf6_header.version = OSPF6_VERSION;
-  ospf6_header.type = type;
-  ospf6_header.len = htons (msg_len + sizeof (struct ospf6_header));
-  ospf6_header.router_id = ospf6->router_id;
-  ospf6_header.area_id = o6i->area->area_id;
-  /* checksum is calculated by kernel */
-  ospf6_header.instance_id = o6i->instance_id;
-  ospf6_header.reserved = 0;
-  OSPF6_MESSAGE_ATTACH (message, &ospf6_header, sizeof (struct ospf6_header));
-
-  /* Attach rest to message */
-  OSPF6_MESSAGE_JOIN (message, msg);
-
-  /* statistics */
-  if (type >= OSPF6_MESSAGE_TYPE_MAX)
-    type = OSPF6_MESSAGE_TYPE_UNKNOWN;
-  o6i->message_stat[type].send++;
-  o6i->message_stat[type].send_octet += ntohs (ospf6_header.len);
-
-  /* log */
-  if (IS_OSPF6_DUMP_MESSAGE (type))
-    {
-      inet_ntop (AF_INET6, dst, dst_name, sizeof (dst_name));
-      if (o6i->lladdr)
-        inet_ntop (AF_INET6, o6i->lladdr, src_name, sizeof (src_name));
-      else
-        strcpy (src_name, "Unknown");
-      zlog_info ("Send %s on %s",
-                 ospf6_message_type_string[type], o6i->interface->name);
-      zlog_info ("    %s -> %s", src_name, dst_name);
-      ospf6_message_log (message);
-    }
-
-  /* send message */
-  ospf6_sendmsg (o6i->lladdr, dst, &ifindex, message);
-}
-
-
-int
-ospf6_send_hello (struct thread *thread)
-{
-  listnode n;
-  struct ospf6_interface *o6i;
-  struct ospf6_neighbor *o6n;
-  struct in6_addr dst;
-  struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
-  struct ospf6_hello hello;
-  char router_buffer[1024]; /* xxx */
-  u_int router_size;
-
-  /* which ospf6 interface to send */
-  o6i = (struct ospf6_interface *) THREAD_ARG (thread);
-  o6i->thread_send_hello = (struct thread *) NULL;
-
-  /* assure interface is up */
-  if (o6i->state <= IFS_DOWN)
-    {
-      if (IS_OSPF6_DUMP_HELLO)
-        zlog_warn ("Send HELLO Failed: Interface not enabled: %s",
-                   o6i->interface->name);
-      return 0;
-    }
-
-  /* clear message buffer */
-  OSPF6_MESSAGE_CLEAR (message);
-
-  /* set Hello fields */
-  hello.interface_id = htonl (o6i->if_id);
-  hello.rtr_pri = o6i->priority;
-  memcpy (hello.options, o6i->area->options, sizeof (hello.options));
-  hello.hello_interval = htons (o6i->hello_interval);
-  hello.router_dead_interval = htons (o6i->dead_interval);
-  hello.dr = o6i->dr;
-  hello.bdr = o6i->bdr;
-  OSPF6_MESSAGE_ATTACH (message, &hello, sizeof (struct ospf6_hello));
-
-  /* set neighbor router id */
-  router_size = 0;
-  for (n = listhead (o6i->neighbor_list); n; nextnode (n))
-    {
-      o6n = (struct ospf6_neighbor *) getdata (n);
-
-      if (o6n->state < NBS_INIT)
-        continue;
-
-      if (router_size + sizeof (o6n->router_id) > sizeof (router_buffer))
-        {
-          zlog_warn ("Send HELLO: Buffer shortage on %s",
-                     o6i->interface->name);
-          break;
-        }
-
-      /* Copy Router-ID to Buffer */
-      memcpy (router_buffer + router_size, &o6n->router_id,
-              sizeof (o6n->router_id));
-      router_size += sizeof (o6n->router_id);
-    }
-  OSPF6_MESSAGE_ATTACH (message, router_buffer, router_size);
-
-  /* set destionation */
-  inet_pton (AF_INET6, ALLSPFROUTERS6, &dst);
-
-  /* send hello */
-  ospf6_message_send (OSPF6_MESSAGE_TYPE_HELLO, message, &dst,
-                      o6i->interface->ifindex);
-
-  /* set next timer thread */
-  o6i->thread_send_hello = thread_add_timer (master, ospf6_send_hello,
-                                             o6i, o6i->hello_interval);
-
-  return 0;
-}
-
-void
-ospf6_dbdesc_seqnum_init (struct ospf6_neighbor *o6n)
-{
-  struct timeval tv;
-
-  if (gettimeofday (&tv, (struct timezone *) NULL) < 0)
-    tv.tv_sec = 1;
-
-  o6n->dbdesc_seqnum = tv.tv_sec;
-
-  if (IS_OSPF6_DUMP_DBDESC)
-    zlog_info ("set dbdesc seqnum %d for %s", o6n->dbdesc_seqnum, o6n->str);
-}
-
-int
-ospf6_send_dbdesc_rxmt (struct thread *thread)
-{
-  struct ospf6_lsdb_node node;
-  struct ospf6_neighbor *o6n;
-  struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
-  struct ospf6_lsa *lsa;
-  struct ospf6_lsa_header *lsa_header;
-  struct ospf6_dbdesc dbdesc;
-
-  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
-  assert (o6n);
-
-  /* clear thread */
-  o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
-
-  /* if state less than ExStart, do nothing */
-  if (o6n->state < NBS_EXSTART)
-    return 0;
-
-  OSPF6_MESSAGE_CLEAR (message);
-
-  /* set dbdesc */
-  memcpy (dbdesc.options, o6n->ospf6_interface->area->options,
-          sizeof (dbdesc.options));
-  dbdesc.ifmtu = htons (o6n->ospf6_interface->interface->mtu);
-  dbdesc.bits = o6n->dbdesc_bits;
-  dbdesc.seqnum = htonl (o6n->dbdesc_seqnum);
-  OSPF6_MESSAGE_ATTACH (message, &dbdesc, sizeof (struct ospf6_dbdesc));
-
-  /* if this is not initial, set LSA summary to dbdesc */
-  if (! DD_IS_IBIT_SET (o6n->dbdesc_bits))
-    {
-      for (ospf6_lsdb_head (&node, o6n->dbdesc_list);
-           ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node))
-        {
-          lsa = node.lsa;
-
-          /* xxx, no MTU check: no support for Dynamic MTU change */
-
-          /* set age and add InfTransDelay */
-          ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay);
-
-          /* set LSA summary to send buffer */
-          lsa_header = (struct ospf6_lsa_header *) lsa->lsa_hdr;
-          OSPF6_MESSAGE_ATTACH (message, lsa_header,
-                                sizeof (struct ospf6_lsa_header));
-        }
-    }
-
-  /* send dbdesc */
-  ospf6_message_send (OSPF6_MESSAGE_TYPE_DBDESC, message, &o6n->hisaddr,
-                      o6n->ospf6_interface->interface->ifindex);
-
-  /* if master, set futher retransmission */
-  if (DD_IS_MSBIT_SET (o6n->dbdesc_bits))
-    o6n->thread_rxmt_dbdesc =
-      thread_add_timer (master, ospf6_send_dbdesc_rxmt,
-                        o6n, o6n->ospf6_interface->rxmt_interval);
-
-  /* statistics */
-  o6n->ospf6_stat_retrans_dbdesc++;
-
-  return 0;
-}
-
-int
-ospf6_send_dbdesc (struct thread *thread)
-{
-  struct ospf6_neighbor *o6n;
-  struct ospf6_lsa *lsa;
-  struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
-  struct ospf6_dbdesc dbdesc;
-  struct ospf6_lsdb_node node;
-
-  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
-  assert (o6n);
-
-  /* clear thread */
-  o6n->thread_send_dbdesc = (struct thread *) NULL;
-  if (o6n->thread_rxmt_dbdesc)
-    thread_cancel (o6n->thread_rxmt_dbdesc);
-  o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
-
-  /* if state less than ExStart, do nothing */
-  if (o6n->state < NBS_EXSTART)
-    return 0;
-
-  OSPF6_MESSAGE_CLEAR (message);
-  OSPF6_MESSAGE_ATTACH (message, &dbdesc, sizeof (struct ospf6_dbdesc));
-
-  /* clear previous LSA summary sent */
-  ospf6_lsdb_remove_all (o6n->dbdesc_list);
-  assert (o6n->dbdesc_list->count == 0);
-
-  /* if this is not initial, set LSA summary to dbdesc */
-  if (! DD_IS_IBIT_SET (o6n->dbdesc_bits))
-    {
-      for (ospf6_lsdb_head (&node, o6n->summary_list);
-           ! ospf6_lsdb_is_end (&node);
-           ospf6_lsdb_next (&node))
-        {
-          lsa = node.lsa;
-
-          /* MTU check */
-          if (OSPF6_MESSAGE_LENGTH (message)
-              + sizeof (struct ospf6_lsa_header)
-              + sizeof (struct ospf6_header)
-              > o6n->ospf6_interface->ifmtu)
-            break;
-
-          /* debug */
-          if (IS_OSPF6_DUMP_DBDESC)
-            zlog_info ("Include DbDesc: %s", lsa->str);
-
-          /* attach to dbdesclist */
-          ospf6_neighbor_dbdesc_add (lsa, o6n);
-          /* detach from summarylist */
-          ospf6_neighbor_summary_remove (lsa, o6n);
-
-          /* set age and add InfTransDelay */
-          ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay);
-
-          /* set LSA summary to send buffer */
-          OSPF6_MESSAGE_ATTACH (message, lsa->header,
-                                sizeof (struct ospf6_lsa_header));
-        }
-
-      if (o6n->summary_list->count == 0)
-        {
-          /* Clear more bit */
-          DD_MBIT_CLEAR (o6n->dbdesc_bits);
-
-          /* slave must schedule ExchangeDone on sending, here */
-          if (! DD_IS_MSBIT_SET (o6n->dbdesc_bits))
-            {
-              if (! DD_IS_MBIT_SET (o6n->dbdesc_bits) &&
-                  ! DD_IS_MBIT_SET (o6n->last_dd.bits))
-                thread_add_event (master, exchange_done, o6n, 0);
-            }
-        }
-    }
-
-  /* if this is initial, set seqnum */
-  if (DDBIT_IS_INITIAL (o6n->dbdesc_bits))
-    ospf6_dbdesc_seqnum_init (o6n);
-
-  /* set dbdesc */
-  memcpy (dbdesc.options, o6n->ospf6_interface->area->options,
-          sizeof (dbdesc.options));
-  dbdesc.ifmtu = htons (o6n->ospf6_interface->interface->mtu);
-  dbdesc.bits = o6n->dbdesc_bits;
-  dbdesc.seqnum = htonl (o6n->dbdesc_seqnum);
-
-  /* send dbdesc */
-  ospf6_message_send (OSPF6_MESSAGE_TYPE_DBDESC, message, &o6n->hisaddr,
-                      o6n->ospf6_interface->interface->ifindex);
-
-  /* if master, set retransmission */
-  if (DD_IS_MSBIT_SET (o6n->dbdesc_bits))
-    o6n->thread_rxmt_dbdesc =
-      thread_add_timer (master, ospf6_send_dbdesc_rxmt,
-                          o6n, o6n->ospf6_interface->rxmt_interval);
-
-  /* statistics */
-  o6n->lsa_send[OSPF6_MESSAGE_TYPE_DBDESC] += o6n->dbdesc_list->count;
-
-  return 0;
-}
-
-int
-ospf6_send_lsreq_rxmt (struct thread *thread)
-{
-  struct ospf6_neighbor *o6n;
-
-  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
-  assert (o6n);
-
-  o6n->thread_rxmt_lsreq = (struct thread *) NULL;
-  o6n->thread_send_lsreq = thread_add_event (master, ospf6_send_lsreq, o6n, 0);
-  return 0;
-}
-
-int
-ospf6_send_lsreq (struct thread *thread)
-{
-  struct ospf6_neighbor *o6n;
-  struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
-  struct ospf6_lsreq lsreq[OSPF6_MESSAGE_IOVEC_SIZE];
-  struct ospf6_lsa *lsa;
-  struct ospf6_lsdb_node node;
+  unsigned char level = 0;
+  int type = 0;
   int i;
 
-  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
-  assert (o6n);
+  assert (argc > 0);
 
-  /* LSReq will be send only in ExStart or Loading */
-  if (o6n->state != NBS_EXCHANGE && o6n->state != NBS_LOADING)
-    return 0;
+  /* check type */
+  if (! strncmp (argv[0], "u", 1))
+    type = OSPF6_MESSAGE_TYPE_UNKNOWN;
+  else if (! strncmp (argv[0], "h", 1))
+    type = OSPF6_MESSAGE_TYPE_HELLO;
+  else if (! strncmp (argv[0], "d", 1))
+    type = OSPF6_MESSAGE_TYPE_DBDESC;
+  else if (! strncmp (argv[0], "lsr", 3))
+    type = OSPF6_MESSAGE_TYPE_LSREQ;
+  else if (! strncmp (argv[0], "lsu", 3))
+    type = OSPF6_MESSAGE_TYPE_LSUPDATE;
+  else if (! strncmp (argv[0], "lsa", 3))
+    type = OSPF6_MESSAGE_TYPE_LSACK;
+  else if (! strncmp (argv[0], "a", 1))
+    type = OSPF6_MESSAGE_TYPE_ALL;
 
-  /* clear thread */
-  o6n->thread_send_lsreq = (struct thread *) NULL;
-  if (o6n->thread_rxmt_lsreq)
-    thread_cancel (o6n->thread_rxmt_lsreq);
-  o6n->thread_rxmt_lsreq = (struct thread *) NULL;
+  if (argc == 1)
+    level = OSPF6_DEBUG_MESSAGE_SEND | OSPF6_DEBUG_MESSAGE_RECV;
+  else if (! strncmp (argv[1], "s", 1))
+    level = OSPF6_DEBUG_MESSAGE_SEND;
+  else if (! strncmp (argv[1], "r", 1))
+    level = OSPF6_DEBUG_MESSAGE_RECV;
 
-  /* schedule loading_done if request list is empty */
-  if (o6n->request_list->count == 0)
+  if (type == OSPF6_MESSAGE_TYPE_ALL)
     {
-      thread_add_event (master, loading_done, o6n, 0);
+      for (i = 0; i < 6; i++)
+        OSPF6_DEBUG_MESSAGE_ON (i, level);
+    }
+  else
+    OSPF6_DEBUG_MESSAGE_ON (type, level);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (debug_ospf6_message,
+       debug_ospf6_message_sendrecv_cmd,
+       "debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all) (send|recv)",
+       DEBUG_STR
+       OSPF6_STR
+       "Debug OSPFv3 message\n"
+       "Debug Unknown message\n"
+       "Debug Hello message\n"
+       "Debug Database Description message\n"
+       "Debug Link State Request message\n"
+       "Debug Link State Update message\n"
+       "Debug Link State Acknowledgement message\n"
+       "Debug All message\n"
+       "Debug only sending message\n"
+       "Debug only receiving message\n"
+       );
+
+
+DEFUN (no_debug_ospf6_message,
+       no_debug_ospf6_message_cmd,
+       "no debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all)",
+       NO_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Debug OSPFv3 message\n"
+       "Debug Unknown message\n"
+       "Debug Hello message\n"
+       "Debug Database Description message\n"
+       "Debug Link State Request message\n"
+       "Debug Link State Update message\n"
+       "Debug Link State Acknowledgement message\n"
+       "Debug All message\n"
+       )
+{
+  unsigned char level = 0;
+  int type = 0;
+  int i;
+
+  assert (argc > 0);
+
+  /* check type */
+  if (! strncmp (argv[0], "u", 1))
+    type = OSPF6_MESSAGE_TYPE_UNKNOWN;
+  else if (! strncmp (argv[0], "h", 1))
+    type = OSPF6_MESSAGE_TYPE_HELLO;
+  else if (! strncmp (argv[0], "d", 1))
+    type = OSPF6_MESSAGE_TYPE_DBDESC;
+  else if (! strncmp (argv[0], "lsr", 3))
+    type = OSPF6_MESSAGE_TYPE_LSREQ;
+  else if (! strncmp (argv[0], "lsu", 3))
+    type = OSPF6_MESSAGE_TYPE_LSUPDATE;
+  else if (! strncmp (argv[0], "lsa", 3))
+    type = OSPF6_MESSAGE_TYPE_LSACK;
+  else if (! strncmp (argv[0], "a", 1))
+    type = OSPF6_MESSAGE_TYPE_ALL;
+
+  if (argc == 1)
+    level = OSPF6_DEBUG_MESSAGE_SEND | OSPF6_DEBUG_MESSAGE_RECV;
+  else if (! strncmp (argv[1], "s", 1))
+    level = OSPF6_DEBUG_MESSAGE_SEND;
+  else if (! strncmp (argv[1], "r", 1))
+    level = OSPF6_DEBUG_MESSAGE_RECV;
+
+  if (type == OSPF6_MESSAGE_TYPE_ALL)
+    {
+      for (i = 0; i < 6; i++)
+        OSPF6_DEBUG_MESSAGE_OFF (i, level);
+    }
+  else
+    OSPF6_DEBUG_MESSAGE_OFF (type, level);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_ospf6_message,
+       no_debug_ospf6_message_sendrecv_cmd,
+       "no debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all) (send|recv)",
+       NO_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Debug OSPFv3 message\n"
+       "Debug Unknown message\n"
+       "Debug Hello message\n"
+       "Debug Database Description message\n"
+       "Debug Link State Request message\n"
+       "Debug Link State Update message\n"
+       "Debug Link State Acknowledgement message\n"
+       "Debug All message\n"
+       "Debug only sending message\n"
+       "Debug only receiving message\n"
+       );
+
+int
+config_write_ospf6_debug_message (struct vty *vty)
+{
+  char *type_str[] = {"unknown", "hello", "dbdesc",
+                      "lsreq", "lsupdate", "lsack"};
+  unsigned char s = 0, r = 0;
+  int i;
+
+  for (i = 0; i < 6; i++)
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (i, SEND))
+        s |= 1 << i;
+      if (IS_OSPF6_DEBUG_MESSAGE (i, RECV))
+        r |= 1 << i;
+    }
+
+  if (s == 0x3f && r == 0x3f)
+    {
+      vty_out (vty, "debug ospf6 message all%s", VTY_NEWLINE);
       return 0;
     }
 
-  /* clear message buffer */
-  OSPF6_MESSAGE_CLEAR (message);
-
-  i = 0;
-  for (ospf6_lsdb_head (&node, o6n->request_list);
-       ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node))
+  if (s == 0x3f && r == 0)
     {
-      lsa = node.lsa;
-
-      /* Buffer Overflow */
-      if (i >= OSPF6_MESSAGE_IOVEC_SIZE)
-        break;
-
-      /* I/F MTU check */
-      if (OSPF6_MESSAGE_LENGTH (message)
-          + sizeof (struct ospf6_lsreq)
-          + sizeof (struct ospf6_header)
-          > o6n->ospf6_interface->ifmtu)
-        break;
-
-      lsreq[i].mbz = 0;
-      lsreq[i].type = lsa->header->type;
-      lsreq[i].id = lsa->header->id;
-      lsreq[i].adv_router = lsa->header->adv_router;
-
-      OSPF6_MESSAGE_ATTACH (message, &lsreq[i], sizeof (struct ospf6_lsreq));
-      i++;
+      vty_out (vty, "debug ospf6 message all send%s", VTY_NEWLINE);
+      return 0;
+    }
+  else if (s == 0 && r == 0x3f)
+    {
+      vty_out (vty, "debug ospf6 message all recv%s", VTY_NEWLINE);
+      return 0;
     }
 
-  ospf6_message_send (OSPF6_MESSAGE_TYPE_LSREQ, message, &o6n->hisaddr,
-                      o6n->ospf6_interface->interface->ifindex);
+  /* Unknown message is logged by default */
+  if (! IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, SEND) &&
+      ! IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+    vty_out (vty, "no debug ospf6 message unknown%s", VTY_NEWLINE);
+  else if (! IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, SEND))
+    vty_out (vty, "no debug ospf6 message unknown send%s", VTY_NEWLINE);
+  else if (! IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV))
+    vty_out (vty, "no debug ospf6 message unknown recv%s", VTY_NEWLINE);
 
-  /* set retransmit thread */
-  o6n->thread_rxmt_lsreq =
-    thread_add_timer (master, ospf6_send_lsreq_rxmt,
-                      o6n, o6n->ospf6_interface->rxmt_interval);
-
-  /* statistics */
-  o6n->lsa_send[OSPF6_MESSAGE_TYPE_LSREQ] += i;
+  for (i = 1; i < 6; i++)
+    {
+      if (IS_OSPF6_DEBUG_MESSAGE (i, SEND) &&
+          IS_OSPF6_DEBUG_MESSAGE (i, RECV))
+        vty_out (vty, "debug ospf6 message %s%s", type_str[i], VTY_NEWLINE);
+      else if (IS_OSPF6_DEBUG_MESSAGE (i, SEND))
+        vty_out (vty, "debug ospf6 message %s send%s", type_str[i],
+                 VTY_NEWLINE);
+      else if (IS_OSPF6_DEBUG_MESSAGE (i, RECV))
+        vty_out (vty, "debug ospf6 message %s recv%s", type_str[i],
+                 VTY_NEWLINE);
+    }
 
   return 0;
 }
 
-/* Send LSUpdate directly to the neighbor, from his retransmission list */
-int
-ospf6_send_lsupdate_rxmt (struct thread *thread)
-{
-  struct ospf6_neighbor *o6n;
-  struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
-  struct ospf6_lsupdate lsupdate;
-  struct ospf6_lsa *lsa;
-  struct ospf6_lsdb_node node;
-
-  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
-  assert (o6n);
-
-  o6n->send_update = (struct thread *) NULL;
-
-  if (o6n->ospf6_interface->state <= IFS_WAITING)
-    return -1;
-
-  /* clear message buffer */
-  OSPF6_MESSAGE_CLEAR (message);
-
-  /* set lsupdate header */
-  lsupdate.lsupdate_num = 0; /* set gradually */
-  OSPF6_MESSAGE_ATTACH (message, &lsupdate, sizeof (struct ospf6_lsupdate));
-
-  /* for each LSA listed on retransmission-list */
-  for (ospf6_lsdb_head (&node, o6n->retrans_list);
-       ! ospf6_lsdb_is_end (&node);
-       ospf6_lsdb_next (&node))
-    {
-      lsa = node.lsa;
-
-      /* I/F MTU check */
-      if (OSPF6_MESSAGE_LENGTH (message)
-          + sizeof (struct ospf6_lsupdate)
-          + sizeof (struct ospf6_header)
-          + ntohs (lsa->header->length)
-          > o6n->ospf6_interface->ifmtu)
-        break;
-
-      ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay);
-      OSPF6_MESSAGE_ATTACH (message, lsa->header, ntohs (lsa->header->length));
-      lsupdate.lsupdate_num++;
-    }
-
-  /* check and correct lsupdate */
-  if (lsupdate.lsupdate_num == 0)
-    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++;
-
-  ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, message,
-                      &o6n->hisaddr, o6n->ospf6_interface->if_id);
-
-  o6n->send_update = thread_add_timer (master, ospf6_send_lsupdate_rxmt, o6n,
-                                       o6n->ospf6_interface->rxmt_interval);
-  return 0;
-}
-
-/* Send LSUpdate containing one LSA directly to the neighbor.
-   This is "implied acknowledgement" */
 void
-ospf6_send_lsupdate_direct (struct ospf6_lsa *lsa, struct ospf6_neighbor *o6n)
+install_element_ospf6_debug_message ()
 {
-  struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
-  struct ospf6_lsupdate lsupdate;
-  int lsa_len;
-
-  /* clear message buffer */
-  OSPF6_MESSAGE_CLEAR (message);
-
-  /* set lsupdate header */
-  lsupdate.lsupdate_num = ntohl (1);
-  OSPF6_MESSAGE_ATTACH (message, &lsupdate, sizeof (struct ospf6_lsupdate));
-
-  /* set one LSA */
-  lsa_len = ntohs (lsa->lsa_hdr->lsh_len);
-  ospf6_lsa_age_update_to_send (lsa, o6n->ospf6_interface->transdelay);
-  OSPF6_MESSAGE_ATTACH (message, lsa->lsa_hdr, lsa_len);
-
-  ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, message, &o6n->hisaddr,
-                      o6n->ospf6_interface->if_id);
+  install_element (ENABLE_NODE, &debug_ospf6_message_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf6_message_cmd);
+  install_element (ENABLE_NODE, &debug_ospf6_message_sendrecv_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf6_message_sendrecv_cmd);
+  install_element (CONFIG_NODE, &debug_ospf6_message_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf6_message_cmd);
+  install_element (CONFIG_NODE, &debug_ospf6_message_sendrecv_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf6_message_sendrecv_cmd);
 }
 
-/* Send LSUpdate containing one LSA by multicast.
-   On non-broadcast link, send it to each neighbor by unicast.
-   This is ordinary flooding */
-void
-ospf6_send_lsupdate_flood (struct ospf6_lsa *lsa, struct ospf6_interface *o6i)
-{
-  struct iovec message[OSPF6_MESSAGE_IOVEC_SIZE];
-  struct ospf6_lsupdate lsupdate;
-  struct in6_addr dst;
-  int lsa_len;
-
-  /* clear message buffer */
-  OSPF6_MESSAGE_CLEAR (message);
-
-  /* set lsupdate header */
-  lsupdate.lsupdate_num = ntohl (1);
-  OSPF6_MESSAGE_ATTACH (message, &lsupdate, sizeof (struct ospf6_lsupdate));
-
-  /* set one LSA */
-  lsa_len = ntohs (lsa->lsa_hdr->lsh_len);
-  ospf6_lsa_age_update_to_send (lsa, o6i->transdelay);
-  OSPF6_MESSAGE_ATTACH (message, lsa->lsa_hdr, lsa_len);
-
-  if (if_is_broadcast (o6i->interface))
-    {
-      /* set destination */
-      if (o6i->state == IFS_DR || o6i->state == IFS_BDR)
-        inet_pton (AF_INET6, ALLSPFROUTERS6, &dst);
-      else
-        inet_pton (AF_INET6, ALLDROUTERS6, &dst);
-    }
-  else
-    {
-      /* IPv6 relies on link local multicast */
-      inet_pton (AF_INET6, ALLSPFROUTERS6, &dst);
-    }
-
-  ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, message, &dst,
-                      o6i->if_id);
-}
-
-int
-ospf6_send_lsack_delayed (struct thread *thread)
-{
-  struct ospf6_interface *o6i;
-  struct iovec message[MAXIOVLIST];
-  struct ospf6_lsa *lsa;
-  struct ospf6_lsdb_node node;
-
-  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;
-
-  if (o6i->state <= IFS_WAITING)
-    return 0;
-
-  if (o6i->ack_list->count == 0)
-    return 0;
-
-  iov_clear (message, MAXIOVLIST);
-
-  for (ospf6_lsdb_head (&node, o6i->ack_list);
-       ! ospf6_lsdb_is_end (&node);
-       ospf6_lsdb_next (&node))
-    {
-      lsa = node.lsa;
-      if (IS_OVER_MTU (message, o6i->ifmtu, sizeof (struct ospf6_lsa_hdr)))
-        break;
-
-      OSPF6_MESSAGE_ATTACH (message, lsa->header,
-                            sizeof (struct ospf6_lsa_header));
-      ospf6_interface_delayed_ack_remove (lsa, o6i);
-    }
-
-  /* statistics */
-  o6i->ospf6_stat_delayed_lsack++;
-
-  switch (o6i->state)
-    {
-    case IFS_DR:
-    case IFS_BDR:
-      ospf6_message_send (OSPF6_MESSAGE_TYPE_LSACK, message,
-                          &allspfrouters6.sin6_addr, o6i->if_id);
-      break;
-    default:
-      ospf6_message_send (OSPF6_MESSAGE_TYPE_LSACK, message,
-                          &alldrouters6.sin6_addr, o6i->if_id);
-      break;
-    }
-
-  iov_clear (message, MAXIOVLIST);
-  return 0;
-}
 
diff --git a/ospf6d/ospf6_message.h b/ospf6d/ospf6_message.h
index 105cb4f..f8be627 100644
--- a/ospf6d/ospf6_message.h
+++ b/ospf6d/ospf6_message.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 1999-2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -22,87 +22,84 @@
 #ifndef OSPF6_MESSAGE_H
 #define OSPF6_MESSAGE_H
 
-#include "ospf6_prefix.h"
-#include "ospf6_lsa.h"
+#define OSPF6_MESSAGE_BUFSIZ  4096
+
+/* Debug option */
+extern unsigned char conf_debug_ospf6_message[];
+#define OSPF6_DEBUG_MESSAGE_SEND 0x01
+#define OSPF6_DEBUG_MESSAGE_RECV 0x02
+#define OSPF6_DEBUG_MESSAGE_ON(type, level) \
+  (conf_debug_ospf6_message[type] |= (level))
+#define OSPF6_DEBUG_MESSAGE_OFF(type, level) \
+  (conf_debug_ospf6_message[type] &= ~(level))
+#define IS_OSPF6_DEBUG_MESSAGE(t, e) \
+  (conf_debug_ospf6_message[t] & OSPF6_DEBUG_MESSAGE_ ## e)
 
 /* Type */
-#define OSPF6_MESSAGE_TYPE_NONE     0x0
 #define OSPF6_MESSAGE_TYPE_UNKNOWN  0x0
 #define OSPF6_MESSAGE_TYPE_HELLO    0x1  /* Discover/maintain neighbors */
 #define OSPF6_MESSAGE_TYPE_DBDESC   0x2  /* Summarize database contents */
-#define OSPF6_MESSAGE_TYPE_LSREQ    0x3  /* Database download */
+#define OSPF6_MESSAGE_TYPE_LSREQ    0x3  /* Database download request */
 #define OSPF6_MESSAGE_TYPE_LSUPDATE 0x4  /* Database update */
 #define OSPF6_MESSAGE_TYPE_LSACK    0x5  /* Flooding acknowledgment */
-#define OSPF6_MESSAGE_TYPE_MAX      0x6
+#define OSPF6_MESSAGE_TYPE_ALL      0x6  /* For debug option */
+
+#define OSPF6_MESSAGE_TYPE_CANONICAL(T) \
+  ((T) > OSPF6_MESSAGE_TYPE_LSACK ? OSPF6_MESSAGE_TYPE_UNKNOWN : (T))
+
+extern char *ospf6_message_type_str[];
+#define OSPF6_MESSAGE_TYPE_NAME(T) \
+  (ospf6_message_type_str[ OSPF6_MESSAGE_TYPE_CANONICAL (T) ])
 
 /* OSPFv3 packet header */
 struct ospf6_header
 {
   u_char    version;
   u_char    type;
-  u_int16_t len;
+  u_int16_t length;
   u_int32_t router_id;
   u_int32_t area_id;
-  u_int16_t cksum;
+  u_int16_t checksum;
   u_char    instance_id;
   u_char    reserved;
 };
 
+#define OSPF6_MESSAGE_END(H) ((caddr_t) (H) + ntohs ((H)->length))
+
 /* Hello */
-#define MAXLISTEDNBR     64
 struct ospf6_hello
 {
   u_int32_t interface_id;
-  u_char    rtr_pri;
+  u_char    priority;
   u_char    options[3];
   u_int16_t hello_interval;
-  u_int16_t router_dead_interval;
-  u_int32_t dr;
-  u_int32_t bdr;
+  u_int16_t dead_interval;
+  u_int32_t drouter;
+  u_int32_t bdrouter;
+  /* Followed by Router-IDs */
 };
 
 /* Database Description */
 struct ospf6_dbdesc
 {
-  u_char    mbz1;
+  u_char    reserved1;
   u_char    options[3];
   u_int16_t ifmtu;
-  u_char    mbz2;
+  u_char    reserved2;
   u_char    bits;
   u_int32_t seqnum;
-  /* Followed by LSAs */
+  /* Followed by LSA Headers */
 };
-#define DEFAULT_INTERFACE_MTU 1500
 
-#define DD_IS_MSBIT_SET(x) ((x) & (1 << 0))
-#define DD_MSBIT_SET(x) ((x) |= (1 << 0))
-#define DD_MSBIT_CLEAR(x) ((x) &= ~(1 << 0))
-#define DD_IS_MBIT_SET(x) ((x) & (1 << 1))
-#define DD_MBIT_SET(x) ((x) |= (1 << 1))
-#define DD_MBIT_CLEAR(x) ((x) &= ~(1 << 1))
-#define DD_IS_IBIT_SET(x) ((x) & (1 << 2))
-#define DD_IBIT_SET(x) ((x) |= (1 << 2))
-#define DD_IBIT_CLEAR(x) ((x) &= ~(1 << 2))
-
-#define DDBIT_IS_MASTER(x)   ((x) &   (1 << 0))
-#define DDBIT_IS_SLAVE(x)  (!((x) &   (1 << 0)))
-#define DDBIT_SET_MASTER(x)  ((x) |=  (1 << 0))
-#define DDBIT_SET_SLAVE(x)   ((x) |= ~(1 << 0))
-#define DDBIT_IS_MORE(x)     ((x) &   (1 << 1))
-#define DDBIT_SET_MORE(x)    ((x) |=  (1 << 1))
-#define DDBIT_CLR_MORE(x)    ((x) |= ~(1 << 1))
-#define DDBIT_IS_INITIAL(x)  ((x) &   (1 << 2))
-#define DDBIT_SET_INITIAL(x) ((x) |=  (1 << 2))
-#define DDBIT_CLR_INITIAL(x) ((x) |= ~(1 << 2))
-
-#define OSPF6_DBDESC_BIT_MASTER  0x01
-#define OSPF6_DBDESC_BIT_MORE    0x02
-#define OSPF6_DBDESC_BIT_INITIAL 0x04
+#define OSPF6_DBDESC_MSBIT (0x01) /* master/slave bit */
+#define OSPF6_DBDESC_MBIT  (0x02) /* more bit */
+#define OSPF6_DBDESC_IBIT  (0x04) /* initial bit */
 
 /* Link State Request */
-struct ospf6_lsreq
+/* It is just a sequence of entries below */
+struct ospf6_lsreq_entry
 {
-  u_int16_t mbz;          /* Must Be Zero */
+  u_int16_t reserved;     /* Must Be Zero */
   u_int16_t type;         /* LS type */
   u_int32_t id;           /* Link State ID */
   u_int32_t adv_router;   /* Advertising Router */
@@ -111,92 +108,33 @@
 /* Link State Update */
 struct ospf6_lsupdate
 {
-  u_int32_t lsupdate_num;
+  u_int32_t lsa_number;
+  /* Followed by LSAs */
 };
 
 /* Link State Acknowledgement */
-  /* no need for structure,
-     it will include only LSA header in the packet body.*/
+/* It is just a sequence of LSA Headers */
 
-/* definition for ospf6_message.c */
-#define OSPF6_MESSAGE_RECEIVE_BUFSIZE 5120
-#define OSPF6_MESSAGE_IOVEC_END       1024
+/* Function definition */
+void ospf6_hello_print (struct ospf6_header *);
+void ospf6_dbdesc_print (struct ospf6_header *);
+void ospf6_lsreq_print (struct ospf6_header *);
+void ospf6_lsupdate_print (struct ospf6_header *);
+void ospf6_lsack_print (struct ospf6_header *);
 
-#define IS_OVER_MTU(message,mtu,addsize) \
-          (iov_totallen(message)+(addsize) >= \
-            (mtu)-sizeof(struct ospf6_header))
+int ospf6_receive (struct thread *thread);
 
-#define OSPF6_MESSAGE_IOVEC_SIZE  1024
-#define OSPF6_MESSAGE_CLEAR(msg) \
-do { \
-  int x; \
-  for (x = 0; x < OSPF6_MESSAGE_IOVEC_SIZE; x++) \
-    { \
-      (msg)[x].iov_base = NULL; \
-      (msg)[x].iov_len = 0; \
-    } \
-} while (0)
+int ospf6_hello_send (struct thread *thread);
+int ospf6_dbdesc_send (struct thread *thread);
+int ospf6_dbdesc_send_newone (struct thread *thread);
+int ospf6_lsreq_send (struct thread *thread);
+int ospf6_lsupdate_send_interface (struct thread *thread);
+int ospf6_lsupdate_send_neighbor (struct thread *thread);
+int ospf6_lsack_send_interface (struct thread *thread);
+int ospf6_lsack_send_neighbor (struct thread *thread);
 
-#define OSPF6_MESSAGE_ATTACH(msg,buf,bufsize) \
-do { \
-  int x; \
-  for (x = 0; x < OSPF6_MESSAGE_IOVEC_SIZE; x++) \
-    if ((msg)[x].iov_base == (void *)NULL && (msg)[x].iov_len == 0) \
-      break; \
-  if (x < OSPF6_MESSAGE_IOVEC_SIZE - 1) \
-    { \
-      (msg)[x].iov_base = (void *)(buf); \
-      (msg)[x].iov_len = (bufsize); \
-    } \
-} while (0)
-
-#define OSPF6_MESSAGE_JOIN(msg,join) \
-do { \
-  int x,y; \
-  for (x = 0; x < OSPF6_MESSAGE_IOVEC_SIZE; x++) \
-    if ((msg)[x].iov_base == NULL && (msg)[x].iov_len == 0) \
-      break; \
-  for (y = x; y < OSPF6_MESSAGE_IOVEC_SIZE; y++) \
-    { \
-      (msg)[y].iov_base = (join)[y - x].iov_base; \
-      (msg)[y].iov_len = (join)[y - x].iov_len; \
-    } \
-} while (0)
-
-
-/* Statistics */
-struct ospf6_message_stat
-{
-  u_int32_t send;
-  u_int32_t send_octet;
-  u_int32_t recv;
-  u_int32_t recv_octet;
-};
-
-/* Type string */
-extern char *ospf6_message_type_string[];
-
-/* Function Prototypes */
-int ospf6_receive (struct thread *);
-
-int ospf6_send_hello (struct thread *);
-int ospf6_send_dbdesc_rxmt (struct thread *);
-int ospf6_send_dbdesc (struct thread *);
-int ospf6_send_lsreq (struct thread *);
-
-struct ospf6_neighbor;
-struct ospf6_interface;
-int
-ospf6_send_lsupdate_rxmt (struct thread *);
-void
-ospf6_send_lsupdate_direct (struct ospf6_lsa *, struct ospf6_neighbor *);
-void
-ospf6_send_lsupdate_flood (struct ospf6_lsa *, struct ospf6_interface *);
-
-int ospf6_send_lsack_delayed (struct thread *);
-int ospf6_send_lsack_direct (struct thread *);
-
-void ospf6_message_send (u_char, struct iovec *, struct in6_addr *, u_int);
+int config_write_ospf6_debug_message (struct vty *);
+void install_element_ospf6_debug_message ();
 
 #endif /* OSPF6_MESSAGE_H */
 
diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c
index 72735d5..acfd1a4 100644
--- a/ospf6d/ospf6_neighbor.c
+++ b/ospf6d/ospf6_neighbor.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -19,321 +19,581 @@
  * Boston, MA 02111-1307, USA.  
  */
 
-#include "ospf6d.h"
-
 #include <zebra.h>
 
 #include "log.h"
+#include "memory.h"
 #include "thread.h"
 #include "linklist.h"
 #include "vty.h"
 #include "command.h"
 
-#include "ospf6_lsa.h"
-#include "ospf6_message.h"
-#include "ospf6_neighbor.h"
-#include "ospf6_nsm.h"
+#include "ospf6d.h"
+#include "ospf6_proto.h"
 #include "ospf6_lsa.h"
 #include "ospf6_lsdb.h"
+#include "ospf6_message.h"
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_interface.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_intra.h"
 
-char *ospf6_neighbor_state_string[] =
-{
-  "None", "Down", "Attempt", "Init", "Twoway",
-  "ExStart", "ExChange", "Loading", "Full", NULL
-};
+unsigned char conf_debug_ospf6_neighbor = 0;
+
+char *ospf6_neighbor_state_str[] =
+{ "None", "Down", "Attempt", "Init", "Twoway", "ExStart", "ExChange",
+  "Loading", "Full", NULL };
 
 int
-ospf6_neighbor_last_dbdesc_release (struct thread *thread)
+ospf6_neighbor_cmp (void *va, void *vb)
 {
-  struct ospf6_neighbor *o6n;
-
-  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
-  assert (o6n);
-  memset (&o6n->last_dd, 0, sizeof (struct ospf6_dbdesc));
-  return 0;
+  struct ospf6_neighbor *ona = (struct ospf6_neighbor *) va;
+  struct ospf6_neighbor *onb = (struct ospf6_neighbor *) vb;
+  return (ntohl (ona->router_id) - ntohl (onb->router_id));
 }
 
-
-
-void
-ospf6_neighbor_thread_cancel_all (struct ospf6_neighbor *o6n)
+struct ospf6_neighbor *
+ospf6_neighbor_lookup (u_int32_t router_id,
+                       struct ospf6_interface *oi)
 {
-  if (o6n->inactivity_timer)
-    thread_cancel (o6n->inactivity_timer);
-  o6n->inactivity_timer = (struct thread *) NULL;
+  listnode n;
+  struct ospf6_neighbor *on;
 
-  if (o6n->send_update)
-    thread_cancel (o6n->send_update);
-  o6n->send_update = (struct thread *) NULL;
-
-  if (o6n->thread_send_dbdesc)
-    thread_cancel (o6n->thread_send_dbdesc);
-  o6n->thread_send_dbdesc = (struct thread *) NULL;
-  if (o6n->thread_rxmt_dbdesc)
-    thread_cancel (o6n->thread_rxmt_dbdesc);
-  o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
-
-  if (o6n->thread_rxmt_lsreq)
-    thread_cancel (o6n->thread_rxmt_lsreq);
-  o6n->thread_rxmt_lsreq = (struct thread *) NULL;
-}
-
-void
-ospf6_neighbor_lslist_clear (struct ospf6_neighbor *nei)
-{
-  ospf6_lsdb_remove_all (nei->summary_list);
-  ospf6_lsdb_remove_all (nei->request_list);
-  ospf6_lsdb_remove_all (nei->retrans_list);
-  ospf6_lsdb_remove_all (nei->dbdesc_list);
-}
-
-void
-ospf6_neighbor_summary_add (struct ospf6_lsa *lsa,
-                            struct ospf6_neighbor *nei)
-{
-  struct ospf6_lsa *summary;
-
-  if (IS_OSPF6_DUMP_NEIGHBOR)
+  for (n = listhead (oi->neighbor_list); n; nextnode (n))
     {
-      zlog_info ("Neighbor %s summary-list:", nei->str);
-      zlog_info ("    Add %s", lsa->str);
+      on = (struct ospf6_neighbor *) getdata (n);
+      if (on->router_id == router_id)
+        return on;
     }
-
-  ospf6_lsa_age_current (lsa);
-  summary = ospf6_lsa_summary_create (lsa->header);
-  ospf6_lsdb_add (summary, nei->summary_list);
-}
-
-void
-ospf6_neighbor_summary_remove (struct ospf6_lsa *lsa,
-                               struct ospf6_neighbor *nei)
-{
-  struct ospf6_lsa *summary;
-
-  if (IS_OSPF6_DUMP_NEIGHBOR)
-    {
-      zlog_info ("Neighbor %s summary-list:", nei->str);
-      zlog_info ("    Remove %s", lsa->str);
-    }
-
-  summary = ospf6_lsdb_lookup_lsdb (lsa->header->type, lsa->header->id,
-                                    lsa->header->adv_router, nei->summary_list);
-  ospf6_lsdb_remove (summary, nei->summary_list);
-}
-
-void
-ospf6_neighbor_request_add (struct ospf6_lsa *lsa,
-                            struct ospf6_neighbor *nei)
-{
-  struct ospf6_lsa *summary;
-
-  if (IS_OSPF6_DUMP_NEIGHBOR)
-    {
-      zlog_info ("Neighbor %s request-list:", nei->str);
-      zlog_info ("    Add %s", lsa->str);
-    }
-
-  ospf6_lsa_age_current (lsa);
-  summary = ospf6_lsa_summary_create (lsa->header);
-  ospf6_lsdb_add (summary, nei->request_list);
-}
-
-void
-ospf6_neighbor_request_remove (struct ospf6_lsa *lsa,
-                               struct ospf6_neighbor *nei)
-{
-  struct ospf6_lsa *summary;
-
-  if (IS_OSPF6_DUMP_NEIGHBOR)
-    {
-      zlog_info ("Neighbor %s request-list:", nei->str);
-      zlog_info ("    Remove %s", lsa->str);
-    }
-
-  summary = ospf6_lsdb_lookup_lsdb (lsa->header->type, lsa->header->id,
-                                    lsa->header->adv_router, nei->request_list);
-  ospf6_lsdb_remove (summary, nei->request_list);
-}
-
-void
-ospf6_neighbor_retrans_add (struct ospf6_lsa *lsa,
-                            struct ospf6_neighbor *nei)
-{
-  if (IS_OSPF6_DUMP_NEIGHBOR)
-    {
-      zlog_info ("Neighbor %s retrans-list:", nei->str);
-      zlog_info ("    Add %s", lsa->str);
-    }
-
-  ospf6_lsdb_add (lsa, nei->retrans_list);
-}
-
-void
-ospf6_neighbor_retrans_remove (struct ospf6_lsa *lsa,
-                               struct ospf6_neighbor *nei)
-{
-  if (IS_OSPF6_DUMP_NEIGHBOR)
-    {
-      zlog_info ("Neighbor %s retrans-list:", nei->str);
-      zlog_info ("    Remove %s", lsa->str);
-    }
-
-  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
-ospf6_neighbor_dbdesc_add (struct ospf6_lsa *lsa,
-                           struct ospf6_neighbor *nei)
-{
-  if (IS_OSPF6_DUMP_NEIGHBOR)
-    {
-      zlog_info ("Neighbor %s dbdesc-list:", nei->str);
-      zlog_info ("    Add %s", lsa->str);
-    }
-
-  ospf6_lsdb_add (lsa, nei->dbdesc_list);
-}
-
-void
-ospf6_neighbor_dbdesc_remove (struct ospf6_lsa *lsa,
-                              struct ospf6_neighbor *nei)
-{
-  if (IS_OSPF6_DUMP_NEIGHBOR)
-    {
-      zlog_info ("Neighbor %s dbdesc-list:", nei->str);
-      zlog_info ("    Remove %s", lsa->str);
-    }
-
-  ospf6_lsdb_remove (lsa, nei->dbdesc_list);
-}
-
-
-/* prepare summary-list of his neighbor structure */
-void
-ospf6_neighbor_dbex_init (struct ospf6_neighbor *nei)
-{
-  struct ospf6_lsdb_node node;
-
-  /* clear ls-list */
-  ospf6_neighbor_lslist_clear (nei);
-
-  /* AS scope LSAs */
-  for (ospf6_lsdb_head (&node, nei->ospf6_interface->area->ospf6->lsdb);
-       ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node))
-    {
-      if (IS_LSA_MAXAGE (node.lsa))
-        ospf6_neighbor_retrans_add (node.lsa, nei);
-      else
-        ospf6_neighbor_summary_add (node.lsa, nei);
-    }
-
-  /* AREA scope LSAs */
-  for (ospf6_lsdb_head (&node, nei->ospf6_interface->area->lsdb);
-       ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node))
-    {
-      if (IS_LSA_MAXAGE (node.lsa))
-        ospf6_neighbor_retrans_add (node.lsa, nei);
-      else
-        ospf6_neighbor_summary_add (node.lsa, nei);
-    }
-
-  /* INTERFACE scope LSAs */
-  for (ospf6_lsdb_head (&node, nei->ospf6_interface->lsdb);
-       ! ospf6_lsdb_is_end (&node); ospf6_lsdb_next (&node))
-    {
-      if (IS_LSA_MAXAGE (node.lsa))
-        ospf6_neighbor_retrans_add (node.lsa, nei);
-      else
-        ospf6_neighbor_summary_add (node.lsa, nei);
-    }
+  return (struct ospf6_neighbor *) NULL;
 }
 
 /* create ospf6_neighbor */
 struct ospf6_neighbor *
-ospf6_neighbor_create (u_int32_t router_id, struct ospf6_interface *o6i)
+ospf6_neighbor_create (u_int32_t router_id, struct ospf6_interface *oi)
 {
-  struct ospf6_neighbor *new;
-  char buf[32];
+  struct ospf6_neighbor *on;
+  char buf[16];
 
-  new = (struct ospf6_neighbor *)
+  on = (struct ospf6_neighbor *)
     XMALLOC (MTYPE_OSPF6_NEIGHBOR, sizeof (struct ospf6_neighbor));
-  if (new == NULL)
+  if (on == NULL)
     {
       zlog_warn ("neighbor: malloc failed");
       return NULL;
     }
 
-  memset (new, 0, sizeof (struct ospf6_neighbor));
-
-  new->state = OSPF6_NEIGHBOR_STATE_DOWN;
-
-  new->router_id = router_id;
+  memset (on, 0, sizeof (struct ospf6_neighbor));
   inet_ntop (AF_INET, &router_id, buf, sizeof (buf));
-  snprintf (new->str, sizeof (new->str), "%s%%%s", buf, o6i->interface->name);
-  new->inactivity_timer = (struct thread *) NULL;
+  snprintf (on->name, sizeof (on->name), "%s%%%s",
+            buf, oi->interface->name);
+  on->ospf6_if = oi;
+  on->state = OSPF6_NEIGHBOR_DOWN;
+  gettimeofday (&on->last_changed, (struct timezone *) NULL);
+  on->router_id = router_id;
 
-  new->summary_list = ospf6_lsdb_create ();
-  new->request_list = ospf6_lsdb_create ();
-  new->retrans_list = ospf6_lsdb_create ();
-  new->dbdesc_list = ospf6_lsdb_create ();
+  on->summary_list = ospf6_lsdb_create ();
+  on->request_list = ospf6_lsdb_create ();
+  on->retrans_list = ospf6_lsdb_create ();
 
-  listnode_add (o6i->neighbor_list, new);
-  new->ospf6_interface = o6i;
+  on->dbdesc_list = ospf6_lsdb_create ();
+  on->lsreq_list = ospf6_lsdb_create ();
+  on->lsupdate_list = ospf6_lsdb_create ();
+  on->lsack_list = ospf6_lsdb_create ();
 
-  CALL_ADD_HOOK (&neighbor_hook, new);
-
-  return new;
+  listnode_add_sort (oi->neighbor_list, on);
+  return on;
 }
 
 void
-ospf6_neighbor_delete (struct ospf6_neighbor *o6n)
+ospf6_neighbor_delete (struct ospf6_neighbor *on)
 {
-  CALL_REMOVE_HOOK (&neighbor_hook, o6n);
+  ospf6_lsdb_remove_all (on->summary_list);
+  ospf6_lsdb_remove_all (on->request_list);
+  ospf6_lsdb_remove_all (on->retrans_list);
 
-  ospf6_neighbor_thread_cancel_all (o6n);
-  ospf6_neighbor_lslist_clear (o6n);
+  ospf6_lsdb_remove_all (on->dbdesc_list);
+  ospf6_lsdb_remove_all (on->lsreq_list);
+  ospf6_lsdb_remove_all (on->lsupdate_list);
+  ospf6_lsdb_remove_all (on->lsack_list);
 
-  list_free (o6n->dbdesc_lsa);
+  ospf6_lsdb_delete (on->summary_list);
+  ospf6_lsdb_delete (on->request_list);
+  ospf6_lsdb_delete (on->retrans_list);
 
-  ospf6_lsdb_delete (o6n->summary_list);
-  ospf6_lsdb_delete (o6n->request_list);
-  ospf6_lsdb_delete (o6n->retrans_list);
-  ospf6_lsdb_delete (o6n->dbdesc_list);
+  ospf6_lsdb_delete (on->dbdesc_list);
+  ospf6_lsdb_delete (on->lsreq_list);
+  ospf6_lsdb_delete (on->lsupdate_list);
+  ospf6_lsdb_delete (on->lsack_list);
 
-  XFREE (MTYPE_OSPF6_NEIGHBOR, o6n);
+  THREAD_OFF (on->inactivity_timer);
+
+  THREAD_OFF (on->thread_send_dbdesc);
+  THREAD_OFF (on->thread_send_lsreq);
+  THREAD_OFF (on->thread_send_lsupdate);
+  THREAD_OFF (on->thread_send_lsack);
+
+  XFREE (MTYPE_OSPF6_NEIGHBOR, on);
 }
 
-struct ospf6_neighbor *
-ospf6_neighbor_lookup (u_int32_t router_id,
-                       struct ospf6_interface *o6i)
+static void
+ospf6_neighbor_state_change (u_char next_state, struct ospf6_neighbor *on)
 {
-  listnode n;
-  struct ospf6_neighbor *o6n;
+  u_char prev_state;
 
-  for (n = listhead (o6i->neighbor_list); n; nextnode (n))
+  prev_state = on->state;
+  on->state = next_state;
+
+  if (prev_state == next_state)
+    return;
+
+  gettimeofday (&on->last_changed, (struct timezone *) NULL);
+
+  /* log */
+  if (IS_OSPF6_DEBUG_NEIGHBOR (STATE))
     {
-      o6n = (struct ospf6_neighbor *) getdata (n);
-      if (o6n->router_id == router_id)
-        return o6n;
+      zlog_info ("Neighbor state change %s: [%s]->[%s]", on->name,
+                 ospf6_neighbor_state_str[prev_state],
+                 ospf6_neighbor_state_str[next_state]);
     }
-  return (struct ospf6_neighbor *) NULL;
+
+  if (prev_state == OSPF6_NEIGHBOR_FULL || next_state == OSPF6_NEIGHBOR_FULL)
+    {
+      OSPF6_ROUTER_LSA_SCHEDULE (on->ospf6_if->area);
+      if (on->ospf6_if->state == OSPF6_INTERFACE_DR)
+        {
+          OSPF6_NETWORK_LSA_SCHEDULE (on->ospf6_if);
+          OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (on->ospf6_if);
+          OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (on->ospf6_if->area);
+        }
+    }
+
+#ifdef XXX
+  if (prev_state == NBS_FULL || next_state == NBS_FULL)
+    nbs_full_change (on->ospf6_interface);
+
+  /* check for LSAs that already reached MaxAge */
+  if ((prev_state == OSPF6_NEIGHBOR_EXCHANGE ||
+       prev_state == OSPF6_NEIGHBOR_LOADING) &&
+      (next_state != OSPF6_NEIGHBOR_EXCHANGE &&
+       next_state != OSPF6_NEIGHBOR_LOADING))
+    {
+      ospf6_maxage_remover ();
+    }
+#endif /*XXX*/
+
 }
 
+/* RFC2328 section 10.4 */
+int
+need_adjacency (struct ospf6_neighbor *on)
+{
+  if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT ||
+      on->ospf6_if->state == OSPF6_INTERFACE_DR ||
+      on->ospf6_if->state == OSPF6_INTERFACE_BDR)
+    return 1;
+
+  if (on->ospf6_if->drouter == on->router_id ||
+      on->ospf6_if->bdrouter == on->router_id)
+    return 1;
+
+  return 0;
+}
+
+int
+hello_received (struct thread *thread)
+{
+  struct ospf6_neighbor *on;
+
+  on = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (on);
+
+  if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT))
+    zlog_info ("Neighbor Event %s: *HelloReceived*", on->name);
+
+  /* reset Inactivity Timer */
+  THREAD_OFF (on->inactivity_timer);
+  on->inactivity_timer = thread_add_timer (master, inactivity_timer, on,
+                                           on->ospf6_if->dead_interval);
+
+  if (on->state <= OSPF6_NEIGHBOR_DOWN)
+    ospf6_neighbor_state_change (OSPF6_NEIGHBOR_INIT, on);
+
+  return 0;
+}
+
+int
+twoway_received (struct thread *thread)
+{
+  struct ospf6_neighbor *on;
+
+  on = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (on);
+
+  if (on->state > OSPF6_NEIGHBOR_INIT)
+    return 0;
+
+  if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT))
+    zlog_info ("Neighbor Event %s: *2Way-Received*", on->name);
+
+  thread_add_event (master, neighbor_change, on->ospf6_if, 0);
+
+  if (! need_adjacency (on))
+    {
+      ospf6_neighbor_state_change (OSPF6_NEIGHBOR_TWOWAY, on);
+      return 0;
+    }
+
+  ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on);
+  SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT);
+  SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT);
+  SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT);
+
+  THREAD_OFF (on->thread_send_dbdesc);
+  on->thread_send_dbdesc =
+    thread_add_event (master, ospf6_dbdesc_send, on, 0);
+
+  return 0;
+}
+
+int
+negotiation_done (struct thread *thread)
+{
+  struct ospf6_neighbor *on;
+  struct ospf6_lsa *lsa;
+
+  on = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (on);
+
+  if (on->state != OSPF6_NEIGHBOR_EXSTART)
+    return 0;
+
+  if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT))
+    zlog_info ("Neighbor Event %s: *NegotiationDone*", on->name);
+
+  /* clear ls-list */
+  ospf6_lsdb_remove_all (on->summary_list);
+  ospf6_lsdb_remove_all (on->request_list);
+  ospf6_lsdb_remove_all (on->retrans_list);
+
+  /* Interface scoped LSAs */
+  for (lsa = ospf6_lsdb_head (on->ospf6_if->lsdb); lsa;
+       lsa = ospf6_lsdb_next (lsa))
+    {
+      if (IS_OSPF6_DEBUG_LSA (DATABASE))
+        zlog_info ("Add copy of %s to %s of %s", lsa->name,
+                   (OSPF6_LSA_IS_MAXAGE (lsa) ? "retrans_list" :
+                    "summary_list"), on->name);
+      if (OSPF6_LSA_IS_MAXAGE (lsa))
+        ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->retrans_list);
+      else
+        ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->summary_list);
+    }
+
+  /* Area scoped LSAs */
+  for (lsa = ospf6_lsdb_head (on->ospf6_if->area->lsdb); lsa;
+       lsa = ospf6_lsdb_next (lsa))
+    {
+      if (IS_OSPF6_DEBUG_LSA (DATABASE))
+        zlog_info ("Add copy of %s to %s of %s", lsa->name,
+                   (OSPF6_LSA_IS_MAXAGE (lsa) ? "retrans_list" :
+                    "summary_list"), on->name);
+      if (OSPF6_LSA_IS_MAXAGE (lsa))
+        ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->retrans_list);
+      else
+        ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->summary_list);
+    }
+
+  /* AS scoped LSAs */
+  for (lsa = ospf6_lsdb_head (on->ospf6_if->area->ospf6->lsdb); lsa;
+       lsa = ospf6_lsdb_next (lsa))
+    {
+      if (IS_OSPF6_DEBUG_LSA (DATABASE))
+        zlog_info ("Add copy of %s to %s of %s", lsa->name,
+                   (OSPF6_LSA_IS_MAXAGE (lsa) ? "retrans_list" :
+                    "summary_list"), on->name);
+      if (OSPF6_LSA_IS_MAXAGE (lsa))
+        ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->retrans_list);
+      else
+        ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->summary_list);
+    }
+
+  UNSET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT);
+  ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXCHANGE, on);
+
+  return 0;
+}
+
+int
+exchange_done (struct thread *thread)
+{
+  struct ospf6_neighbor *on;
+
+  on = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (on);
+
+  if (on->state != OSPF6_NEIGHBOR_EXCHANGE)
+    return 0;
+
+  if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT))
+    zlog_info ("Neighbor Event %s: *ExchangeDone*", on->name);
+
+  THREAD_OFF (on->thread_send_dbdesc);
+  ospf6_lsdb_remove_all (on->dbdesc_list);
+
+/* XXX
+  thread_add_timer (master, ospf6_neighbor_last_dbdesc_release, on,
+                    on->ospf6_if->dead_interval);
+*/
+
+  if (on->request_list->count == 0)
+    ospf6_neighbor_state_change (OSPF6_NEIGHBOR_FULL, on);
+  else
+    ospf6_neighbor_state_change (OSPF6_NEIGHBOR_LOADING, on);
+
+  return 0;
+}
+
+int
+loading_done (struct thread *thread)
+{
+  struct ospf6_neighbor *on;
+
+  on = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (on);
+
+  if (on->state != OSPF6_NEIGHBOR_LOADING)
+    return 0;
+
+  if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT))
+    zlog_info ("Neighbor Event %s: *LoadingDone*", on->name);
+
+  assert (on->request_list->count == 0);
+
+  ospf6_neighbor_state_change (OSPF6_NEIGHBOR_FULL, on);
+
+  return 0;
+}
+
+int
+adj_ok (struct thread *thread)
+{
+  struct ospf6_neighbor *on;
+
+  on = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (on);
+
+  if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT))
+    zlog_info ("Neighbor Event %s: *AdjOK?*", on->name);
+
+  if (on->state == OSPF6_NEIGHBOR_TWOWAY && need_adjacency (on))
+    {
+      ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on);
+      SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT);
+      SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT);
+      SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT);
+
+      THREAD_OFF (on->thread_send_dbdesc);
+      on->thread_send_dbdesc =
+        thread_add_event (master, ospf6_dbdesc_send, on, 0);
+
+    }
+  else if (on->state >= OSPF6_NEIGHBOR_EXSTART &&
+           ! need_adjacency (on))
+    {
+      ospf6_neighbor_state_change (OSPF6_NEIGHBOR_TWOWAY, on);
+      ospf6_lsdb_remove_all (on->summary_list);
+      ospf6_lsdb_remove_all (on->request_list);
+      ospf6_lsdb_remove_all (on->retrans_list);
+    }
+
+  return 0;
+}
+
+int
+seqnumber_mismatch (struct thread *thread)
+{
+  struct ospf6_neighbor *on;
+
+  on = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (on);
+
+  if (on->state < OSPF6_NEIGHBOR_EXCHANGE)
+    return 0;
+
+  if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT))
+    zlog_info ("Neighbor Event %s: *SeqNumberMismatch*", on->name);
+
+  ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on);
+  SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT);
+  SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT);
+  SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT);
+
+  ospf6_lsdb_remove_all (on->summary_list);
+  ospf6_lsdb_remove_all (on->request_list);
+  ospf6_lsdb_remove_all (on->retrans_list);
+
+  THREAD_OFF (on->thread_send_dbdesc);
+  on->thread_send_dbdesc =
+    thread_add_event (master, ospf6_dbdesc_send, on, 0);
+
+  return 0;
+}
+
+int
+bad_lsreq (struct thread *thread)
+{
+  struct ospf6_neighbor *on;
+
+  on = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (on);
+
+  if (on->state < OSPF6_NEIGHBOR_EXCHANGE)
+    return 0;
+
+  if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT))
+    zlog_info ("Neighbor Event %s: *BadLSReq*", on->name);
+
+  ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on);
+  SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT);
+  SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT);
+  SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT);
+
+  ospf6_lsdb_remove_all (on->summary_list);
+  ospf6_lsdb_remove_all (on->request_list);
+  ospf6_lsdb_remove_all (on->retrans_list);
+
+  THREAD_OFF (on->thread_send_dbdesc);
+  on->thread_send_dbdesc =
+    thread_add_event (master, ospf6_dbdesc_send, on, 0);
+
+  return 0;
+}
+
+int
+oneway_received (struct thread *thread)
+{
+  struct ospf6_neighbor *on;
+
+  on = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (on);
+
+  if (on->state < OSPF6_NEIGHBOR_TWOWAY)
+    return 0;
+
+  if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT))
+    zlog_info ("Neighbor Event %s: *1Way-Received*", on->name);
+
+  ospf6_neighbor_state_change (OSPF6_NEIGHBOR_INIT, on);
+  thread_add_event (master, neighbor_change, on->ospf6_if, 0);
+
+  ospf6_lsdb_remove_all (on->summary_list);
+  ospf6_lsdb_remove_all (on->request_list);
+  ospf6_lsdb_remove_all (on->retrans_list);
+
+  THREAD_OFF (on->thread_send_dbdesc);
+  THREAD_OFF (on->thread_send_lsreq);
+  THREAD_OFF (on->thread_send_lsupdate);
+  THREAD_OFF (on->thread_send_lsack);
+
+  return 0;
+}
+
+int
+inactivity_timer (struct thread *thread)
+{
+  struct ospf6_neighbor *on;
+
+  on = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (on);
+
+  if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT))
+    zlog_info ("Neighbor Event %s: *InactivityTimer*", on->name);
+
+  on->inactivity_timer = NULL;
+  on->drouter = on->prev_drouter = 0;
+  on->bdrouter = on->prev_bdrouter = 0;
+
+  ospf6_neighbor_state_change (OSPF6_NEIGHBOR_DOWN, on);
+  thread_add_event (master, neighbor_change, on->ospf6_if, 0);
+
+  listnode_delete (on->ospf6_if->neighbor_list, on);
+  ospf6_neighbor_delete (on);
+
+  return 0;
+}
+
+
 
 /* vty functions */
 /* show neighbor structure */
 void
-ospf6_neighbor_show_summary (struct vty *vty, struct ospf6_neighbor *o6n)
+ospf6_neighbor_show (struct vty *vty, struct ospf6_neighbor *on)
 {
   char router_id[16];
-  char dr[16], bdr[16];
+  char duration[16];
+  struct timeval now, res;
+  char nstate[16];
+  char deadtime[16];
+  long h, m, s;
+
+  /* Router-ID (Name) */
+  inet_ntop (AF_INET, &on->router_id, router_id, sizeof (router_id));
+#ifdef HAVE_GETNAMEINFO
+  {
+  }
+#endif /*HAVE_GETNAMEINFO*/
+
+  gettimeofday (&now, NULL);
+
+  /* Dead time */
+  h = m = s = 0;
+  if (on->inactivity_timer)
+    {
+      s = on->inactivity_timer->u.sands.tv_sec - now.tv_sec;
+      h = s / 3600;
+      s -= h * 3600;
+      m = s / 60;
+      s -= m * 60;
+    }
+  snprintf (deadtime, sizeof (deadtime), "%02ld:%02ld:%02ld", h, m, s);
+
+  /* Neighbor State */
+  if (if_is_pointopoint (on->ospf6_if->interface))
+    snprintf (nstate, sizeof (nstate), "PointToPoint");
+  else
+    {
+      if (on->router_id == on->drouter)
+        snprintf (nstate, sizeof (nstate), "DR");
+      else if (on->router_id == on->bdrouter)
+        snprintf (nstate, sizeof (nstate), "BDR");
+      else
+        snprintf (nstate, sizeof (nstate), "DROther");
+    }
+
+  /* Duration */
+  timersub (&now, &on->last_changed, &res);
+  timerstring (&res, duration, sizeof (duration));
+
+  /*
+  vty_out (vty, "%-15s %3d %11s %6s/%-12s %11s %s[%s]%s",
+           "Neighbor ID", "Pri", "DeadTime", "State", "", "Duration",
+           "I/F", "State", VTY_NEWLINE);
+  */
+
+  vty_out (vty, "%-15s %3d %11s %6s/%-12s %11s %s[%s]%s",
+           router_id, on->priority, deadtime,
+           ospf6_neighbor_state_str[on->state], nstate, duration,
+           on->ospf6_if->interface->name,
+           ospf6_interface_state_str[on->ospf6_if->state], VTY_NEWLINE);
+}
+
+void
+ospf6_neighbor_show_drchoice (struct vty *vty, struct ospf6_neighbor *on)
+{
+  char router_id[16];
+  char drouter[16], bdrouter[16];
   char duration[16];
   struct timeval now, res;
 
@@ -343,247 +603,232 @@
              "State", VTY_NEWLINE);
 */
 
-  inet_ntop (AF_INET, &o6n->router_id, router_id, sizeof (router_id));
-  inet_ntop (AF_INET, &o6n->dr, dr, sizeof (dr));
-  inet_ntop (AF_INET, &o6n->bdr, bdr, sizeof (bdr));
+  inet_ntop (AF_INET, &on->router_id, router_id, sizeof (router_id));
+  inet_ntop (AF_INET, &on->drouter, drouter, sizeof (drouter));
+  inet_ntop (AF_INET, &on->bdrouter, bdrouter, sizeof (bdrouter));
 
   gettimeofday (&now, NULL);
-  ospf6_timeval_sub (&now, &o6n->last_changed, &res);
-  ospf6_timeval_string_summary (&res, duration, sizeof (duration));
+  timersub (&now, &on->last_changed, &res);
+  timerstring (&res, duration, sizeof (duration));
 
   vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s",
-           router_id, ospf6_neighbor_state_string[o6n->state],
-           duration, dr, bdr, o6n->ospf6_interface->interface->name,
-           ospf6_interface_state_string[o6n->ospf6_interface->state],
+           router_id, ospf6_neighbor_state_str[on->state],
+           duration, drouter, bdrouter, on->ospf6_if->interface->name,
+           ospf6_interface_state_str[on->ospf6_if->state],
            VTY_NEWLINE);
 }
 
 void
-ospf6_neighbor_show (struct vty *vty, struct ospf6_neighbor *o6n)
+ospf6_neighbor_show_detail (struct vty *vty, struct ospf6_neighbor *on)
 {
-  char hisaddr[64], timestring[32];
+  char drouter[16], bdrouter[16];
+  char linklocal_addr[64], duration[32];
   struct timeval now, res;
+  struct ospf6_lsa *lsa;
 
-  inet_ntop (AF_INET6, &o6n->hisaddr, hisaddr, sizeof (hisaddr));
-  vty_out (vty, " Neighbor %s, interface address %s%s",
-           o6n->str, hisaddr, VTY_NEWLINE);
-  vty_out (vty, "    Area %s via interface %s (ifindex %d)%s",
-           o6n->ospf6_interface->area->str,
-           o6n->ospf6_interface->interface->name,
-           o6n->ospf6_interface->interface->ifindex,
-           VTY_NEWLINE);
-  vty_out (vty, "    Priority: %d, State: %s, %d state changes%s",
-           o6n->priority, ospf6_neighbor_state_string[o6n->state],
-           o6n->ospf6_stat_state_changed, VTY_NEWLINE);
+  inet_ntop (AF_INET6, &on->linklocal_addr, linklocal_addr,
+             sizeof (linklocal_addr));
+  inet_ntop (AF_INET, &on->drouter, drouter, sizeof (drouter));
+  inet_ntop (AF_INET, &on->bdrouter, bdrouter, sizeof (bdrouter));
 
   gettimeofday (&now, NULL);
-  ospf6_timeval_sub (&now, &o6n->last_changed, &res);
-  ospf6_timeval_string_summary (&res, timestring, sizeof (timestring));
-  vty_out (vty, "    Last state changed: %s ago%s", timestring, VTY_NEWLINE);
-}
+  timersub (&now, &on->last_changed, &res);
+  timerstring (&res, duration, sizeof (duration));
 
-void
-ospf6_neighbor_show_detail (struct vty *vty, struct ospf6_neighbor *o6n)
-{
-  char hisdr[16], hisbdr[16];
-
-  ospf6_neighbor_show (vty, o6n);
-
-  inet_ntop (AF_INET, &o6n->dr, hisdr, sizeof (hisdr));
-  inet_ntop (AF_INET, &o6n->bdr, hisbdr, sizeof (hisbdr));
-
-  vty_out (vty, "    His Ifindex of myside: %d%s",
-                o6n->ifid, VTY_NEWLINE);
-  vty_out (vty, "    His DR Election: DR %s, BDR %s%s",
-                hisdr, hisbdr, VTY_NEWLINE);
-
-  vty_out (vty, "    Last received DbDesc: opt:%s"
-                " ifmtu:%hu bit:%s%s%s seqnum:%ld%s",
-                "xxx", ntohs (o6n->last_dd.ifmtu),
-                (DD_IS_IBIT_SET (o6n->last_dd.bits) ? "I" : "-"),
-                (DD_IS_MBIT_SET (o6n->last_dd.bits) ? "M" : "-"),
-                (DD_IS_MSBIT_SET (o6n->last_dd.bits) ? "m" : "s"),
-                (u_long)ntohl (o6n->last_dd.seqnum), VTY_NEWLINE);
-  vty_out (vty, "    My DbDesc bit for this neighbor: %s%s%s%s",
-           (DD_IS_IBIT_SET (o6n->dbdesc_bits) ? "I" : "-"),
-           (DD_IS_MBIT_SET (o6n->dbdesc_bits) ? "M" : "-"),
-           (DD_IS_MSBIT_SET (o6n->dbdesc_bits) ? "m" : "s"),
+  vty_out (vty, " Neighbor %s%s", on->name,
+           VTY_NEWLINE);
+  vty_out (vty, "    Area %s via interface %s (ifindex %d)%s",
+           on->ospf6_if->area->name,
+           on->ospf6_if->interface->name,
+           on->ospf6_if->interface->ifindex,
+           VTY_NEWLINE);
+  vty_out (vty, "    His IfIndex: %d Link-local address: %s%s",
+           on->ifindex, linklocal_addr,
+           VTY_NEWLINE);
+  vty_out (vty, "    State %s for a duration of %s%s",
+           ospf6_neighbor_state_str[on->state], duration,
+           VTY_NEWLINE);
+  vty_out (vty, "    His choice of DR/BDR %s/%s, Priority %d%s",
+           drouter, bdrouter, on->priority,
+           VTY_NEWLINE);
+  vty_out (vty, "    DbDesc status: %s%s%s SeqNum: %#lx%s",
+           (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT) ? "Initial " : ""),
+           (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT) ? "More " : ""),
+           (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT) ?
+            "Master" : "Slave"), (u_long) ntohl (on->dbdesc_seqnum),
            VTY_NEWLINE);
 
-  vty_out (vty, "    %-16s %5d times, %-16s %5d times%s",
-                "SeqnumMismatch", o6n->ospf6_stat_seqnum_mismatch,
-                "BadLSReq", o6n->ospf6_stat_bad_lsreq, VTY_NEWLINE);
-  vty_out (vty, "    %-16s %5d times, %-16s %5d times%s",
-                "OnewayReceived", o6n->ospf6_stat_oneway_received,
-                "InactivityTimer", o6n->ospf6_stat_inactivity_timer,
-                VTY_NEWLINE);
-  vty_out (vty, "    %-16s %5d times, %-16s %5d times%s",
-                "DbDescRetrans", o6n->ospf6_stat_retrans_dbdesc,
-                "LSReqRetrans", o6n->ospf6_stat_retrans_lsreq,
-                VTY_NEWLINE);
-  vty_out (vty, "    %-16s %5d times%s",
-                "LSUpdateRetrans", o6n->ospf6_stat_retrans_lsupdate,
-                VTY_NEWLINE);
-  vty_out (vty, "    %-16s %5d times, %-16s %5d times%s",
-                "LSAReceived", o6n->ospf6_stat_received_lsa,
-                "LSUpdateReceived", o6n->ospf6_stat_received_lsupdate,
-                VTY_NEWLINE);
+  vty_out (vty, "    Summary-List: %d LSAs%s", on->summary_list->count,
+           VTY_NEWLINE);
+  for (lsa = ospf6_lsdb_head (on->summary_list); lsa;
+       lsa = ospf6_lsdb_next (lsa))
+    vty_out (vty, "      %s%s", lsa->name, VTY_NEWLINE);
 
-  vty_out (vty, "    %-12s %-12s %-12s%s",
-           "Message", "DbDesc", "LSReq", VTY_NEWLINE);
-  vty_out (vty, "    %-12s %12d %12d%s", "LSA Send",
-           o6n->lsa_send[OSPF6_MESSAGE_TYPE_DBDESC],
-           o6n->lsa_send[OSPF6_MESSAGE_TYPE_LSREQ], VTY_NEWLINE);
-  vty_out (vty, "    %-12s %12d %12d%s", "LSA Receive",
-           o6n->lsa_receive[OSPF6_MESSAGE_TYPE_DBDESC],
-           o6n->lsa_receive[OSPF6_MESSAGE_TYPE_LSREQ], VTY_NEWLINE);
-  vty_out (vty, "%s", VTY_NEWLINE);
+  vty_out (vty, "    Request-List: %d LSAs%s", on->request_list->count,
+           VTY_NEWLINE);
+  for (lsa = ospf6_lsdb_head (on->request_list); lsa;
+       lsa = ospf6_lsdb_next (lsa))
+    vty_out (vty, "      %s%s", lsa->name, VTY_NEWLINE);
+
+  vty_out (vty, "    Retrans-List: %d LSAs%s", on->retrans_list->count,
+           VTY_NEWLINE);
+  for (lsa = ospf6_lsdb_head (on->retrans_list); lsa;
+       lsa = ospf6_lsdb_next (lsa))
+    vty_out (vty, "      %s%s", lsa->name, VTY_NEWLINE);
+
+  timerclear (&res);
+  if (on->thread_send_dbdesc)
+    timersub (&on->thread_send_dbdesc->u.sands, &now, &res);
+  timerstring (&res, duration, sizeof (duration));
+  vty_out (vty, "    %d Pending LSAs for DbDesc in Time %s [thread %s]%s",
+           on->dbdesc_list->count, duration,
+           (on->thread_send_dbdesc ? "on" : "off"),
+           VTY_NEWLINE);
+  for (lsa = ospf6_lsdb_head (on->dbdesc_list); lsa;
+       lsa = ospf6_lsdb_next (lsa))
+    vty_out (vty, "      %s%s", lsa->name, VTY_NEWLINE);
+
+  timerclear (&res);
+  if (on->thread_send_lsreq)
+    timersub (&on->thread_send_lsreq->u.sands, &now, &res);
+  timerstring (&res, duration, sizeof (duration));
+  vty_out (vty, "    %d Pending LSAs for LSReq in Time %s [thread %s]%s",
+           on->lsreq_list->count, duration,
+           (on->thread_send_lsreq ? "on" : "off"),
+           VTY_NEWLINE);
+  for (lsa = ospf6_lsdb_head (on->lsreq_list); lsa;
+       lsa = ospf6_lsdb_next (lsa))
+    vty_out (vty, "      %s%s", lsa->name, VTY_NEWLINE);
+
+  timerclear (&res);
+  if (on->thread_send_lsupdate)
+    timersub (&on->thread_send_lsupdate->u.sands, &now, &res);
+  timerstring (&res, duration, sizeof (duration));
+  vty_out (vty, "    %d Pending LSAs for LSUpdate in Time %s [thread %s]%s",
+           on->lsupdate_list->count, duration,
+           (on->thread_send_lsupdate ? "on" : "off"),
+           VTY_NEWLINE);
+  for (lsa = ospf6_lsdb_head (on->lsupdate_list); lsa;
+       lsa = ospf6_lsdb_next (lsa))
+    vty_out (vty, "      %s%s", lsa->name, VTY_NEWLINE);
+
+  timerclear (&res);
+  if (on->thread_send_lsack)
+    timersub (&on->thread_send_lsack->u.sands, &now, &res);
+  timerstring (&res, duration, sizeof (duration));
+  vty_out (vty, "    %d Pending LSAs for LSAck in Time %s [thread %s]%s",
+           on->lsack_list->count, duration,
+           (on->thread_send_lsack ? "on" : "off"),
+           VTY_NEWLINE);
+  for (lsa = ospf6_lsdb_head (on->lsack_list); lsa;
+       lsa = ospf6_lsdb_next (lsa))
+    vty_out (vty, "      %s%s", lsa->name, VTY_NEWLINE);
+
 }
 
-void
-ospf6_neighbor_timestamp_hello (struct ospf6_neighbor *o6n)
-{
-  struct timeval now, interval;
-  gettimeofday (&now, (struct timezone *) NULL);
-  if (o6n->tv_last_hello_received.tv_sec)
-    {
-      ospf6_timeval_sub (&now, &o6n->tv_last_hello_received, &interval);
-      zlog_info ("Hello Interval %s : %ld msec",
-                  o6n->str, interval.tv_sec * 1000 + interval.tv_usec % 1000);
-    }
-  o6n->tv_last_hello_received.tv_sec = now.tv_sec;
-  o6n->tv_last_hello_received.tv_usec = now.tv_usec;
-}
-
-DEFUN (show_ipv6_ospf6_neighbor_routerid,
-       show_ipv6_ospf6_neighbor_routerid_cmd,
-       "show ipv6 ospf6 neighbor A.B.C.D",
-       SHOW_STR
-       IP6_STR
-       OSPF6_STR
-       "Neighbor list\n"
-       "OSPF6 neighbor Router ID in IP address format\n"
-       )
-{
-  u_int32_t router_id;
-  struct ospf6_neighbor *o6n;
-  struct ospf6_interface *o6i;
-  struct ospf6_area *o6a;
-  listnode nodei, nodej, nodek;
-
-  OSPF6_CMD_CHECK_RUNNING ();
-
-  if (argc == 0)
-    vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s",
-             "RouterID", "State", "Duration", "DR", "BDR", "I/F",
-             "State", VTY_NEWLINE);
-  else if (inet_pton (AF_INET, argv[0], &router_id) != 1)
-    {
-      vty_out (vty, "Malformed Router-ID: %s%s", argv[0], VTY_NEWLINE);
-      return CMD_SUCCESS;
-    }
-
-  for (nodei = listhead (ospf6->area_list); nodei; nextnode (nodei))
-    {
-      o6a = getdata (nodei);
-      for (nodej = listhead (o6a->if_list); nodej; nextnode (nodej))
-        {
-          o6i = getdata (nodej);
-          for (nodek = listhead (o6i->neighbor_list); nodek; nextnode (nodek))
-            {
-              o6n = getdata (nodek);
-              if (argc == 0)
-                ospf6_neighbor_show_summary (vty, o6n);
-              else if (o6n->router_id == router_id)
-                ospf6_neighbor_show_detail (vty, o6n);
-            }
-        }
-    }
-  return CMD_SUCCESS;
-}
-
-ALIAS (show_ipv6_ospf6_neighbor_routerid,
+DEFUN (show_ipv6_ospf6_neighbor,
        show_ipv6_ospf6_neighbor_cmd,
        "show ipv6 ospf6 neighbor",
        SHOW_STR
        IP6_STR
        OSPF6_STR
        "Neighbor list\n"
-       )
-
-DEFUN (show_ipv6_ospf6_neighborlist,
-       show_ipv6_ospf6_neighborlist_cmd,
-       "show ipv6 ospf6 (summary-list|request-list|retrans-list|dbdesc-list)",
-       SHOW_STR
-       IP6_STR
-       OSPF6_STR
-       "Link State summary list\n"
-       "Link State request list\n"
-       "Link State retransmission list\n"
-       "Link State Description list (Used to retrans DbDesc)\n"
-       )
+      )
 {
-  struct ospf6_area *o6a;
-  struct ospf6_interface *o6i;
-  struct ospf6_neighbor *o6n;
-  listnode i, j, k, l;
-  struct ospf6_lsa *lsa;
-  struct ospf6_lsdb *lsdb = NULL;
-  char type[16], id[16], adv_router[16];
-  struct ospf6_lsdb_node node;
-  u_int16_t age, cksum, len;
-  u_int32_t seqnum;
+  struct ospf6_neighbor *on;
+  struct ospf6_interface *oi;
+  struct ospf6_area *oa;
+  listnode i, j, k;
+  void (*showfunc) (struct vty *, struct ospf6_neighbor *);
 
   OSPF6_CMD_CHECK_RUNNING ();
-  i = j = k = l = NULL;
+  showfunc = ospf6_neighbor_show;
+
+  if (argc)
+    {
+      if (! strncmp (argv[0], "de", 2))
+        showfunc = ospf6_neighbor_show_detail;
+      else if (! strncmp (argv[0], "dr", 2))
+        showfunc = ospf6_neighbor_show_drchoice;
+    }
+
+  if (showfunc == ospf6_neighbor_show)
+    vty_out (vty, "%-15s %3s %11s %6s/%-12s %11s %s[%s]%s",
+             "Neighbor ID", "Pri", "DeadTime", "State", "IfState", "Duration",
+             "I/F", "State", VTY_NEWLINE);
+  else if (showfunc == ospf6_neighbor_show_drchoice)
+    vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s",
+             "RouterID", "State", "Duration", "DR", "BDR", "I/F",
+             "State", VTY_NEWLINE);
 
   for (i = listhead (ospf6->area_list); i; nextnode (i))
     {
-      o6a = (struct ospf6_area *) getdata (i);
-      for (j = listhead (o6a->if_list); j; nextnode (j))
+      oa = (struct ospf6_area *) getdata (i);
+      for (j = listhead (oa->if_list); j; nextnode (j))
         {
-          o6i = (struct ospf6_interface *) getdata (j);
-          for (k = listhead (o6i->neighbor_list); k; nextnode (k))
+          oi = (struct ospf6_interface *) getdata (j);
+          for (k = listhead (oi->neighbor_list); k; nextnode (k))
             {
-              o6n = (struct ospf6_neighbor *) getdata (k);
-
-              if (strncmp (argv[0], "sum", 3) == 0)
-                lsdb = o6n->summary_list;
-              else if (strncmp (argv[0], "req", 3) == 0)
-                lsdb = o6n->request_list;
-              else if (strncmp (argv[0], "ret", 3) == 0)
-                lsdb = o6n->retrans_list;
-              else if (strncmp (argv[0], "dbd", 3) == 0)
-                lsdb = o6n->dbdesc_list;
-
-              vty_out (vty, "neighbor %s on interface %s: %d%s", o6n->str,
-                       o6i->interface->name, lsdb->count,
-                       VTY_NEWLINE);
-              for (ospf6_lsdb_head (&node, lsdb); ! ospf6_lsdb_is_end (&node);
-                   ospf6_lsdb_next (&node))
-                {
-                  lsa = node.lsa;
-                  ospf6_lsa_age_current (lsa);
-
-                  ospf6_lsa_type_string (lsa->header->type, type,
-                                         sizeof (type));
-                  inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id));
-                  inet_ntop (AF_INET, &lsa->header->adv_router, adv_router,
-                             sizeof (adv_router));
-                  age = ntohs (lsa->header->age);
-                  seqnum = ntohl (lsa->header->seqnum);
-                  cksum = ntohs (lsa->header->checksum);
-                  len = ntohs (lsa->header->length);
-
-                  vty_out (vty, "  %s-LSA ID=%s Adv=%s%s",
-                           type, id, adv_router, VTY_NEWLINE);
-                  vty_out (vty, "  Age: %hu SeqNum: %#x Cksum: %hx Len: %hu%s",
-                           age, seqnum, cksum, len, VTY_NEWLINE);
-                }
+              on = (struct ospf6_neighbor *) getdata (k);
+              (*showfunc) (vty, on);
             }
         }
     }
+  return CMD_SUCCESS;
+}
 
+ALIAS (show_ipv6_ospf6_neighbor,
+       show_ipv6_ospf6_neighbor_detail_cmd,
+       "show ipv6 ospf6 neighbor (detail|drchoice)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Neighbor list\n"
+       "Display details\n"
+       "Display DR choices\n"
+      );
+
+DEFUN (show_ipv6_ospf6_neighbor_one,
+       show_ipv6_ospf6_neighbor_one_cmd,
+       "show ipv6 ospf6 neighbor A.B.C.D",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Neighbor list\n"
+       "Specify Router-ID as IPv4 address notation\n"
+      )
+{
+  struct ospf6_neighbor *on;
+  struct ospf6_interface *oi;
+  struct ospf6_area *oa;
+  listnode i, j, k;
+  void (*showfunc) (struct vty *, struct ospf6_neighbor *);
+  u_int32_t router_id;
+
+  OSPF6_CMD_CHECK_RUNNING ();
+  showfunc = ospf6_neighbor_show_detail;
+
+  if ((inet_pton (AF_INET, argv[0], &router_id)) != 1)
+    {
+      vty_out (vty, "Router-ID is not parsable: %s%s", argv[0],
+               VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  for (i = listhead (ospf6->area_list); i; nextnode (i))
+    {
+      oa = (struct ospf6_area *) getdata (i);
+      for (j = listhead (oa->if_list); j; nextnode (j))
+        {
+          oi = (struct ospf6_interface *) getdata (j);
+          for (k = listhead (oi->neighbor_list); k; nextnode (k))
+            {
+              on = (struct ospf6_neighbor *) getdata (k);
+              if (on->router_id == router_id)
+                (*showfunc) (vty, on);
+            }
+        }
+    }
   return CMD_SUCCESS;
 }
 
@@ -591,12 +836,104 @@
 ospf6_neighbor_init ()
 {
   install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_cmd);
-  install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_routerid_cmd);
-  install_element (VIEW_NODE, &show_ipv6_ospf6_neighborlist_cmd);
-
+  install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_detail_cmd);
   install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_cmd);
-  install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_routerid_cmd);
-  install_element (ENABLE_NODE, &show_ipv6_ospf6_neighborlist_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_detail_cmd);
 }
 
+DEFUN (debug_ospf6_neighbor,
+       debug_ospf6_neighbor_cmd,
+       "debug ospf6 neighbor",
+       DEBUG_STR
+       OSPF6_STR
+       "Debug OSPFv3 Neighbor\n"
+      )
+{
+  unsigned char level = 0;
+  if (argc)
+    {
+      if (! strncmp (argv[0], "s", 1))
+        level = OSPF6_DEBUG_NEIGHBOR_STATE;
+      if (! strncmp (argv[0], "e", 1))
+        level = OSPF6_DEBUG_NEIGHBOR_EVENT;
+    }
+  else
+    level = OSPF6_DEBUG_NEIGHBOR_STATE | OSPF6_DEBUG_NEIGHBOR_EVENT;
+
+  OSPF6_DEBUG_NEIGHBOR_ON (level);
+  return CMD_SUCCESS;
+}
+
+ALIAS (debug_ospf6_neighbor,
+       debug_ospf6_neighbor_detail_cmd,
+       "debug ospf6 neighbor (state|event)",
+       DEBUG_STR
+       OSPF6_STR
+       "Debug OSPFv3 Neighbor\n"
+       "Debug OSPFv3 Neighbor State Change\n"
+       "Debug OSPFv3 Neighbor Event\n"
+      );
+
+DEFUN (no_debug_ospf6_neighbor,
+       no_debug_ospf6_neighbor_cmd,
+       "no debug ospf6 neighbor",
+       NO_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Debug OSPFv3 Neighbor\n"
+      )
+{
+  unsigned char level = 0;
+  if (argc)
+    {
+      if (! strncmp (argv[0], "s", 1))
+        level = OSPF6_DEBUG_NEIGHBOR_STATE;
+      if (! strncmp (argv[0], "e", 1))
+        level = OSPF6_DEBUG_NEIGHBOR_EVENT;
+    }
+  else
+    level = OSPF6_DEBUG_NEIGHBOR_STATE | OSPF6_DEBUG_NEIGHBOR_EVENT;
+
+  OSPF6_DEBUG_NEIGHBOR_OFF (level);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_ospf6_neighbor,
+       no_debug_ospf6_neighbor_detail_cmd,
+       "no debug ospf6 neighbor (state|event)",
+       NO_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Debug OSPFv3 Neighbor\n"
+       "Debug OSPFv3 Neighbor State Change\n"
+       "Debug OSPFv3 Neighbor Event\n"
+      );
+
+int
+config_write_ospf6_debug_neighbor (struct vty *vty)
+{
+  if (IS_OSPF6_DEBUG_NEIGHBOR (STATE) &&
+      IS_OSPF6_DEBUG_NEIGHBOR (EVENT))
+    vty_out (vty, "debug ospf6 neighbor%s", VTY_NEWLINE);
+  else if (IS_OSPF6_DEBUG_NEIGHBOR (STATE))
+    vty_out (vty, "debug ospf6 neighbor state%s", VTY_NEWLINE);
+  else if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT))
+    vty_out (vty, "debug ospf6 neighbor event%s", VTY_NEWLINE);
+  return 0;
+}
+
+void
+install_element_ospf6_debug_neighbor ()
+{
+  install_element (ENABLE_NODE, &debug_ospf6_neighbor_cmd);
+  install_element (ENABLE_NODE, &debug_ospf6_neighbor_detail_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf6_neighbor_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf6_neighbor_detail_cmd);
+  install_element (CONFIG_NODE, &debug_ospf6_neighbor_cmd);
+  install_element (CONFIG_NODE, &debug_ospf6_neighbor_detail_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf6_neighbor_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf6_neighbor_detail_cmd);
+}
+
+
 
diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h
index c3821c6..441ab81 100644
--- a/ospf6d/ospf6_neighbor.h
+++ b/ospf6d/ospf6_neighbor.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -22,140 +22,117 @@
 #ifndef OSPF6_NEIGHBOR_H
 #define OSPF6_NEIGHBOR_H
 
+/* Debug option */
+extern unsigned char conf_debug_ospf6_neighbor;
+#define OSPF6_DEBUG_NEIGHBOR_STATE   0x01
+#define OSPF6_DEBUG_NEIGHBOR_EVENT   0x02
+#define OSPF6_DEBUG_NEIGHBOR_ON(level) \
+  (conf_debug_ospf6_neighbor |= (level))
+#define OSPF6_DEBUG_NEIGHBOR_OFF(level) \
+  (conf_debug_ospf6_neighbor &= ~(level))
+#define IS_OSPF6_DEBUG_NEIGHBOR(level) \
+  (conf_debug_ospf6_neighbor & OSPF6_DEBUG_NEIGHBOR_ ## level)
+
 /* Neighbor structure */
 struct ospf6_neighbor
 {
   /* Neighbor Router ID String */
-  char str[32];
+  char name[32];
 
   /* OSPFv3 Interface this neighbor belongs to */
-  struct ospf6_interface *ospf6_interface;
+  struct ospf6_interface *ospf6_if;
 
   /* Neighbor state */
   u_char state;
+
+  /* timestamp of last changing state */
   struct timeval last_changed;
 
   /* Neighbor Router ID */
   u_int32_t router_id;
 
+  /* Neighbor Interface ID */
+  u_int32_t ifindex;
+
   /* Router Priority of this neighbor */
   u_char priority;
 
-  u_int32_t ifid;
-  u_int32_t dr;
-  u_int32_t bdr;
-  u_int32_t prevdr;
-  u_int32_t prevbdr;
+  u_int32_t drouter;
+  u_int32_t bdrouter;
+  u_int32_t prev_drouter;
+  u_int32_t prev_bdrouter;
 
-  /* Link-LSA's options field */
+  /* Options field (Capability) */
   char options[3];
 
   /* IPaddr of I/F on our side link */
-  struct in6_addr hisaddr;
-
-  /* new */
-  struct ospf6_lsdb *summary_list;
-  struct ospf6_lsdb *request_list;
-  struct ospf6_lsdb *retrans_list;
+  struct in6_addr linklocal_addr;
 
   /* For Database Exchange */
   u_char               dbdesc_bits;
   u_int32_t            dbdesc_seqnum;
-  struct ospf6_dbdesc *dbdesc_previous;
+  /* Last received Database Description packet */
+  struct ospf6_dbdesc  dbdesc_last;
 
-  /* last received DD , including OSPF capability of this neighbor */
-  struct ospf6_dbdesc last_dd;
+  /* LS-list */
+  struct ospf6_lsdb *summary_list;
+  struct ospf6_lsdb *request_list;
+  struct ospf6_lsdb *retrans_list;
 
-  /* LSAs to retransmit to this neighbor */
-  list dbdesc_lsa;
+  /* LSA list for message transmission */
+  struct ospf6_lsdb *dbdesc_list;
+  struct ospf6_lsdb *lsreq_list;
+  struct ospf6_lsdb *lsupdate_list;
+  struct ospf6_lsdb *lsack_list;
 
-  /* placeholder for DbDesc */
-  struct iovec dbdesc_last_send[1024];
-
+  /* Inactivity timer */
   struct thread *inactivity_timer;
 
-  /* DbDesc */
+  /* Thread for sending message */
   struct thread *thread_send_dbdesc;
-  struct thread *thread_rxmt_dbdesc;
-  list dbdesclist;
-  struct ospf6_lsdb *dbdesc_list;
-
-  /* LSReq */
   struct thread *thread_send_lsreq;
-  struct thread *thread_rxmt_lsreq;
-
-  /* LSUpdate */
-  struct thread *send_update;
-  struct thread *thread_send_update;
-  struct thread *thread_rxmt_update;
-
-  /* statistics */
-  u_int message_send[OSPF6_MESSAGE_TYPE_MAX];
-  u_int message_receive[OSPF6_MESSAGE_TYPE_MAX];
-  u_int lsa_send[OSPF6_MESSAGE_TYPE_MAX];
-  u_int lsa_receive[OSPF6_MESSAGE_TYPE_MAX];
-
-  u_int ospf6_stat_state_changed;
-  u_int ospf6_stat_seqnum_mismatch;
-  u_int ospf6_stat_bad_lsreq;
-  u_int ospf6_stat_oneway_received;
-  u_int ospf6_stat_inactivity_timer;
-  u_int ospf6_stat_dr_election;
-  u_int ospf6_stat_retrans_dbdesc;
-  u_int ospf6_stat_retrans_lsreq;
-  u_int ospf6_stat_retrans_lsupdate;
-  u_int ospf6_stat_received_lsa;
-  u_int ospf6_stat_received_lsupdate;
-
-  struct timeval tv_last_hello_received;
+  struct thread *thread_send_lsupdate;
+  struct thread *thread_send_lsack;
 };
 
-extern char *ospf6_neighbor_state_string[];
+/* Neighbor state */
+#define OSPF6_NEIGHBOR_DOWN     1
+#define OSPF6_NEIGHBOR_ATTEMPT  2
+#define OSPF6_NEIGHBOR_INIT     3
+#define OSPF6_NEIGHBOR_TWOWAY   4
+#define OSPF6_NEIGHBOR_EXSTART  5
+#define OSPF6_NEIGHBOR_EXCHANGE 6
+#define OSPF6_NEIGHBOR_LOADING  7
+#define OSPF6_NEIGHBOR_FULL     8
+
+extern char *ospf6_neighbor_state_str[];
 
 
 /* Function Prototypes */
-int
-ospf6_neighbor_last_dbdesc_release (struct thread *);
+int ospf6_neighbor_cmp (void *va, void *vb);
+void ospf6_neighbor_dbex_init (struct ospf6_neighbor *on);
 
-void
-ospf6_neighbor_lslist_clear (struct ospf6_neighbor *);
+struct ospf6_neighbor *ospf6_neighbor_lookup (u_int32_t,
+                                              struct ospf6_interface *);
+struct ospf6_neighbor *ospf6_neighbor_create (u_int32_t,
+                                              struct ospf6_interface *);
+void ospf6_neighbor_delete (struct ospf6_neighbor *);
 
-void
-ospf6_neighbor_summary_add (struct ospf6_lsa *, struct ospf6_neighbor *);
-void
-ospf6_neighbor_summary_remove (struct ospf6_lsa *, struct ospf6_neighbor *);
-
-void
-ospf6_neighbor_request_add (struct ospf6_lsa *, struct ospf6_neighbor *);
-void
-ospf6_neighbor_request_remove (struct ospf6_lsa *, struct ospf6_neighbor *);
-
-void
-ospf6_neighbor_retrans_add (struct ospf6_lsa *, struct ospf6_neighbor *);
-void
-ospf6_neighbor_retrans_remove (struct ospf6_lsa *, struct ospf6_neighbor *);
-
-void
-ospf6_neighbor_dbdesc_add (struct ospf6_lsa *lsa,
-                           struct ospf6_neighbor *nei);
-void
-ospf6_neighbor_dbdesc_remove (struct ospf6_lsa *lsa,
-                              struct ospf6_neighbor *nei);
-
-void
-ospf6_neighbor_dbex_init (struct ospf6_neighbor *nei);
-
-void
-ospf6_neighbor_thread_cancel_all (struct ospf6_neighbor *);
-
-struct ospf6_neighbor *
-ospf6_neighbor_create (u_int32_t, struct ospf6_interface *);
-void
-ospf6_neighbor_delete (struct ospf6_neighbor *);
-struct ospf6_neighbor *
-ospf6_neighbor_lookup (u_int32_t, struct ospf6_interface *);
+/* Neighbor event */
+int hello_received (struct thread *);
+int twoway_received (struct thread *);
+int negotiation_done (struct thread *);
+int exchange_done (struct thread *);
+int loading_done (struct thread *);
+int adj_ok (struct thread *);
+int seqnumber_mismatch (struct thread *);
+int bad_lsreq (struct thread *);
+int oneway_received (struct thread *);
+int inactivity_timer (struct thread *);
 
 void ospf6_neighbor_init ();
+int config_write_ospf6_debug_neighbor (struct vty *vty);
+void install_element_ospf6_debug_neighbor ();
 
 #endif /* OSPF6_NEIGHBOR_H */
 
diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c
index ece3413..b4f37f6 100644
--- a/ospf6d/ospf6_network.c
+++ b/ospf6d/ospf6_network.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -20,288 +20,20 @@
  */
 
 #include <zebra.h>
-#include "memory.h"
+
 #include "log.h"
+#include "memory.h"
 #include "sockunion.h"
 #include "privs.h"
 
-#include "ospf6d.h"
 #include "ospf6_proto.h"
+#include "ospf6_network.h"
 
-extern int errno;
-extern struct sockaddr_in6 allspfrouters6;
-extern struct sockaddr_in6 alldrouters6;
-extern int ospf6_sock;
-extern struct thread_master *master;
 extern struct zebra_privs_t ospf6d_privs;
 
-/* iovec functions */
-void
-iov_clear (struct iovec *iov, size_t iovlen)
-{
-  int i;
-  for (i = 0; i < iovlen; i++)
-    {
-      iov[i].iov_base = NULL;
-      iov[i].iov_len = 0;
-    }
-}
-
-int
-iov_count (struct iovec *iov)
-{
-  int i;
-  for (i = 0; iov[i].iov_base; i++)
-    ;
-  return i;
-}
-
-int
-iov_totallen (struct iovec *iov)
-{
-  int i;
-  int totallen = 0;
-  for (i = 0; iov[i].iov_base; i++)
-    totallen += iov[i].iov_len;
-  return totallen;
-}
-
-void *
-iov_prepend (int mtype, struct iovec *iov, size_t len)
-{
-  int i, iovlen;
-  void *base;
-
-  base = (void *) XMALLOC (mtype, len);
-  if (!base)
-    {
-      zlog_warn ("Network: iov_prepend failed");
-      return NULL;
-    }
-  memset (base, 0, len);
-
-  iovlen = iov_count (iov);
-  for (i = iovlen; i; i--)
-    {
-      iov[i].iov_base = iov[i - 1].iov_base;
-      iov[i].iov_len = iov[i - 1].iov_len;
-    }
-  iov[0].iov_base = (char *)base;
-  iov[0].iov_len = len;
-
-  return base;
-}
-
-void *
-iov_append (int mtype, struct iovec *iov, size_t len)
-{
-  int i;
-  void *base;
-
-  base = (void *)XMALLOC (mtype, len);
-  if (!base)
-    {
-      zlog_warn ("Network: iov_append failed");
-      return NULL;
-    }
-  memset (base, 0, len);
-
-  /* proceed to the end */
-  i = iov_count (iov);
-
-  iov[i].iov_base = (char *)base;
-  iov[i].iov_len = len;
-
-  return base;
-}
-
-void *
-iov_attach_last (struct iovec *iov, void *base, size_t len)
-{
-  int i;
-  i = iov_count (iov);
-  iov[i].iov_base = (char *)base;
-  iov[i].iov_len = len;
-  return base;
-}
-
-void *
-iov_detach_first (struct iovec *iov)
-{
-  int i, iovlen;
-  void *base;
-  size_t len;
-
-  base = iov[0].iov_base;
-  len = iov[0].iov_len;
-  iovlen = iov_count (iov);
-  for (i = 0; i < iovlen; i++)
-    {
-      iov[i].iov_base = iov[i + 1].iov_base;
-      iov[i].iov_len = iov[i + 1].iov_len;
-    }
-  return base;
-}
-
-int
-iov_free (int mtype, struct iovec *iov, u_int begin, u_int end)
-{
-  int i;
-
-  for (i = begin; i < end; i++)
-    {
-      XFREE (mtype, iov[i].iov_base);
-      iov[i].iov_base = NULL;
-      iov[i].iov_len = 0;
-    }
-
-  return 0;
-}
-
-void
-iov_trim_head (int mtype, struct iovec *iov)
-{
-  void *base;
-
-  base = iov_detach_first (iov);
-  XFREE (mtype, base);
-  return;
-}
-
-void
-iov_free_all (int mtype, struct iovec *iov)
-{
-  int i, end = iov_count (iov);
-  for (i = 0; i < end; i++)
-    {
-      XFREE (mtype, iov[i].iov_base);
-      iov[i].iov_base = NULL;
-      iov[i].iov_len = 0;
-    }
-}
-
-void
-iov_copy_all (struct iovec *dst, struct iovec *src, size_t size)
-{
-  int i;
-  for (i = 0; i < size; i++)
-    {
-      dst[i].iov_base = src[i].iov_base;
-      dst[i].iov_len = src[i].iov_len;
-    }
-}
-
-
-/* Make ospf6d's server socket. */
-int
-ospf6_serv_sock ()
-{
-
-  if (ospf6d_privs.change (ZPRIVS_RAISE))
-      zlog_err ("ospf6_serv_sock: could not raise privs");
-      
-  ospf6_sock = socket (AF_INET6, SOCK_RAW, IPPROTO_OSPFIGP);
-  if (ospf6_sock < 0)
-    {
-      zlog_warn ("Network: can't create OSPF6 socket.");
-      return -1;
-    }
-  sockopt_reuseaddr (ospf6_sock);
-
-  if (ospf6d_privs.change (ZPRIVS_LOWER))
-      zlog_err ("ospf_sock_init: could not lower privs");
-  
-  /* setup global sockaddr_in6, allspf6 & alldr6 for later use */
-  allspfrouters6.sin6_family = AF_INET6;
-  alldrouters6.sin6_family = AF_INET6;
-#ifdef SIN6_LEN
-  allspfrouters6.sin6_len = sizeof (struct sockaddr_in6);
-  alldrouters6.sin6_len = sizeof (struct sockaddr_in6);
-#endif /* SIN6_LEN */
-  inet_pton (AF_INET6, ALLSPFROUTERS6, &allspfrouters6.sin6_addr);
-  inet_pton (AF_INET6, ALLDROUTERS6, &alldrouters6.sin6_addr);
-
-  return 0;
-}
-
-/* returns 0 if succeed, else returns -1 */
-int
-ospf6_join_allspfrouters (u_int ifindex)
-{
-  struct ipv6_mreq mreq6;
-  int retval;
-
-  assert (ifindex);
-  mreq6.ipv6mr_interface = ifindex;
-  memcpy (&mreq6.ipv6mr_multiaddr, &allspfrouters6.sin6_addr,
-          sizeof (struct in6_addr));
-
-  retval = setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
-                       &mreq6, sizeof (mreq6));
-
-  if (retval < 0)
-    zlog_err ("Network: Join AllSPFRouters on ifindex %d failed: %s",
-               ifindex, strerror (errno));
-#if 0
-  else
-    zlog_info ("Network: Join AllSPFRouters on ifindex %d", ifindex);
-#endif
-
-  return retval;
-}
-
-void
-ospf6_leave_allspfrouters (u_int ifindex)
-{
-  struct ipv6_mreq mreq6;
-
-  assert (ifindex);
-  mreq6.ipv6mr_interface = ifindex;
-  memcpy (&mreq6.ipv6mr_multiaddr, &allspfrouters6.sin6_addr,
-          sizeof (struct in6_addr));
-
-  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
-                  &mreq6, sizeof (mreq6)) < 0)
-    zlog_warn ("Network: Leave AllSPFRouters on ifindex %d Failed: %s",
-               ifindex, strerror (errno));
-  else
-    zlog_info ("Network: Leave AllSPFRouters on ifindex %d", ifindex);
-}
-
-void
-ospf6_join_alldrouters (u_int ifindex)
-{
-  struct ipv6_mreq mreq6;
-
-  assert (ifindex);
-  mreq6.ipv6mr_interface = ifindex;
-  memcpy (&mreq6.ipv6mr_multiaddr, &alldrouters6.sin6_addr,
-          sizeof (struct in6_addr));
-
-  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
-                  &mreq6, sizeof (mreq6)) < 0)
-    zlog_warn ("Network: Join AllDRouters on ifindex %d Failed: %s",
-               ifindex, strerror (errno));
-  else
-    zlog_info ("Network: Join AllDRouters on ifindex %d", ifindex);
-}
-
-void
-ospf6_leave_alldrouters (u_int ifindex)
-{
-  struct ipv6_mreq mreq6;
-
-  assert (ifindex);
-  mreq6.ipv6mr_interface = ifindex;
-  memcpy (&mreq6.ipv6mr_multiaddr, &alldrouters6.sin6_addr,
-          sizeof (struct in6_addr));
-
-  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
-                  &mreq6, sizeof (mreq6)) < 0)
-    zlog_warn ("Network: Leave AllDRouters on ifindex %d Failed", ifindex);
-  else
-    zlog_info ("Network: Leave AllDRouters on ifindex %d", ifindex);
-}
+int  ospf6_sock;
+struct in6_addr allspfrouters6;
+struct in6_addr alldrouters6;
 
 /* setsockopt ReUseAddr to on */
 void
@@ -343,7 +75,7 @@
 ospf6_set_checksum ()
 {
   int offset = 12;
-#if !defined(DISABLE_IPV6_CHECKSUM)
+#ifndef DISABLE_IPV6_CHECKSUM
   if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_CHECKSUM,
                   &offset, sizeof (offset)) < 0)
     zlog_warn ("Network: set IPV6_CHECKSUM failed: %s", strerror (errno));
@@ -352,7 +84,143 @@
 #endif /* DISABLE_IPV6_CHECKSUM */
 }
 
+/* Make ospf6d's server socket. */
+int
+ospf6_serv_sock ()
+{
+  if (ospf6d_privs.change (ZPRIVS_RAISE))
+    zlog_err ("ospf6_serv_sock: could not raise privs");
+
+  ospf6_sock = socket (AF_INET6, SOCK_RAW, IPPROTO_OSPFIGP);
+  if (ospf6_sock < 0)
+    {
+      zlog_warn ("Network: can't create OSPF6 socket.");
+      if (ospf6d_privs.change (ZPRIVS_LOWER))
+        zlog_err ("ospf_sock_init: could not lower privs");
+      return -1;
+    }
+  if (ospf6d_privs.change (ZPRIVS_LOWER))
+      zlog_err ("ospf_sock_init: could not lower privs");
+
+  /* set socket options */
+#if 1
+  sockopt_reuseaddr (ospf6_sock);
+#else
+  ospf6_set_reuseaddr ();
+#endif /*1*/
+  ospf6_reset_mcastloop ();
+  ospf6_set_pktinfo ();
+  ospf6_set_checksum ();
+
+  /* setup global in6_addr, allspf6 and alldr6 for later use */
+  inet_pton (AF_INET6, ALLSPFROUTERS6, &allspfrouters6);
+  inet_pton (AF_INET6, ALLDROUTERS6, &alldrouters6);
+
+  return 0;
+}
+
 void
+ospf6_join_allspfrouters (u_int ifindex)
+{
+  struct ipv6_mreq mreq6;
+  int retval;
+
+  assert (ifindex);
+  mreq6.ipv6mr_interface = ifindex;
+  memcpy (&mreq6.ipv6mr_multiaddr, &allspfrouters6,
+          sizeof (struct in6_addr));
+
+  retval = setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+                       &mreq6, sizeof (mreq6));
+
+  if (retval < 0)
+    zlog_err ("Network: Join AllSPFRouters on ifindex %d failed: %s",
+              ifindex, strerror (errno));
+#if 0
+  else
+    zlog_info ("Network: Join AllSPFRouters on ifindex %d", ifindex);
+#endif
+}
+
+void
+ospf6_leave_allspfrouters (u_int ifindex)
+{
+  struct ipv6_mreq mreq6;
+
+  assert (ifindex);
+  mreq6.ipv6mr_interface = ifindex;
+  memcpy (&mreq6.ipv6mr_multiaddr, &allspfrouters6,
+          sizeof (struct in6_addr));
+
+  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
+                  &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
+ospf6_join_alldrouters (u_int ifindex)
+{
+  struct ipv6_mreq mreq6;
+
+  assert (ifindex);
+  mreq6.ipv6mr_interface = ifindex;
+  memcpy (&mreq6.ipv6mr_multiaddr, &alldrouters6,
+          sizeof (struct in6_addr));
+
+  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+                  &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
+ospf6_leave_alldrouters (u_int ifindex)
+{
+  struct ipv6_mreq mreq6;
+
+  assert (ifindex);
+  mreq6.ipv6mr_interface = ifindex;
+  memcpy (&mreq6.ipv6mr_multiaddr, &alldrouters6,
+          sizeof (struct in6_addr));
+
+  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
+}
+
+int
+iov_count (struct iovec *iov)
+{
+  int i;
+  for (i = 0; iov[i].iov_base; i++)
+    ;
+  return i;
+}
+
+int
+iov_totallen (struct iovec *iov)
+{
+  int i;
+  int totallen = 0;
+  for (i = 0; iov[i].iov_base; i++)
+    totallen += iov[i].iov_len;
+  return totallen;
+}
+
+int
 ospf6_sendmsg (struct in6_addr *src, struct in6_addr *dst,
                unsigned int *ifindex, struct iovec *message)
 {
@@ -403,11 +271,13 @@
 
   retval = sendmsg (ospf6_sock, &smsghdr, 0);
   if (retval != iov_totallen (message))
-    zlog_warn ("Network: sendmsg (ifindex: %d) failed: %s(%d)",
+    zlog_warn ("sendmsg failed: ifindex: %d: %s (%d)",
                *ifindex, strerror (errno), errno);
+
+  return retval;
 }
 
-void
+int
 ospf6_recvmsg (struct in6_addr *src, struct in6_addr *dst,
                unsigned int *ifindex, struct iovec *message)
 {
@@ -438,14 +308,9 @@
 
   retval = recvmsg (ospf6_sock, &rmsghdr, 0);
   if (retval < 0)
-    {
-      zlog_warn ("Network: recvmsg failed: %s", strerror (errno));
-    }
+    zlog_warn ("recvmsg failed: %s", strerror (errno));
   else if (retval == iov_totallen (message))
-    {
-      zlog_warn ("Network: possibly buffer shortage: %d received, buffer size: %d",
-                  retval, iov_totallen (message));
-    }
+    zlog_warn ("recvmsg read full buffer size: %d", retval);
 
   /* source address */
   assert (src);
@@ -456,49 +321,8 @@
     *ifindex = pktinfo->ipi6_ifindex;
   if (dst)
     memcpy (dst, &pktinfo->ipi6_addr, sizeof (struct in6_addr));
+
+  return retval;
 }
 
-void
-ospf6_recvmsg_peek (struct in6_addr *src, struct in6_addr *dst,
-                    unsigned int *ifindex, struct iovec *message)
-{
-  int retval;
-  struct msghdr rmsghdr;
-  struct cmsghdr *rcmsgp;
-  u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))];
-  struct in6_pktinfo *pktinfo;
-  struct sockaddr_in6 src_sin6;
-
-  rcmsgp = (struct cmsghdr *)cmsgbuf;
-  pktinfo = (struct in6_pktinfo *)(CMSG_DATA(rcmsgp));
-  memset (&src_sin6, 0, sizeof (struct sockaddr_in6));
-
-  /* receive control msg */
-  rcmsgp->cmsg_level = IPPROTO_IPV6;
-  rcmsgp->cmsg_type = IPV6_PKTINFO;
-  rcmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo));
-  /* rcmsgp = CMSG_NXTHDR (&rmsghdr, rcmsgp); */
-
-  /* receive msg hdr */
-  rmsghdr.msg_iov = message;
-  rmsghdr.msg_iovlen = iov_count (message);
-  rmsghdr.msg_name = (caddr_t) &src_sin6;
-  rmsghdr.msg_namelen = sizeof (struct sockaddr_in6);
-  rmsghdr.msg_control = (caddr_t) cmsgbuf;
-  rmsghdr.msg_controllen = sizeof (cmsgbuf);
-
-  retval = recvmsg (ospf6_sock, &rmsghdr, MSG_PEEK);
-  if (retval != iov_totallen (message))
-    zlog_warn ("Network: recvmsg failed: %s", strerror (errno));
-
-  /* source address */
-  assert (src);
-  memcpy (src, &src_sin6.sin6_addr, sizeof (struct in6_addr));
-
-  /* destination address */
-  if (ifindex)
-    *ifindex = pktinfo->ipi6_ifindex;
-  if (dst)
-    memcpy (dst, &pktinfo->ipi6_addr, sizeof (struct in6_addr));
-}
 
diff --git a/ospf6d/ospf6_network.h b/ospf6d/ospf6_network.h
index 934cce5..9a4d795 100644
--- a/ospf6d/ospf6_network.h
+++ b/ospf6d/ospf6_network.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -24,35 +24,27 @@
 
 
 
-/* Function Prototypes */
-void iov_clear (struct iovec *, size_t);
-int iov_count (struct iovec *);
-int iov_totallen (struct iovec *);
-void *iov_prepend (int, struct iovec *, size_t);
-void *iov_append (int, struct iovec *, size_t);
-void *iov_attach_last (struct iovec *, void *, size_t);
-void *iov_detach_first (struct iovec *);
-int iov_free (int, struct iovec *, u_int, u_int);
-void iov_trim_head (int, struct iovec *);
-void iov_free_all (int, struct iovec *);
-void iov_copy_all (struct iovec *, struct iovec *, size_t);
+extern int ospf6_sock;
+extern struct in6_addr allspfrouters6;
+extern struct in6_addr alldrouters6;
 
-int ospf6_serv_sock ();
-int ospf6_join_allspfrouters (u_int);
-void ospf6_leave_allspfrouters (u_int);
-void ospf6_join_alldrouters (u_int);
-void ospf6_leave_alldrouters (u_int);
+/* Function Prototypes */
 void ospf6_set_reuseaddr ();
 void ospf6_reset_mcastloop ();
 void ospf6_set_pktinfo ();
 void ospf6_set_checksum ();
 
-void ospf6_sendmsg (struct in6_addr *, struct in6_addr *,
-                    unsigned int *, struct iovec *);
-void ospf6_recvmsg (struct in6_addr *, struct in6_addr *,
-                    unsigned int *, struct iovec *);
-void ospf6_recvmsg_peek (struct in6_addr *, struct in6_addr *,
-                         unsigned int *, struct iovec *);
+int ospf6_serv_sock ();
+
+void ospf6_join_allspfrouters (u_int);
+void ospf6_leave_allspfrouters (u_int);
+void ospf6_join_alldrouters (u_int);
+void ospf6_leave_alldrouters (u_int);
+
+int ospf6_sendmsg (struct in6_addr *, struct in6_addr *,
+                   unsigned int *, struct iovec *);
+int ospf6_recvmsg (struct in6_addr *, struct in6_addr *,
+                   unsigned int *, struct iovec *);
 
 #endif /* OSPF6_NETWORK_H */
 
diff --git a/ospf6d/ospf6_nsm.c b/ospf6d/ospf6_nsm.c
deleted file mode 100644
index aa08d40..0000000
--- a/ospf6d/ospf6_nsm.c
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * Copyright (C) 1999 Yasuhiro Ohara
- *
- * 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 "ospf6d.h"
-
-static int
-nbs_full_change (struct ospf6_interface *ospf6_interface)
-{
-  CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, ospf6_interface);
-  return 0;
-}
-
-static int
-nbs_change (state_t nbs_next, char *reason, struct ospf6_neighbor *o6n)
-{
-  state_t nbs_previous;
-
-  nbs_previous = o6n->state;
-  o6n->state = nbs_next;
-
-  if (nbs_previous == nbs_next)
-    return 0;
-
-  /* statistics */
-  o6n->ospf6_stat_state_changed++;
-  gettimeofday (&o6n->last_changed, NULL);
-
-  /* log */
-  if (IS_OSPF6_DUMP_NEIGHBOR)
-    {
-      if (reason)
-        zlog_info ("Neighbor status change %s: [%s]->[%s](%s)",
-                   o6n->str,
-                   ospf6_neighbor_state_string[nbs_previous],
-                   ospf6_neighbor_state_string[nbs_next],
-                   reason);
-      else
-        zlog_info ("Neighbor status change %s: [%s]->[%s]",
-                   o6n->str,
-                   ospf6_neighbor_state_string[nbs_previous],
-                   ospf6_neighbor_state_string[nbs_next]);
-    }
-
-  if (nbs_previous == NBS_FULL || nbs_next == NBS_FULL)
-    nbs_full_change (o6n->ospf6_interface);
-
-  /* check for LSAs that already reached MaxAge */
-  if ((nbs_previous == NBS_EXCHANGE || nbs_previous == NBS_LOADING) &&
-      (nbs_next != NBS_EXCHANGE && nbs_next != NBS_LOADING))
-    {
-      ospf6_maxage_remover ();
-    }
-
-  CALL_CHANGE_HOOK (&neighbor_hook, o6n);
-
-  return 0;
-}
-
-/* RFC2328 section 10.4 */
-int
-need_adjacency (struct ospf6_neighbor *o6n)
-{
-
-  if (o6n->ospf6_interface->state == IFS_PTOP)
-    return 1;
-  if (o6n->ospf6_interface->state == IFS_DR)
-    return 1;
-  if (o6n->ospf6_interface->state == IFS_BDR)
-    return 1;
-  if (o6n->router_id == o6n->ospf6_interface->dr)
-    return 1;
-  if (o6n->router_id == o6n->ospf6_interface->bdr)
-    return 1;
-
-  return 0;
-}
-
-int
-hello_received (struct thread *thread)
-{
-  struct ospf6_neighbor *o6n;
-
-  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
-  assert (o6n);
-
-  if (IS_OSPF6_DUMP_NEIGHBOR)
-    zlog_info ("Neighbor Event %s: *HelloReceived*", o6n->str);
-
-  if (o6n->inactivity_timer)
-    thread_cancel (o6n->inactivity_timer);
-
-  o6n->inactivity_timer = thread_add_timer (master, inactivity_timer, o6n,
-                                            o6n->ospf6_interface->dead_interval);
-  if (o6n->state <= NBS_DOWN)
-    nbs_change (NBS_INIT, "HelloReceived", o6n);
-  return 0;
-}
-
-int
-twoway_received (struct thread *thread)
-{
-  struct ospf6_neighbor *o6n;
-
-  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
-  assert (o6n);
-
-  if (o6n->state > NBS_INIT)
-    return 0;
-
-  if (IS_OSPF6_DUMP_NEIGHBOR)
-    zlog_info ("Neighbor Event %s: *2Way-Received*", o6n->str);
-
-  thread_add_event (master, neighbor_change, o6n->ospf6_interface, 0);
-
-  if (!need_adjacency (o6n))
-    {
-      nbs_change (NBS_TWOWAY, "No Need Adjacency", o6n);
-      return 0;
-    }
-  else
-    nbs_change (NBS_EXSTART, "Need Adjacency", o6n);
-
-  DD_MSBIT_SET (o6n->dbdesc_bits);
-  DD_MBIT_SET (o6n->dbdesc_bits);
-  DD_IBIT_SET (o6n->dbdesc_bits);
-
-  if (o6n->thread_send_dbdesc)
-    thread_cancel (o6n->thread_send_dbdesc);
-  o6n->thread_send_dbdesc =
-    thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
-  if (o6n->thread_rxmt_dbdesc)
-    thread_cancel (o6n->thread_rxmt_dbdesc);
-  o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
-
-  return 0;
-}
-
-int
-negotiation_done (struct thread *thread)
-{
-  struct ospf6_neighbor *o6n;
-
-  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
-  assert (o6n);
-
-  if (o6n->state != NBS_EXSTART)
-    return 0;
-
-  if (IS_OSPF6_DUMP_NEIGHBOR)
-    zlog_info ("Neighbor Event %s: *NegotiationDone*", o6n->str);
-
-  nbs_change (NBS_EXCHANGE, "NegotiationDone", o6n);
-  DD_IBIT_CLEAR (o6n->dbdesc_bits);
-
-  return 0;
-}
-
-int
-exchange_done (struct thread *thread)
-{
-  struct ospf6_neighbor *o6n;
-
-  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
-  assert (o6n);
-
-  if (o6n->state != NBS_EXCHANGE)
-    return 0;
-
-  if (o6n->thread_rxmt_dbdesc)
-    thread_cancel (o6n->thread_rxmt_dbdesc);
-  o6n->thread_rxmt_dbdesc = (struct thread *) NULL;
-
-  if (IS_OSPF6_DUMP_NEIGHBOR)
-    zlog_info ("Neighbor Event %s: *ExchangeDone*", o6n->str);
-
-  ospf6_lsdb_remove_all (o6n->dbdesc_list);
-
-  thread_add_timer (master, ospf6_neighbor_last_dbdesc_release, o6n,
-                    o6n->ospf6_interface->dead_interval);
-
-  if (o6n->request_list->count == 0)
-    nbs_change (NBS_FULL, "Requestlist Empty", o6n);
-  else
-    {
-      thread_add_event (master, ospf6_send_lsreq, o6n, 0);
-      nbs_change (NBS_LOADING, "Requestlist Not Empty", o6n);
-    }
-  return 0;
-}
-
-int
-loading_done (struct thread *thread)
-{
-  struct ospf6_neighbor *o6n;
-
-  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
-  assert (o6n);
-
-  if (o6n->state != NBS_LOADING)
-    return 0;
-
-  if (IS_OSPF6_DUMP_NEIGHBOR)
-    zlog_info ("Neighbor Event %s: *LoadingDone*", o6n->str);
-
-  assert (o6n->request_list->count == 0);
-
-  nbs_change (NBS_FULL, "LoadingDone", o6n);
-
-  return 0;
-}
-
-int
-adj_ok (struct thread *thread)
-{
-  struct ospf6_neighbor *o6n;
-
-  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
-  assert (o6n);
-
-  if (IS_OSPF6_DUMP_NEIGHBOR)
-    zlog_info ("Neighbor Event %s: *AdjOK?*", o6n->str);
-
-  if (o6n->state == NBS_TWOWAY)
-    {
-      if (!need_adjacency (o6n))
-        {
-          nbs_change (NBS_TWOWAY, "No Need Adjacency", o6n);
-          return 0;
-        }
-      else
-        nbs_change (NBS_EXSTART, "Need Adjacency", o6n);
-
-      DD_MSBIT_SET (o6n->dbdesc_bits);
-      DD_MBIT_SET (o6n->dbdesc_bits);
-      DD_IBIT_SET (o6n->dbdesc_bits);
-
-      if (o6n->thread_send_dbdesc)
-        thread_cancel (o6n->thread_send_dbdesc);
-      o6n->thread_send_dbdesc =
-        thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
-
-      return 0;
-    }
-
-  if (o6n->state >= NBS_EXSTART)
-    {
-      if (need_adjacency (o6n))
-        return 0;
-      else
-        {
-          nbs_change (NBS_TWOWAY, "No Need Adjacency", o6n);
-          ospf6_neighbor_lslist_clear (o6n);
-        }
-    }
-  return 0;
-}
-
-int
-seqnumber_mismatch (struct thread *thread)
-{
-  struct ospf6_neighbor *o6n;
-
-  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
-  assert (o6n);
-
-  if (o6n->state < NBS_EXCHANGE)
-    return 0;
-
-  /* statistics */
-  o6n->ospf6_stat_seqnum_mismatch++;
-
-  if (IS_OSPF6_DUMP_NEIGHBOR)
-    zlog_info ("Neighbor Event %s: *SeqNumberMismatch*", o6n->str);
-
-  nbs_change (NBS_EXSTART, "SeqNumberMismatch", o6n);
-
-  DD_MSBIT_SET (o6n->dbdesc_bits);
-  DD_MBIT_SET (o6n->dbdesc_bits);
-  DD_IBIT_SET (o6n->dbdesc_bits);
-  ospf6_neighbor_lslist_clear (o6n);
-
-  if (o6n->thread_send_dbdesc)
-    thread_cancel (o6n->thread_send_dbdesc);
-  o6n->thread_send_dbdesc =
-    thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
-
-  return 0;
-}
-
-int
-bad_lsreq (struct thread *thread)
-{
-  struct ospf6_neighbor *o6n;
-
-  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
-  assert (o6n);
-
-  if (o6n->state < NBS_EXCHANGE)
-    return 0;
-
-  /* statistics */
-  o6n->ospf6_stat_bad_lsreq++;
-
-  if (IS_OSPF6_DUMP_NEIGHBOR)
-    zlog_info ("Neighbor Event %s: *BadLSReq*", o6n->str);
-
-  nbs_change (NBS_EXSTART, "BadLSReq", o6n);
-
-  DD_MSBIT_SET (o6n->dbdesc_bits);
-  DD_MBIT_SET (o6n->dbdesc_bits);
-  DD_IBIT_SET (o6n->dbdesc_bits);
-  ospf6_neighbor_lslist_clear (o6n);
-
-  if (o6n->thread_send_dbdesc)
-    thread_cancel (o6n->thread_send_dbdesc);
-  o6n->thread_send_dbdesc =
-    thread_add_event (master, ospf6_send_dbdesc, o6n, 0);
-
-  return 0;
-}
-
-int
-oneway_received (struct thread *thread)
-{
-  struct ospf6_neighbor *o6n;
-
-  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
-  assert (o6n);
-
-  if (o6n->state < NBS_TWOWAY)
-    return 0;
-
-  /* statistics */
-  o6n->ospf6_stat_oneway_received++;
-
-  if (IS_OSPF6_DUMP_NEIGHBOR)
-    zlog_info ("Neighbor Event %s: *1Way-Received*", o6n->str);
-
-  nbs_change (NBS_INIT, "1Way-Received", o6n);
-
-  thread_add_event (master, neighbor_change, o6n->ospf6_interface, 0);
-
-  ospf6_neighbor_thread_cancel_all (o6n);
-  ospf6_neighbor_lslist_clear (o6n);
-  return 0;
-}
-
-int
-inactivity_timer (struct thread *thread)
-{
-  struct ospf6_neighbor *o6n;
-
-  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
-  assert (o6n);
-
-  /* statistics */
-  o6n->ospf6_stat_inactivity_timer++;
-
-  if (IS_OSPF6_DUMP_NEIGHBOR)
-    zlog_info ("Neighbor Event %s: *InactivityTimer*", o6n->str);
-
-  o6n->inactivity_timer = NULL;
-  o6n->dr = o6n->bdr = o6n->prevdr = o6n->prevbdr = 0;
-  nbs_change (NBS_DOWN, "InactivityTimer", o6n);
-
-  thread_add_event (master, neighbor_change, o6n->ospf6_interface, 0);
-
-  listnode_delete (o6n->ospf6_interface->neighbor_list, o6n);
-  ospf6_neighbor_delete (o6n);
-
-  return 0;
-}
-
diff --git a/ospf6d/ospf6_nsm.h b/ospf6d/ospf6_nsm.h
deleted file mode 100644
index d70f1e8..0000000
--- a/ospf6d/ospf6_nsm.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 1999 Yasuhiro Ohara
- *
- * 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.  
- */
-
-#ifndef OSPF6_NSM_H
-#define OSPF6_NSM_H
-
-/* Neighbor state */
-#define NBS_DOWN                      1
-#define OSPF6_NEIGHBOR_STATE_DOWN     1
-#define NBS_ATTEMPT                   2
-#define OSPF6_NEIGHBOR_STATE_ATTEMPT  2
-#define NBS_INIT                      3
-#define OSPF6_NEIGHBOR_STATE_INIT     3
-#define NBS_TWOWAY                    4
-#define OSPF6_NEIGHBOR_STATE_TWOWAY   4
-#define NBS_EXSTART                   5
-#define OSPF6_NEIGHBOR_STATE_EXSTART  5
-#define NBS_EXCHANGE                  6
-#define OSPF6_NEIGHBOR_STATE_EXCHANGE 6
-#define NBS_LOADING                   7
-#define OSPF6_NEIGHBOR_STATE_LOADING  7
-#define NBS_FULL                      8
-#define OSPF6_NEIGHBOR_STATE_FULL     8
-
-
-
-/* Function Prototypes */
-
-#include "ospf6_types.h"
-
-int need_adjacency (struct ospf6_neighbor *);
-
-
-/* Neighbor event */
-int hello_received (struct thread *);
-int twoway_received (struct thread *);
-int negotiation_done (struct thread *);
-int exchange_done (struct thread *);
-int loading_done (struct thread *);
-int adj_ok (struct thread *);
-int seqnumber_mismatch (struct thread *);
-int bad_lsreq (struct thread *);
-int oneway_received (struct thread *);
-int inactivity_timer (struct thread *);
-
-int dr_election (struct ospf6_interface *);
-
-#endif /* OSPF6_NSM_H */
-
diff --git a/ospf6d/ospf6_prefix.c b/ospf6d/ospf6_prefix.c
deleted file mode 100644
index 1542200..0000000
--- a/ospf6d/ospf6_prefix.c
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 1999 Yasuhiro Ohara
- *
- * 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.  
- */
-
-#if 0
-
-#include <zebra.h>
-
-#include "log.h"
-#include "prefix.h"
-#include "memory.h"
-#include "linklist.h"
-
-#include "ospf6_prefix.h"
-
-#else /*0*/
-
-#include "ospf6d.h"
-
-#endif /*0*/
-
-struct ospf6_prefix *
-ospf6_prefix_create (u_int8_t options, u_int16_t metric, struct prefix_ipv6 *p)
-{
-  struct prefix_ipv6 prefix;
-  struct ospf6_prefix *o6p;
-  size_t size;
-
-  /* copy prefix and apply mask */
-  prefix_copy ((struct prefix *) &prefix, (struct prefix *) p);
-  apply_mask_ipv6 (&prefix);
-
-  size = OSPF6_PREFIX_SPACE (prefix.prefixlen) + sizeof (struct ospf6_prefix);
-  o6p = (struct ospf6_prefix *) XMALLOC (MTYPE_OSPF6_PREFIX, size);
-  if (! o6p)
-    zlog_warn ("Can't allocate memory for ospf6 prefix: size: %d", size);
-  else
-    memset (o6p, 0, size);
-
-  o6p->prefix_length = prefix.prefixlen;
-  o6p->prefix_options = options;
-  o6p->prefix_metric = htons (metric);
-  memcpy (o6p + 1, &prefix.prefix, OSPF6_PREFIX_SPACE (prefix.prefixlen));
-
-  return o6p;
-}
-
-void
-ospf6_prefix_delete (struct ospf6_prefix *p)
-{
-  XFREE (MTYPE_OSPF6_PREFIX, p);
-}
-
-int
-ospf6_prefix_issame (struct ospf6_prefix *p1, struct ospf6_prefix *p2)
-{
-  if (p1->prefix_length != p2->prefix_length)
-    return 0;
-  if (memcmp (&p1->u, &p2->u, sizeof (p1->u)))
-    return 0;
-  if (memcmp (p1 + 1, p2 + 1, OSPF6_PREFIX_SPACE (p1->prefix_length)))
-    return 0;
-  return 1;
-}
-
-struct ospf6_prefix *
-ospf6_prefix_lookup (list l, struct ospf6_prefix *p1)
-{
-  listnode node;
-  struct ospf6_prefix *p2;
-  for (node = listhead (l); node; nextnode (node))
-    {
-      p2 = (struct ospf6_prefix *) getdata (node);
-      if (ospf6_prefix_issame (p1, p2))
-        return p2;
-    }
-  return NULL;
-}
-
-/* add a copy of given prefix to the list */
-void
-ospf6_prefix_add (list l, struct ospf6_prefix *p)
-{
-  struct ospf6_prefix *add;
-  add = (struct ospf6_prefix *) XMALLOC (MTYPE_OSPF6_PREFIX,
-                                         OSPF6_PREFIX_SIZE (p));
-  if (add == NULL)
-    {
-      zlog_warn ("Can't allocate memory for ospf6 prefix");
-      return;
-    }
-  else
-    memcpy (add, p, OSPF6_PREFIX_SIZE (p));
-
-  if (ospf6_prefix_lookup (l, add))
-    {
-      ospf6_prefix_delete (add);
-      return;
-    }
-  listnode_add (l, add);
-}
-
-void
-ospf6_prefix_remove (list l, struct ospf6_prefix *p)
-{
-  struct ospf6_prefix *rem;
-  rem = ospf6_prefix_lookup (l, p);
-  if (rem)
-    {
-      listnode_delete (l, rem);
-      ospf6_prefix_delete (rem);
-    }
-}
-
-void
-ospf6_prefix_in6_addr (struct ospf6_prefix *o6p, struct in6_addr *in6)
-{
-  memset (in6, 0, sizeof (struct in6_addr));
-  memcpy (in6, o6p + 1, OSPF6_PREFIX_SPACE (o6p->prefix_length));
-  return;
-}
-
-char *
-ospf6_prefix_options_str (u_int8_t opt, char *buf, size_t bufsize)
-{
-  char *p, *mc, *la, *nu;
-
-  p = (CHECK_FLAG (opt, OSPF6_PREFIX_OPTION_P) ? "P" : "-");
-  mc = (CHECK_FLAG (opt, OSPF6_PREFIX_OPTION_MC) ? "MC" : "--");
-  la = (CHECK_FLAG (opt, OSPF6_PREFIX_OPTION_LA) ? "LA" : "--");
-  nu = (CHECK_FLAG (opt, OSPF6_PREFIX_OPTION_NU) ? "NU" : "--");
-
-  snprintf (buf, bufsize, "%s|%s|%s|%s", p, mc, la, nu);
-  return buf;
-}
-
-char *
-ospf6_prefix_string (struct ospf6_prefix *prefix, char *buf, size_t size)
-{
-  struct in6_addr in6;
-  char s[64];
-
-  memset (&in6, 0, sizeof (in6));
-  memcpy (&in6, prefix + 1, OSPF6_PREFIX_SPACE (prefix->prefix_length));
-  inet_ntop (AF_INET6, &in6, s, sizeof (s));
-
-  snprintf (buf, size, "%s/%d", s, prefix->prefix_length);
-  return buf;
-}
-
-void
-ospf6_prefix_copy (struct ospf6_prefix *dst, struct ospf6_prefix *src,
-                   size_t dstsize)
-{
-  size_t srcsize;
-
-  memset (dst, 0, dstsize);
-
-  srcsize = OSPF6_PREFIX_SIZE (src);
-  if (dstsize < srcsize)
-    memcpy (dst, src, dstsize);
-  else
-    memcpy (dst, src, srcsize);
-
-  return;
-}
-
-void
-ospf6_prefix_apply_mask (struct ospf6_prefix *o6p)
-{
-  u_char *pnt, mask;
-  int index, offset;
-
-  char buf[128];
-  struct in6_addr in6;
-  ospf6_prefix_in6_addr (o6p, &in6);
-  inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
-
-  pnt = (u_char *)(o6p + 1);
-  index = o6p->prefix_length / 8;
-  offset = o6p->prefix_length % 8;
-  mask = 0xff << (8 - offset);
-
-  if (index >= 16)
-    return;
-
-  pnt[index] &= mask;
-  index ++;
-
-  while (index < OSPF6_PREFIX_SPACE (o6p->prefix_length))
-    pnt[index++] = 0;
-
-  ospf6_prefix_in6_addr (o6p, &in6);
-  inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
-}
-
diff --git a/ospf6d/ospf6_prefix.h b/ospf6d/ospf6_prefix.h
deleted file mode 100644
index 65a8cbc..0000000
--- a/ospf6d/ospf6_prefix.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 1999 Yasuhiro Ohara
- *
- * 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.  
- */
-
-#ifndef OSPF6_PREFIX_H
-#define OSPF6_PREFIX_H
-
-#include "linklist.h"
-
-#define OSPF6_PREFIX_OPTION_NU (1 << 0)  /* No Unicast */
-#define OSPF6_PREFIX_OPTION_LA (1 << 1)  /* Local Address */
-#define OSPF6_PREFIX_OPTION_MC (1 << 2)  /* MultiCast */
-#define OSPF6_PREFIX_OPTION_P  (1 << 3)  /* Propagate (NSSA) */
-
-struct ospf6_prefix
-{
-  u_int8_t prefix_length;
-  u_int8_t prefix_options;
-  union {
-    u_int16_t _prefix_metric;
-    u_int16_t _prefix_referenced_lstype;
-  } u;
-#define prefix_metric u._prefix_metric
-#define prefix_refer_lstype u._prefix_referenced_lstype
-  /* followed by one address_prefix */
-};
-
-/* size_t OSPF6_PREFIX_SPACE (int prefixlength); */
-#define OSPF6_PREFIX_SPACE(x) ((((x) + 31) / 32) * 4)
-
-/* size_t OSPF6_PREFIX_SIZE (struct ospf6_prefix *); */
-#define OSPF6_PREFIX_SIZE(x) \
-   (OSPF6_PREFIX_SPACE ((x)->prefix_length) + sizeof (struct ospf6_prefix))
-
-/* struct ospf6_prefix *OSPF6_NEXT_PREFIX (struct ospf6_prefix *); */
-#define OSPF6_NEXT_PREFIX(x) \
-   ((struct ospf6_prefix *)((char *)(x) + OSPF6_PREFIX_SIZE (x)))
-
-
-
-/* Function Prototypes */
-struct ospf6_prefix *
-  ospf6_prefix_make (u_int8_t, u_int16_t, struct prefix_ipv6 *);
-void ospf6_prefix_free (struct ospf6_prefix *);
-void ospf6_prefix_in6_addr (struct ospf6_prefix *, struct in6_addr *);
-void ospf6_prefix_copy (struct ospf6_prefix *, struct ospf6_prefix *,
-                        size_t);
-
-void ospf6_prefix_apply_mask (struct ospf6_prefix *);
-int ospf6_prefix_issame (struct ospf6_prefix *, struct ospf6_prefix *);
-
-char *ospf6_prefix_options_str (u_int8_t, char *, size_t);
-char *ospf6_prefix_string (struct ospf6_prefix *, char *, size_t);
-
-struct ospf6_prefix *
-ospf6_prefix_lookup (list l, struct ospf6_prefix *prefix);
-void ospf6_prefix_add (list, struct ospf6_prefix *);
-
-struct ospf6_prefix *
-ospf6_prefix_create (u_int8_t, u_int16_t, struct prefix_ipv6 *);
-void ospf6_prefix_delete (struct ospf6_prefix *);
-
-void ospf6_prefix_init ();
-
-#endif /* OSPF6_PREFIX_H */
-
diff --git a/ospf6d/ospf6_proto.c b/ospf6d/ospf6_proto.c
index 71e575f..7ee7e0a 100644
--- a/ospf6d/ospf6_proto.c
+++ b/ospf6d/ospf6_proto.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -21,20 +21,62 @@
 
 #include <zebra.h>
 
+#include "log.h"
+
 #include "ospf6_proto.h"
 
-char *
-ospf6_options_string (u_char opt_capability[3], char *buffer, int size)
+void
+ospf6_prefix_apply_mask (struct ospf6_prefix *op)
+{
+  u_char *pnt, mask;
+  int index, offset;
+
+  pnt = (u_char *)((caddr_t) op + sizeof (struct ospf6_prefix));
+  index = op->prefix_length / 8;
+  offset = op->prefix_length % 8;
+  mask = 0xff << (8 - offset);
+
+  if (index >= 16)
+    {
+      zlog_warn ("Apply mask to ospf6_prefix failed");
+      return;
+    }
+
+  pnt[index] &= mask;
+  index ++;
+
+  while (index < OSPF6_PREFIX_SPACE (op->prefix_length))
+    pnt[index++] = 0;
+}
+
+void
+ospf6_prefix_options_printbuf (u_int8_t prefix_options, char *buf, int size)
+{
+  snprintf (buf, size, "xxx");
+}
+
+void
+ospf6_capability_printbuf (char capability, char *buf, int size)
+{
+  char w, v, e, b;
+  w = (capability & OSPF6_ROUTER_BIT_W ? 'W' : '-');
+  v = (capability & OSPF6_ROUTER_BIT_V ? 'V' : '-');
+  e = (capability & OSPF6_ROUTER_BIT_E ? 'E' : '-');
+  b = (capability & OSPF6_ROUTER_BIT_B ? 'B' : '-');
+  snprintf (buf, size, "----%c%c%c%c", w, v, e, b);
+}
+
+void
+ospf6_options_printbuf (char *options, char *buf, int size)
 {
   char *dc, *r, *n, *mc, *e, *v6;
-
-  dc = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_DC) ? "DC" : "--");
-  r  = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_R) ? "R" : "-");
-  n  = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_N) ? "N" : "-");
-  mc = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_MC) ? "MC" : "--");
-  e  = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_E) ? "E" : "-");
-  v6 = (OSPF6_OPT_ISSET (opt_capability, OSPF6_OPT_V6) ? "V6" : "--");
-  snprintf (buffer, size, "%s|%s|%s|%s|%s|%s", dc, r, n, mc, e, v6);
-  return buffer;
+  dc = (OSPF6_OPT_ISSET (options, OSPF6_OPT_DC) ? "DC" : "--");
+  r  = (OSPF6_OPT_ISSET (options, OSPF6_OPT_R)  ? "R"  : "-" );
+  n  = (OSPF6_OPT_ISSET (options, OSPF6_OPT_N)  ? "N"  : "-" );
+  mc = (OSPF6_OPT_ISSET (options, OSPF6_OPT_MC) ? "MC" : "--");
+  e  = (OSPF6_OPT_ISSET (options, OSPF6_OPT_E)  ? "E"  : "-" );
+  v6 = (OSPF6_OPT_ISSET (options, OSPF6_OPT_V6) ? "V6" : "--");
+  snprintf (buf, size, "%s|%s|%s|%s|%s|%s", dc, r, n, mc, e, v6);
 }
 
+
diff --git a/ospf6d/ospf6_proto.h b/ospf6d/ospf6_proto.h
index 9a95444..447513a 100644
--- a/ospf6d/ospf6_proto.h
+++ b/ospf6d/ospf6_proto.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -23,7 +23,7 @@
 #define OSPF6_PROTO_H
 
 /* OSPF protocol version */
-#define OSPF6_VERSION		3
+#define OSPFV3_VERSION           3
 
 /* OSPF protocol number. */
 #ifndef IPPROTO_OSPFIGP
@@ -31,28 +31,31 @@
 #endif
 
 /* TOS field normaly null */
-#define OSPF6_TOS_VALUE               0x0
+#define DEFAULT_TOS_VALUE      0x0
 
 /* Architectural Constants */
-#define OSPF6_LS_REFRESH_TIME         1800       /* 30 min */
-#define OSPF6_MIN_LS_INTERVAL         5
-#define OSPF6_MIN_LS_ARRIVAL          1
-#define MAXAGE                  3600       /* 1 hour */
-#define CHECK_AGE               300        /* 5 min */
-#define MAX_AGE_DIFF            900        /* 15 min */
-#define LS_INFINITY             0xffffff   /* 24-bit binary value */
-#define INITIAL_SEQUENCE_NUMBER 0x80000001 /* signed 32-bit integer */
-#define MAX_SEQUENCE_NUMBER     0x7fffffff /* signed 32-bit integer */
-
-#define MAXOSPFMESSAGELEN         4096
+#define LS_REFRESH_TIME                1800  /* 30 min */
+#define MIN_LS_INTERVAL                   5
+#define MIN_LS_ARRIVAL                    1
+#define MAXAGE                         3600  /* 1 hour */
+#define CHECK_AGE                       300  /* 5 min */
+#define MAX_AGE_DIFF                    900  /* 15 min */
+#define LS_INFINITY                0xffffff  /* 24-bit binary value */
+#define INITIAL_SEQUENCE_NUMBER  0x80000001  /* signed 32-bit integer */
+#define MAX_SEQUENCE_NUMBER      0x7fffffff  /* signed 32-bit integer */
 
 #define ALLSPFROUTERS6 "ff02::5"
 #define ALLDROUTERS6   "ff02::6"
 
 /* Configurable Constants */
 
-#define DEFAULT_HELLO_INTERVAL    10
-#define DEFAULT_ROUTER_DEAD_TIMER 40
+#define DEFAULT_HELLO_INTERVAL       10
+#define DEFAULT_ROUTER_DEAD_INTERVAL 40
+
+#define OSPF6_ROUTER_BIT_W     (1 << 3)
+#define OSPF6_ROUTER_BIT_V     (1 << 2)
+#define OSPF6_ROUTER_BIT_E     (1 << 1)
+#define OSPF6_ROUTER_BIT_B     (1 << 0)
 
 /* OSPF options */
 /* present in HELLO, DD, LSA */
@@ -61,15 +64,58 @@
 #define OSPF6_OPT_CLEAR(x,opt) ((x)[2] &= ~(opt))
 #define OSPF6_OPT_CLEAR_ALL(x) ((x)[0] = (x)[1] = (x)[2] = 0)
 
-#define OSPF6_OPT_V6 (1 << 0)   /* IPv6 forwarding Capability */
-#define OSPF6_OPT_E  (1 << 1)   /* AS External Capability */
-#define OSPF6_OPT_MC (1 << 2)   /* Multicasting Capability */
-#define OSPF6_OPT_N  (1 << 3)   /* Handling Type-7 LSA Capability */
-#define OSPF6_OPT_R  (1 << 4)   /* Forwarding Capability (Any Protocol) */
 #define OSPF6_OPT_DC (1 << 5)   /* Demand Circuit handling Capability */
+#define OSPF6_OPT_R  (1 << 4)   /* Forwarding Capability (Any Protocol) */
+#define OSPF6_OPT_N  (1 << 3)   /* Handling Type-7 LSA Capability */
+#define OSPF6_OPT_MC (1 << 2)   /* Multicasting Capability */
+#define OSPF6_OPT_E  (1 << 1)   /* AS External Capability */
+#define OSPF6_OPT_V6 (1 << 0)   /* IPv6 forwarding Capability */
 
-char *
-ospf6_options_string (u_char opt_capability[3], char *buffer, int size);
+/* OSPF6 Prefix */
+struct ospf6_prefix
+{
+  u_int8_t prefix_length;
+  u_int8_t prefix_options;
+  union {
+    u_int16_t _prefix_metric;
+    u_int16_t _prefix_referenced_lstype;
+  } u;
+#define prefix_metric        u._prefix_metric
+#define prefix_refer_lstype  u._prefix_referenced_lstype
+  /* followed by one address_prefix */
+};
+
+#define OSPF6_PREFIX_OPTION_NU (1 << 0)  /* No Unicast */
+#define OSPF6_PREFIX_OPTION_LA (1 << 1)  /* Local Address */
+#define OSPF6_PREFIX_OPTION_MC (1 << 2)  /* MultiCast */
+#define OSPF6_PREFIX_OPTION_P  (1 << 3)  /* Propagate (NSSA) */
+
+/* caddr_t OSPF6_PREFIX_BODY (struct ospf6_prefix *); */
+#define OSPF6_PREFIX_BODY(x) ((caddr_t)(x) + sizeof (struct ospf6_prefix))
+
+/* size_t OSPF6_PREFIX_SPACE (int prefixlength); */
+#define OSPF6_PREFIX_SPACE(x) ((((x) + 31) / 32) * 4)
+
+/* size_t OSPF6_PREFIX_SIZE (struct ospf6_prefix *); */
+#define OSPF6_PREFIX_SIZE(x) \
+   (OSPF6_PREFIX_SPACE ((x)->prefix_length) + sizeof (struct ospf6_prefix))
+
+/* struct ospf6_prefix *OSPF6_PREFIX_NEXT (struct ospf6_prefix *); */
+#define OSPF6_PREFIX_NEXT(x) \
+   ((struct ospf6_prefix *)((caddr_t)(x) + OSPF6_PREFIX_SIZE (x)))
+
+#define ospf6_prefix_in6_addr(in6, op)                         \
+do {                                                           \
+  memset (in6, 0, sizeof (struct in6_addr));                   \
+  memcpy (in6, (caddr_t) (op) + sizeof (struct ospf6_prefix),  \
+          OSPF6_PREFIX_SPACE ((op)->prefix_length));           \
+} while (0)
+
+void ospf6_prefix_apply_mask (struct ospf6_prefix *op);
+void ospf6_prefix_options_printbuf (u_int8_t prefix_options,
+                                    char *buf, int size);
+void ospf6_capability_printbuf (char capability, char *buf, int size);
+void ospf6_options_printbuf (char *options, char *buf, int size);
 
 #endif /* OSPF6_PROTO_H */
 
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c
index b3abedc..73bdac2 100644
--- a/ospf6d/ospf6_route.c
+++ b/ospf6d/ospf6_route.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -19,1118 +19,1119 @@
  * Boston, MA 02111-1307, USA.  
  */
 
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "prefix.h"
+#include "table.h"
+#include "vty.h"
+#include "command.h"
+
 #include "ospf6d.h"
+#include "ospf6_proto.h"
+#include "ospf6_lsa.h"
+#include "ospf6_route.h"
 
-char *
-dtype_name[OSPF6_DEST_TYPE_MAX] =
+unsigned char conf_debug_ospf6_route = 0;
+
+void
+ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id,
+                        struct prefix *prefix)
 {
-  "Unknown", "Router", "Network", "Discard"
-};
-#define DTYPE_NAME(x) \
-  (0 < (x) && (x) < sizeof (dtype_name) ? \
-   dtype_name[(x)] : dtype_name[0])
-
-char *
-dtype_abname[OSPF6_DEST_TYPE_MAX] =
-{
-  "?", "R", "N", "D"
-};
-#define DTYPE_ABNAME(x) \
-  (0 < (x) && (x) < sizeof (dtype_abname) ? \
-   dtype_abname[(x)] : dtype_abname[0])
-
-char *
-ptype_name[OSPF6_PATH_TYPE_MAX] =
-{
-  "Unknown", "Intra", "Inter", "External-1", "External-2",
-  "System", "Kernel", "Connect", "Static", "RIP", "RIPng",
-  "OSPF", "OSPF6", "BGP"
-};
-#define PTYPE_NAME(x) \
-  (0 < (x) && (x) < sizeof (ptype_name) ? \
-   ptype_name[(x)] : ptype_name[0])
-
-char *
-ptype_abname[OSPF6_PATH_TYPE_MAX] =
-{
-  "??", "Ia", "Ie", "E1", "E2",
-  "-X", "-K", "-C", "-S", "-R", "-R",
-  "-O", "-O", "-B"
-};
-#define PTYPE_ABNAME(x) \
-  (0 < (x) && (x) < sizeof (ptype_abname) ? \
-   ptype_abname[(x)] : ptype_abname[0])
-
-
-
-int
-ospf6_path_cmp (void *arg1, void *arg2)
-{
-  struct ospf6_path_node *pn1 = arg1;
-  struct ospf6_path_node *pn2 = arg2;
-  struct ospf6_path *p1 = &pn1->path;
-  struct ospf6_path *p2 = &pn2->path;
-
-  if (p1->type < p2->type)
-    return -1;
-  else if (p1->type > p2->type)
-    return 1;
-
-  if (p1->type == OSPF6_PATH_TYPE_EXTERNAL2)
-    {
-      if (p1->cost_e2 < p2->cost_e2)
-        return -1;
-      else if (p1->cost_e2 > p2->cost_e2)
-        return 1;
-    }
-
-  if (p1->cost < p2->cost)
-    return -1;
-  else if (p1->cost > p2->cost)
-    return 1;
-
-  /* if from the same source, recognize as identical
-     (and treat this as update) */
-  if (! memcmp (&p1->origin, &p2->origin, sizeof (struct ls_origin)) &&
-      p1->area_id == p2->area_id)
-    return 0;
-
-  /* else, always prefer left */
-  return -1;
+  memset (prefix, 0, sizeof (struct prefix));
+  prefix->family = AF_INET6;
+  prefix->prefixlen = 64;
+  memcpy (&prefix->u.prefix6.s6_addr[0], &adv_router, 4);
+  memcpy (&prefix->u.prefix6.s6_addr[4], &id, 4);
 }
 
-int
-ospf6_nexthop_cmp (void *arg1, void *arg2)
+void
+ospf6_linkstate_prefix2str (struct prefix *prefix, char *buf, int size)
 {
-  int i, ret = 0;
-  struct ospf6_nexthop_node *nn1 = arg1;
-  struct ospf6_nexthop_node *nn2 = arg2;
-  struct ospf6_nexthop *n1 = &nn1->nexthop;
-  struct ospf6_nexthop *n2 = &nn2->nexthop;
-
-  if (memcmp (n1, n2, sizeof (struct ospf6_nexthop)) == 0)
-    return 0;
-
-  for (i = 0; i < sizeof (struct in6_addr); i++)
-    {
-      if (nn1->nexthop.address.s6_addr[i] != nn2->nexthop.address.s6_addr[i])
-        {
-          ret = nn1->nexthop.address.s6_addr[i] -
-                nn2->nexthop.address.s6_addr[i];
-          break;
-        }
-    }
-
-  if (ret == 0)
-    ret = -1;
-
-  return ret;
+  u_int32_t adv_router, id;
+  char adv_router_str[16];
+  memcpy (&adv_router, &prefix->u.prefix6.s6_addr[0], 4);
+  memcpy (&id, &prefix->u.prefix6.s6_addr[4], 4);
+  inet_ntop (AF_INET, &adv_router, adv_router_str, sizeof (adv_router_str));
+  snprintf (buf, size, "%s(%lu)", adv_router_str, (u_long) ntohl (id));
 }
 
-static void
-ospf6_route_request (struct ospf6_route_req *request,
-                     struct ospf6_route_node   *rn,
-                     struct ospf6_path_node    *pn,
-                     struct ospf6_nexthop_node *nn)
+/* Global strings for logging */
+char *ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX] =
+{ "Unknown", "Router", "Network", "Discard", "Linkstate", };
+
+char *ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX] =
+{ "?", "R", "N", "D", "L", };
+
+char *ospf6_path_type_str[OSPF6_PATH_TYPE_MAX] =
+{ "Unknown", "Intra-Area", "Inter-Area", "External-1", "External-2", };
+
+char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] =
+{ "??", "Ia", "Ie", "E1", "E2", };
+
+
+struct ospf6_route *
+ospf6_route_create ()
 {
-  assert (request);
-  assert (rn && pn && nn);
-
-  request->route_node = rn->route_node;
-
-  linklist_head (rn->path_list, &request->path_lnode);
-  while (request->path_lnode.data != pn)
-    {
-      //assert (! linklist_end (&request->path_lnode));
-      if (linklist_end (&request->path_lnode))
-        {
-          struct linklist_node node;
-
-          zlog_info ("rn: %p, pn: %p", rn, pn);
-          zlog_info ("origin: %hx %x %x bits: %x opt: %x%x%x popt: %x area: %x type: %d cost  %d %d %d",
-          pn->path.origin.type, pn->path.origin.id, pn->path.origin.adv_router, (int)pn->path.router_bits, (int)pn->path.capability[0],
-          (int)pn->path.capability[1], (int)pn->path.capability[2],
-          (int)pn->path.prefix_options, pn->path.area_id,
-          pn->path.type, pn->path.metric_type, pn->path.cost, pn->path.cost_e2);
-
-          for (linklist_head (rn->path_list, &node); ! linklist_end (&node);
-               linklist_next (&node))
-            {
-              struct ospf6_path_node *pn2 = node.data;
-
-              zlog_info (" %p: path data with pn(%p): %s", pn2, pn,
-                         (memcmp (&pn->path, &pn2->path,
-                                  sizeof (struct ospf6_path)) ?
-                          "different" : "same"));
-
-          zlog_info ("  origin: %hx %x %x bits: %x opt: %x%x%x popt: %x area: %x type: %d cost  %d %d %d",
-          pn2->path.origin.type, pn2->path.origin.id, pn2->path.origin.adv_router, (int)pn2->path.router_bits, (int)pn2->path.capability[0],
-          (int)pn2->path.capability[1], (int)pn2->path.capability[2],
-          (int)pn2->path.prefix_options, pn2->path.area_id,
-          pn2->path.type, pn2->path.metric_type, pn2->path.cost, pn2->path.cost_e2);
-
-              if (! memcmp (&pn->path, &pn2->path, sizeof (struct ospf6_path)))
-                {
-                  pn = pn2;
-                  request->nexthop_lnode.data = pn2;
-                }
-            }
-          break;
-        }
-      linklist_next (&request->path_lnode);
-    }
-  assert (request->path_lnode.data == pn);
-
-  linklist_head (pn->nexthop_list, &request->nexthop_lnode);
-  while (request->nexthop_lnode.data != nn)
-    {
-      assert (! linklist_end (&request->nexthop_lnode));
-      linklist_next (&request->nexthop_lnode);
-    }
-  assert (request->nexthop_lnode.data == nn);
-
-  request->table = rn->table;
-  request->count = rn->count;
-  request->route_id = rn->route_id;
-  memcpy (&request->route,   &rn->route,   sizeof (struct ospf6_route));
-  memcpy (&request->path,    &pn->path,    sizeof (struct ospf6_path));
-  memcpy (&request->nexthop, &nn->nexthop, sizeof (struct ospf6_nexthop));
+  struct ospf6_route *route;
+  route = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route));
+  return route;
 }
 
-int
-ospf6_route_count (struct ospf6_route_req *request)
+void
+ospf6_route_delete (struct ospf6_route *route)
 {
-  return request->count;
+  XFREE (MTYPE_OSPF6_ROUTE, route);
 }
 
-int
-ospf6_route_lookup (struct ospf6_route_req *request,
-                    struct prefix *prefix,
+struct ospf6_route *
+ospf6_route_copy (struct ospf6_route *route)
+{
+  struct ospf6_route *new;
+
+  new = ospf6_route_create ();
+  memcpy (new, route, sizeof (struct ospf6_route));
+  new->rnode = NULL;
+  new->prev = NULL;
+  new->next = NULL;
+  new->lock = 0;
+  return new;
+}
+
+void
+ospf6_route_lock (struct ospf6_route *route)
+{
+  route->lock++;
+}
+
+void
+ospf6_route_unlock (struct ospf6_route *route)
+{
+  assert (route->lock > 0);
+  route->lock--;
+  if (route->lock == 0)
+    ospf6_route_delete (route);
+}
+
+/* Route compare function. If ra is more preferred, it returns
+   less than 0. If rb is more preferred returns greater than 0.
+   Otherwise (neither one is preferred), returns 0 */
+static int
+ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb)
+{
+  assert (ospf6_route_is_same (ra, rb));
+  assert (OSPF6_PATH_TYPE_NONE < ra->path.type &&
+          ra->path.type < OSPF6_PATH_TYPE_MAX);
+  assert (OSPF6_PATH_TYPE_NONE < rb->path.type &&
+          rb->path.type < OSPF6_PATH_TYPE_MAX);
+
+  if (ra->type != rb->type)
+    return (ra->type - rb->type);
+
+  if (ra->path.area_id != rb->path.area_id)
+    return (ntohl (ra->path.area_id) - ntohl (rb->path.area_id));
+
+  if (ra->path.type != rb->path.type)
+    return (ra->path.type - rb->path.type);
+
+  if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2)
+    {
+      if (ra->path.cost_e2 != rb->path.cost_e2)
+        return (ra->path.cost_e2 - rb->path.cost_e2);
+    }
+  else
+    {
+      if (ra->path.cost != rb->path.cost)
+        return (ra->path.cost - rb->path.cost);
+    }
+
+  return 0;
+}
+
+struct ospf6_route *
+ospf6_route_lookup (struct prefix *prefix,
                     struct ospf6_route_table *table)
 {
   struct route_node *node;
-  struct ospf6_route_node   *rn = NULL;
-  struct ospf6_path_node    *pn = NULL;
-  struct ospf6_nexthop_node *nn = NULL;
-  struct linklist_node lnode;
-
-  if (request)
-    memset ((void *) request, 0, sizeof (struct ospf6_route_req));
+  struct ospf6_route *route;
 
   node = route_node_lookup (table->table, prefix);
-  if (! node)
-    return 0;
+  if (node == NULL)
+    return NULL;
 
-  rn = (struct ospf6_route_node *) node->info;
-  if (! rn)
-    return 0;
-
-  if (request)
-    {
-      linklist_head (rn->path_list, &lnode);
-      pn = lnode.data;
-      linklist_head (pn->nexthop_list, &lnode);
-      nn = lnode.data;
-
-      ospf6_route_request (request, rn, pn, nn);
-    }
-
-  return 1;
+  route = (struct ospf6_route *) node->info;
+  return route;
 }
 
-void
-ospf6_route_head (struct ospf6_route_req *request,
-                  struct ospf6_route_table *table)
+struct ospf6_route *
+ospf6_route_lookup_identical (struct ospf6_route *route,
+                              struct ospf6_route_table *table)
+{
+  struct ospf6_route *target;
+
+  for (target = ospf6_route_lookup (&route->prefix, table);
+       target; target = target->next)
+    {
+      if (ospf6_route_is_identical (target, route))
+        return target;
+    }
+  return NULL;
+}
+
+struct ospf6_route *
+ospf6_route_lookup_bestmatch (struct prefix *prefix,
+                              struct ospf6_route_table *table)
 {
   struct route_node *node;
-  struct ospf6_route_node   *rn = NULL;
-  struct ospf6_path_node    *pn = NULL;
-  struct ospf6_nexthop_node *nn = NULL;
-  struct linklist_node lnode;
+  struct ospf6_route *route;
 
-  if (request)
-    memset (request, 0, sizeof (struct ospf6_route_req));
+  node = route_node_match (table->table, prefix);
+  if (node == NULL)
+    return NULL;
+  route_unlock_node (node);
 
-  node = route_top (table->table);
-  if (! node)
-    return;
-
-  while (node && node->info == NULL)
-    node = route_next (node);
-  if (! node)
-    return;
-
-  rn = (struct ospf6_route_node *) node->info;
-  linklist_head (rn->path_list, &lnode);
-  pn = lnode.data;
-  linklist_head (pn->nexthop_list, &lnode);
-  nn = lnode.data;
-
-  ospf6_route_request (request, rn, pn, nn);
+  route = (struct ospf6_route *) node->info;
+  return route;
 }
 
-int
-ospf6_route_end (struct ospf6_route_req *request)
+#ifndef NDEBUG
+static void
+_route_count_assert (struct ospf6_route_table *table)
 {
-  if (request->route_node == NULL &&
-      linklist_end (&request->path_lnode) &&
-      linklist_end (&request->nexthop_lnode) &&
-      request->nexthop.ifindex == 0 &&
-      IN6_IS_ADDR_UNSPECIFIED (&request->nexthop.address))
-    return 1;
-  return 0;
+  struct ospf6_route *debug;
+  int num = 0;
+  for (debug = ospf6_route_head (table); debug;
+       debug = ospf6_route_next (debug))
+    num++;
+  assert (num == table->count);
 }
+#define ospf6_route_count_assert(t) (_route_count_assert (t))
+#else
+#define ospf6_route_count_assert(t) ((void) 0)
+#endif /*NDEBUG*/
 
-void
-ospf6_route_next (struct ospf6_route_req *request)
-{
-  struct ospf6_route_node   *route_node = NULL;
-  struct ospf6_path_node    *path_node = NULL;
-  struct ospf6_nexthop_node *nexthop_node = NULL;
-
-  linklist_next (&request->nexthop_lnode);
-  if (linklist_end (&request->nexthop_lnode))
-    {
-      linklist_next (&request->path_lnode);
-      if (linklist_end (&request->path_lnode))
-        {
-          request->route_node = route_next (request->route_node);
-          while (request->route_node && request->route_node->info == NULL)
-            request->route_node = route_next (request->route_node);
-          if (request->route_node)
-            {
-              route_node = request->route_node->info;
-              if (route_node)
-                linklist_head (route_node->path_list, &request->path_lnode);
-            }
-        }
-
-      path_node = request->path_lnode.data;
-      if (path_node)
-        linklist_head (path_node->nexthop_list, &request->nexthop_lnode);
-    }
-
-  nexthop_node = request->nexthop_lnode.data;
-
-  if (nexthop_node == NULL)
-    {
-      assert (path_node == NULL);
-      assert (route_node == NULL);
-
-      memset (&request->route,   0, sizeof (struct ospf6_route));
-      memset (&request->path,    0, sizeof (struct ospf6_path));
-      memset (&request->nexthop, 0, sizeof (struct ospf6_nexthop));
-    }
-  else
-    {
-      path_node = request->path_lnode.data;
-      route_node = request->route_node->info;
-
-      assert (path_node != NULL);
-      assert (route_node != NULL);
-
-      memcpy (&request->route,   &route_node->route,
-              sizeof (struct ospf6_route));
-      memcpy (&request->path,    &path_node->path,
-              sizeof (struct ospf6_path));
-      memcpy (&request->nexthop, &nexthop_node->nexthop,
-              sizeof (struct ospf6_nexthop));
-    }
-}
-
-#define ADD    0
-#define CHANGE 1
-#define REMOVE 2
-
-void
-ospf6_route_hook_call (int type,
-                       struct ospf6_route_req *request,
-                       struct ospf6_route_table *table)
-{
-  struct linklist_node node;
-  void (*func) (struct ospf6_route_req *);
-
-  for (linklist_head (table->hook_list[type], &node);
-       ! linklist_end (&node);
-       linklist_next (&node))
-    {
-      func = node.data;
-      (*func) (request);
-    }
-}
-
-void
-ospf6_route_hook_register (void (*add)    (struct ospf6_route_req *),
-                           void (*change) (struct ospf6_route_req *),
-                           void (*remove) (struct ospf6_route_req *),
-                           struct ospf6_route_table *table)
-{
-  linklist_add (add,    table->hook_list[ADD]);
-  linklist_add (change, table->hook_list[CHANGE]);
-  linklist_add (remove, table->hook_list[REMOVE]);
-}
-
-void
-ospf6_route_hook_unregister (void (*add)    (struct ospf6_route_req *),
-                             void (*change) (struct ospf6_route_req *),
-                             void (*remove) (struct ospf6_route_req *),
-                             struct ospf6_route_table *table)
-{
-  linklist_remove (add,    table->hook_list[ADD]);
-  linklist_remove (change, table->hook_list[CHANGE]);
-  linklist_remove (remove, table->hook_list[REMOVE]);
-}
-
-
-int
-prefix_ls2str (struct prefix *p, char *str, int size)
-{
-  char id[BUFSIZ], adv_router[BUFSIZ];
-  struct prefix_ls *pl = (struct prefix_ls *) p;
-
-  inet_ntop (AF_INET, &pl->id, id, BUFSIZ);
-  inet_ntop (AF_INET, &pl->adv_router, adv_router, BUFSIZ);
-  snprintf (str, size, "%s-%s", adv_router, id);
-  return 0;
-}
-
-void
-ospf6_route_log_request (char *what, char *where,
-                         struct ospf6_route_req *request)
-{
-  char prefix[64];
-  char area_id[16];
-  char type[16], id[16], adv[16];
-  char address[64], ifname[IFNAMSIZ];
-
-  if (request->route.prefix.family != AF_INET &&
-      request->route.prefix.family != AF_INET6)
-    prefix_ls2str (&request->route.prefix, prefix, sizeof (prefix));
-  else
-    prefix2str (&request->route.prefix, prefix, sizeof (prefix));
-
-  inet_ntop (AF_INET, &request->path.area_id, area_id, sizeof (area_id));
-
-  ospf6_lsa_type_string (request->path.origin.type, type, sizeof (type));
-  inet_ntop (AF_INET, &request->path.origin.id, id, sizeof (id));
-  inet_ntop (AF_INET, &request->path.origin.adv_router, adv, sizeof (adv));
-
-  inet_ntop (AF_INET6, &request->nexthop.address, address, sizeof (address));
-
-  zlog_info ("ROUTE: %s %s %s %s %s",
-             what, DTYPE_ABNAME (request->route.type), prefix,
-             ((strcmp ("Add", what) == 0) ? "to" : "from"), where);
-  zlog_info ("ROUTE:     Area: %s type: %s cost: %lu (E2: %lu)",
-             area_id, PTYPE_NAME (request->path.type),
-             (u_long) request->path.cost, (u_long) request->path.cost_e2);
-  zlog_info ("ROUTE:     Origin: Type: %s", type);
-  zlog_info ("ROUTE:     Origin: Id: %s Adv: %s", id, adv);
-  zlog_info ("ROUTE:     Nexthop: %s", address);
-  zlog_info ("ROUTE:     Nexthop: Ifindex: %u (%s)",
-             request->nexthop.ifindex,
-             if_indextoname (request->nexthop.ifindex, ifname));
-}
-
-struct ospf6_path_node *
-ospf6_route_find_path_node (struct ospf6_route_req *request,
-                            struct ospf6_route_node *rn)
-{
-  struct linklist_node node;
-
-  for (linklist_head (rn->path_list, &node); ! linklist_end (&node);
-       linklist_next (&node))
-    {
-      struct ospf6_path_node *path_node = node.data;
-
-      if (path_node->path.area_id == request->path.area_id &&
-          path_node->path.origin.type == request->path.origin.type &&
-          path_node->path.origin.id == request->path.origin.id &&
-          path_node->path.origin.adv_router == request->path.origin.adv_router)
-        return path_node;
-    }
-
-#if 0
-  zlog_info ("req path : area: %#x origin: type: %d, id: %d, adv_router: %#x",
-             request->path.area_id, request->path.origin.type,
-             request->path.origin.id, request->path.origin.adv_router);
-  for (linklist_head (rn->path_list, &node); ! linklist_end (&node);
-       linklist_next (&node))
-    {
-      struct ospf6_path_node *path_node = node.data;
-      zlog_info ("  path : area: %#x origin: type: %d, id: %d, adv_router: %#x",
-                 path_node->path.area_id, path_node->path.origin.type,
-                 path_node->path.origin.id, path_node->path.origin.adv_router);
-    }
-#endif
-
-  return NULL;
-}
-
-struct ospf6_nexthop_node *
-ospf6_route_find_nexthop_node (struct ospf6_route_req *request,
-                               struct ospf6_path_node *pn)
-{
-  struct linklist_node node;
-  for (linklist_head (pn->nexthop_list, &node); ! linklist_end (&node);
-       linklist_next (&node))
-    {
-      struct ospf6_nexthop_node *nexthop_node = node.data;
-
-      if (! memcmp (&nexthop_node->nexthop, &request->nexthop,
-          sizeof (struct ospf6_nexthop)))
-        return nexthop_node;
-    }
-  return NULL;
-}
-
-void
-ospf6_route_add (struct ospf6_route_req *request,
+struct ospf6_route *
+ospf6_route_add (struct ospf6_route *route,
                  struct ospf6_route_table *table)
 {
-  struct ospf6_route_node   *rn;
-  struct ospf6_path_node    *pn;
-  struct ospf6_nexthop_node *nn;
-  struct route_node *route_node;
+  struct route_node *node, *nextnode, *prevnode;
+  struct ospf6_route *current = NULL;
+  struct ospf6_route *prev = NULL, *old = NULL, *next = NULL;
+  char buf[64];
+  struct timeval now;
 
-  struct ospf6_route_req route;
+  assert (route->rnode == NULL);
+  assert (route->lock == 0);
+  assert (route->next == NULL);
+  assert (route->prev == NULL);
 
-  int route_change   = 0;
-  int path_change    = 0;
-  int nexthop_change = 0;
+  if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
+    ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf));
+  else
+    prefix2str (&route->prefix, buf, sizeof (buf));
 
-  /* find the requested route */
-  route_node = route_node_get (table->table, &request->route.prefix);
-  rn = (struct ospf6_route_node *) route_node->info;
+  if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+    zlog_info ("route add %s", buf);
 
-  if (rn)
+  gettimeofday (&now, NULL);
+
+  node = route_node_get (table->table, &route->prefix);
+  route->rnode = node;
+
+  /* find place to insert */
+  for (current = node->info; current; current = current->next)
     {
-      if (memcmp (&rn->route, &request->route, sizeof (struct ospf6_route)))
-        {
-          memcpy (&rn->route, &request->route, sizeof (struct ospf6_route));
-          route_change++;
-        }
+      if (! ospf6_route_is_same (current, route))
+        next = current;
+      else if (current->type != route->type)
+        prev = current;
+      else if (ospf6_route_is_same_origin (current, route))
+        old = current;
+      else if (ospf6_route_cmp (current, route) > 0)
+        next = current;
+      else
+        prev = current;
+
+      if (old || next)
+        break;
     }
+
+  if (old)
+    {
+      /* if route does not actually change, return unchanged */
+      if (ospf6_route_is_identical (old, route))
+        {
+          if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+            zlog_info ("  identical route found, ignore");
+
+          ospf6_route_delete (route);
+          SET_FLAG (old->flag, OSPF6_ROUTE_ADD);
+          ospf6_route_count_assert (table);
+          return old;
+        }
+
+      if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+        zlog_info ("  old route found, replace");
+
+      /* replace old one if exists */
+      if (node->info == old)
+        {
+          node->info = route;
+          SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
+        }
+
+      if (old->prev)
+        old->prev->next = route;
+      route->prev = old->prev;
+      if (old->next)
+        old->next->prev = route;
+      route->next = old->next;
+
+      route->installed = old->installed;
+      route->changed = now;
+
+      ospf6_route_unlock (old); /* will be deleted later */
+      ospf6_route_lock (route);
+
+      SET_FLAG (route->flag, OSPF6_ROUTE_CHANGE);
+      if (table->hook_add)
+        (*table->hook_add) (route);
+
+      ospf6_route_count_assert (table);
+      return route;
+    }
+
+  /* insert if previous or next node found */
+  if (prev || next)
+    {
+      if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+        zlog_info ("  another path found, insert");
+
+      if (prev == NULL)
+        prev = next->prev;
+      if (next == NULL)
+        next = prev->next;
+
+      if (prev)
+        prev->next = route;
+      route->prev = prev;
+      if (next)
+        next->prev = route;
+      route->next = next;
+
+      if (node->info == next)
+        {
+          assert (next->rnode == node);
+          node->info = route;
+          UNSET_FLAG (next->flag, OSPF6_ROUTE_BEST);
+          SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
+        }
+
+      route->installed = now;
+      route->changed = now;
+
+      ospf6_route_lock (route);
+      table->count++;
+
+      SET_FLAG (route->flag, OSPF6_ROUTE_ADD);
+      if (table->hook_add)
+        (*table->hook_add) (route);
+
+      ospf6_route_count_assert (table);
+      return route;
+    }
+
+  /* Else, this is the brand new route regarding to the prefix */
+  if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+    zlog_info ("  brand new route, add");
+
+  assert (node->info == NULL);
+  node->info = route;
+  SET_FLAG (route->flag, OSPF6_ROUTE_BEST);
+  ospf6_route_lock (route);
+  route->installed = now;
+  route->changed = now;
+
+  /* lookup real existing next route */
+  nextnode = node;
+  route_lock_node (nextnode);
+  do {
+    nextnode = route_next (nextnode);
+  } while (nextnode && nextnode->info == NULL);
+
+  /* set next link */
+  if (nextnode == NULL)
+    route->next = NULL;
   else
     {
-      rn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_node));
-      rn->table = table;
-      rn->route_node = route_node;
-      rn->route_id = table->route_id++;
-      rn->path_list = linklist_create ();
-      rn->path_list->cmp = ospf6_path_cmp;
-      memcpy (&rn->route, &request->route, sizeof (struct ospf6_route));
-      route_node->info = rn;
+      route_unlock_node (nextnode);
+
+      next = nextnode->info;
+      route->next = next;
+      next->prev = route;
     }
 
-  /* find the same path */
-  pn = ospf6_route_find_path_node (request, rn);
+  /* lookup real existing prev route */
+  prevnode = node;
+  route_lock_node (prevnode);
+  do {
+    prevnode = route_prev (prevnode);
+  } while (prevnode && prevnode->info == NULL);
 
-  if (pn)
-    {
-      if (memcmp (&pn->path, &request->path, sizeof (struct ospf6_path)))
-        {
-          memcpy (&pn->path, &request->path, sizeof (struct ospf6_path));
-          path_change++;
-        }
-    }
+  /* set prev link */
+  if (prevnode == NULL)
+    route->prev = NULL;
   else
     {
-      pn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_path_node));
-      pn->route_node = rn;
-      pn->nexthop_list = linklist_create ();
-      pn->nexthop_list->cmp = ospf6_nexthop_cmp;
-      memcpy (&pn->path, &request->path, sizeof (struct ospf6_path));
-      linklist_add (pn, rn->path_list);
+      route_unlock_node (prevnode);
+
+      prev = prevnode->info;
+      while (prev->next && ospf6_route_is_same (prev, prev->next))
+        prev = prev->next;
+      route->prev = prev;
+      prev->next = route;
     }
 
-  /* find the same nexthop */
-  nn = ospf6_route_find_nexthop_node (request, pn);
+  table->count++;
 
-  if (nn)
-    {
-      if (memcmp (&nn->nexthop, &request->nexthop,
-                  sizeof (struct ospf6_nexthop)))
-        {
-          memcpy (&nn->nexthop, &request->nexthop,
-                  sizeof (struct ospf6_nexthop));
-          nexthop_change++;
-          gettimeofday (&nn->installed, (struct timezone *) NULL);
-        }
-    }
-  else
-    {
-      nn = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_nexthop_node));
-      nn->path_node = pn;
-      memcpy (&nn->nexthop, &request->nexthop, sizeof (struct ospf6_nexthop));
-      linklist_add (nn, pn->nexthop_list);
-      rn->count++;
-      gettimeofday (&nn->installed, (struct timezone *) NULL);
-    }
+  SET_FLAG (route->flag, OSPF6_ROUTE_ADD);
+  if (table->hook_add)
+    (*table->hook_add) (route);
 
-  SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD);
-  if (route_change)
-    SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE);
-  if (path_change)
-    SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE);
-  if (nexthop_change)
-    SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE);
-
-  if (table->freeze)
-    return;
-
-  if (IS_OSPF6_DUMP_ROUTE)
-    {
-      ospf6_route_log_request ("Add", table->name, request);
-
-      if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE))
-        zlog_info ("ROUTE:   route attribute change");
-      if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE))
-        zlog_info ("ROUTE:   path attribute change");
-      if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
-        zlog_info ("ROUTE:   nexthop attribute change");
-    }
-
-  if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ROUTE_CHANGE) ||
-      CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_PATH_CHANGE))
-    SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE);
-
-  /* Call hooks */
-  ospf6_route_request (&route, rn, pn, nn);
-  if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD))
-    ospf6_route_hook_call (ADD, &route, table);
-  else if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
-    ospf6_route_hook_call (CHANGE, &route, table);
-
-  if (table->hook_add &&
-      CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD))
-    (*table->hook_add) (&route);
-  else if (table->hook_change &&
-           CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
-    (*table->hook_change) (&route);
-
-  /* clear flag */
-  nn->flag = 0;
+  ospf6_route_count_assert (table);
+  return route;
 }
 
 void
-ospf6_route_remove (struct ospf6_route_req *request,
+ospf6_route_remove (struct ospf6_route *route,
                     struct ospf6_route_table *table)
 {
-  struct ospf6_route_node   *rn;
-  struct ospf6_path_node    *pn;
-  struct ospf6_nexthop_node *nn;
-  struct route_node *route_node;
-  struct ospf6_route_req route;
+  struct route_node *node;
+  struct ospf6_route *current;
+  char buf[64];
 
-  /* find the requested route */
-  route_node = route_node_get (table->table, &request->route.prefix);
-  rn = (struct ospf6_route_node *) route_node->info;
+  if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
+    ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf));
+  else
+    prefix2str (&route->prefix, buf, sizeof (buf));
 
-  if (! rn)
+  if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+    zlog_info ("route remove: %s", buf);
+
+  node = route_node_lookup (table->table, &route->prefix);
+  assert (node);
+
+  /* find the route to remove, making sure that the route pointer
+     is from the route table. */
+  current = node->info;
+  while (current && ospf6_route_is_same (current, route))
     {
-      if (IS_OSPF6_DUMP_ROUTE)
+      if (current == route)
+        break;
+      current = current->next;
+    }
+  assert (current == route);
+
+  /* adjust doubly linked list */
+  if (route->prev)
+    route->prev->next = route->next;
+  if (route->next)
+    route->next->prev = route->prev;
+
+  if (node->info == route)
+    {
+      if (route->next && ospf6_route_is_same (route->next, route))
         {
-          ospf6_route_log_request ("Remove", table->name, request);
-          zlog_info ("ROUTE:   Can't remove: No such route");
+          node->info = route->next;
+          SET_FLAG (route->next->flag, OSPF6_ROUTE_BEST);
         }
-      return;
+      else
+        node->info = NULL; /* should unlock route_node here ? */
     }
 
-  pn = ospf6_route_find_path_node (request, rn);
-  if (! pn)
-    {
-      if (IS_OSPF6_DUMP_ROUTE)
-        {
-          ospf6_route_log_request ("Remove", table->name, request);
-          zlog_info ("ROUTE:   Can't remove: No such path");
-        }
-      return;
-    }
-
-  if (pn->path.area_id != request->path.area_id ||
-      pn->path.origin.type != request->path.origin.type ||
-      pn->path.origin.id != request->path.origin.id ||
-      pn->path.origin.adv_router != request->path.origin.adv_router)
-    {
-      if (IS_OSPF6_DUMP_ROUTE)
-        {
-          ospf6_route_log_request ("Remove", table->name, request);
-          zlog_info ("ROUTE:   Can't remove: Path differ");
-          {
-            char *s, *e, *c;
-            char line[512], *p;
-
-            p = line;
-            s = (char *) &pn->path;
-            e = s + sizeof (struct ospf6_path);
-            for (c = s; c < e; c++)
-              {
-                if ((c - s) % 4 == 0)
-		{
-                  snprintf (p, line + sizeof (line) - p, " ");
-		  p++;
-		}
-                snprintf (p, line + sizeof (line) - p, "%02x", *c);
-                p += 2;
-              }
-            zlog_info ("ROUTE:     path: %s", line);
-
-            p = line;
-            s = (char *) &request->path;
-            e = s + sizeof (struct ospf6_path);
-            for (c = s; c < e; c++)
-              {
-                if ((c - s) % 4 == 0)
-		{
-                  snprintf (p, line + sizeof (line) - p, " ");
-		  p++;
-		}
-                snprintf (p, line + sizeof (line) - p, "%02x", *c);
-                p += 2;
-              }
-            zlog_info ("ROUTE:     req : %s", line);
-
-          }
-        }
-      return;
-    }
-
-  nn = ospf6_route_find_nexthop_node (request, pn);
-  if (! nn)
-    {
-      if (IS_OSPF6_DUMP_ROUTE)
-        {
-          ospf6_route_log_request ("Remove", table->name, request);
-          zlog_info ("ROUTE:   Can't remove: No such nexthop");
-        }
-      return;
-    }
-
-  if (memcmp (&nn->nexthop, &request->nexthop, sizeof (struct ospf6_nexthop)))
-    {
-      if (IS_OSPF6_DUMP_ROUTE)
-        {
-          ospf6_route_log_request ("Remove", table->name, request);
-          zlog_info ("ROUTE:   Can't remove: Nexthop differ");
-        }
-      return;
-    }
-
-  SET_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE);
-
-  if (table->freeze)
-    return;
-
-  if (IS_OSPF6_DUMP_ROUTE)
-    ospf6_route_log_request ("Remove", table->name, request);
-
-  ospf6_route_request (&route, rn, pn, nn);
-  ospf6_route_hook_call (REMOVE, &route, table);
   if (table->hook_remove)
-    (*table->hook_remove) (&route);
+    (*table->hook_remove) (route);
 
-  /* clear flag */
-  nn->flag = 0;
+  ospf6_route_unlock (route);
+  table->count--;
 
-  /* remove nexthop */
-  linklist_remove (nn, pn->nexthop_list);
-  rn->count--;
-  XFREE (MTYPE_OSPF6_ROUTE, nn);
+  ospf6_route_count_assert (table);
+}
 
-  /* remove path if there's no nexthop for the path */
-  if (pn->nexthop_list->count != 0)
-    return;
-  linklist_remove (pn, rn->path_list);
-  linklist_delete (pn->nexthop_list);
-  XFREE (MTYPE_OSPF6_ROUTE, pn);
+struct ospf6_route *
+ospf6_route_head (struct ospf6_route_table *table)
+{
+  struct route_node *node;
+  struct ospf6_route *route;
 
-  /* remove route if there's no path for the route */
-  if (rn->path_list->count != 0)
-    return;
-  route_node->info = NULL;
-  linklist_delete (rn->path_list);
-  XFREE (MTYPE_OSPF6_ROUTE, rn);
+  node = route_top (table->table);
+  if (node == NULL)
+    return NULL;
+
+  /* skip to the real existing entry */
+  while (node && node->info == NULL)
+    node = route_next (node);
+  if (node == NULL)
+    return NULL;
+
+  route_unlock_node (node);
+  assert (node->info);
+
+  route = (struct ospf6_route *) node->info;
+  assert (route->prev == NULL);
+  ospf6_route_lock (route);
+  return route;
+}
+
+struct ospf6_route *
+ospf6_route_next (struct ospf6_route *route)
+{
+  struct ospf6_route *next = route->next;
+
+  ospf6_route_unlock (route);
+  if (next)
+    ospf6_route_lock (next);
+
+  return next;
+}
+
+struct ospf6_route *
+ospf6_route_best_next (struct ospf6_route *route)
+{
+  struct route_node *rnode;
+  struct ospf6_route *next;
+
+  rnode = route->rnode;
+  route_lock_node (rnode);
+  rnode = route_next (rnode);
+  while (rnode && rnode->info == NULL)
+    rnode = route_next (rnode);
+  if (rnode == NULL)
+    return NULL;
+  route_unlock_node (rnode);
+
+  assert (rnode->info);
+  next = (struct ospf6_route *) rnode->info;
+  ospf6_route_unlock (route);
+  ospf6_route_lock (next);
+  return next;
+}
+
+/* Macro version of check_bit (). */
+#define CHECK_BIT(X,P) ((((u_char *)(X))[(P) / 8]) >> (7 - ((P) % 8)) & 1)
+
+struct ospf6_route *
+ospf6_route_match_head (struct prefix *prefix,
+                        struct ospf6_route_table *table)
+{
+  struct route_node *node;
+  struct ospf6_route *route;
+
+  /* Walk down tree. */
+  node = table->table->top;
+  while (node && node->p.prefixlen < prefix->prefixlen &&
+	 prefix_match (&node->p, prefix))
+    node = node->link[CHECK_BIT(&prefix->u.prefix, node->p.prefixlen)];
+
+  if (node)
+    route_lock_node (node);
+  while (node && node->info == NULL)
+    node = route_next (node);
+  if (node == NULL)
+    return NULL;
+  route_unlock_node (node);
+
+  if (! prefix_match (prefix, &node->p))
+    return NULL;
+
+  route = node->info;
+  ospf6_route_lock (route);
+  return route;
+}
+
+struct ospf6_route *
+ospf6_route_match_next (struct prefix *prefix,
+                        struct ospf6_route *route)
+{
+  struct ospf6_route *next;
+
+  next = ospf6_route_next (route);
+  if (next && ! prefix_match (prefix, &next->prefix))
+    {
+      ospf6_route_unlock (next);
+      next = NULL;
+    }
+
+  return next;
 }
 
 void
 ospf6_route_remove_all (struct ospf6_route_table *table)
 {
-  struct ospf6_route_req request;
-
-  for (ospf6_route_head (&request, table); ! ospf6_route_end (&request);
-       ospf6_route_next (&request))
-    ospf6_route_remove (&request, table);
+  struct ospf6_route *route;
+  for (route = ospf6_route_head (table); route;
+       route = ospf6_route_next (route))
+    ospf6_route_remove (route, table);
 }
 
-
 struct ospf6_route_table *
-ospf6_route_table_create (char *name)
+ospf6_route_table_create ()
 {
-  int i;
   struct ospf6_route_table *new;
-
   new = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_table));
-  snprintf (new->name, sizeof (new->name), "%s", name);
-
   new->table = route_table_init ();
-  for (i = 0; i < 3; i++)
-    new->hook_list[i] = linklist_create ();
-
   return new;
 }
 
 void
 ospf6_route_table_delete (struct ospf6_route_table *table)
 {
-  int i;
-
   ospf6_route_remove_all (table);
   route_table_finish (table->table);
-  for (i = 0; i < 3; i++)
-    linklist_delete (table->hook_list[i]);
   XFREE (MTYPE_OSPF6_ROUTE, table);
 }
 
-void
-ospf6_route_table_freeze (struct ospf6_route_table *route_table)
-{
-  if (IS_OSPF6_DUMP_ROUTE)
-    zlog_info ("ROUTE: Table freeze: %s", route_table->name);
-  assert (route_table->freeze == 0);
-  route_table->freeze = 1;
-}
-
-void
-ospf6_route_table_thaw (struct ospf6_route_table *route_table)
-{
-  struct route_node *node;
-  struct linklist_node pnode;
-  struct linklist_node nnode;
-
-  struct ospf6_route_node   *rn;
-  struct ospf6_path_node    *pn;
-  struct ospf6_nexthop_node *nn;
-
-  struct ospf6_route_req request;
-
-  if (IS_OSPF6_DUMP_ROUTE)
-    zlog_info ("ROUTE: Table thaw: %s", route_table->name);
-
-  assert (route_table->freeze == 1);
-  route_table->freeze = 0;
-
-  for (node = route_top (route_table->table); node;
-       node = route_next (node))
-    {
-      rn = node->info;
-      if (! rn)
-        continue;
-
-      for (linklist_head (rn->path_list, &pnode);
-           ! linklist_end (&pnode);
-           linklist_next (&pnode))
-        {
-          pn = pnode.data;
-
-          for (linklist_head (pn->nexthop_list, &nnode);
-               ! linklist_end (&nnode);
-               linklist_next (&nnode))
-            {
-              nn = nnode.data;
-
-              /* if the add and remove flag set without change flag,
-                 do nothing with this route */
-              if (! CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE) &&
-                  CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD) &&
-                  CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE))
-                {
-                  nn->flag = 0;
-                  continue;
-                }
-
-              memset (&request, 0, sizeof (request));
-              memcpy (&request.route, &rn->route, sizeof (rn->route));
-              memcpy (&request.path, &pn->path, sizeof (pn->path));
-              memcpy (&request.nexthop, &nn->nexthop, sizeof (nn->nexthop));
-
-              if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_ADD) ||
-                  CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_CHANGE))
-                ospf6_route_add (&request, route_table);
-              else if (CHECK_FLAG (nn->flag, OSPF6_ROUTE_FLAG_REMOVE))
-                ospf6_route_remove (&request, route_table);
-            }
-        }
-    }
-}
 
 
 /* VTY commands */
+void
+ospf6_route_show (struct vty *vty, struct ospf6_route *route)
+{
+  int i;
+  char destination[64], nexthop[64];
+  char duration[16], ifname[IFNAMSIZ];
+  struct timeval now, res;
+
+  gettimeofday (&now, (struct timezone *) NULL);
+  timersub (&now, &route->changed, &res);
+  timerstring (&res, duration, sizeof (duration));
+
+  /* destination */
+  if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
+    ospf6_linkstate_prefix2str (&route->prefix, destination,
+                                sizeof (destination));
+  else if (route->type == OSPF6_DEST_TYPE_ROUTER)
+    inet_ntop (route->prefix.family, &route->prefix.u.prefix,
+               destination, sizeof (destination));
+  else
+    prefix2str (&route->prefix, destination, sizeof (destination));
+
+  /* nexthop */
+  inet_ntop (AF_INET6, &route->nexthop[0].address, nexthop,
+             sizeof (nexthop));
+  if (! if_indextoname (route->nexthop[0].ifindex, ifname))
+    snprintf (ifname, sizeof (ifname), "%d", route->nexthop[0].ifindex);
+
+  vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s",
+           (ospf6_route_is_best (route) ? '*' : ' '),
+           OSPF6_DEST_TYPE_SUBSTR (route->type),
+           OSPF6_PATH_TYPE_SUBSTR (route->path.type),
+           destination, nexthop, ifname, duration, VTY_NEWLINE);
+
+  for (i = 1; ospf6_nexthop_is_set (&route->nexthop[i]) &&
+       i < OSPF6_MULTI_PATH_LIMIT; i++)
+    {
+      /* nexthop */
+      inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
+                 sizeof (nexthop));
+      if (! if_indextoname (route->nexthop[i].ifindex, ifname))
+        snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex);
+
+      vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s",
+               ' ', "", "", "", nexthop, ifname, "", VTY_NEWLINE);
+    }
+}
 
 void
-ospf6_route_show (struct vty *vty, struct ospf6_route_node *rn)
+ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route)
 {
-  struct linklist_node pnode;
-  struct linklist_node nnode;
-  struct ospf6_path_node    *pn;
-  struct ospf6_nexthop_node *nn;
-
+  char destination[64], nexthop[64], ifname[IFNAMSIZ];
+  char area_id[16], id[16], adv_router[16], capa[16], options[16];
   struct timeval now, res;
   char duration[16];
-
-  u_int pc = 0;
-  u_int nc = 0;
-#define HEAD (pc == 0 && nc == 0)
-
-  char prefix[64], nexthop[64], ifname[IFNAMSIZ];
+  int i;
 
   gettimeofday (&now, (struct timezone *) NULL);
 
   /* destination */
-  if (rn->route.prefix.family == AF_INET ||
-      rn->route.prefix.family == AF_INET6)
-    prefix2str (&rn->route.prefix, prefix, sizeof (prefix));
+  if (route->type == OSPF6_DEST_TYPE_LINKSTATE)
+    ospf6_linkstate_prefix2str (&route->prefix, destination,
+                                sizeof (destination));
+  else if (route->type == OSPF6_DEST_TYPE_ROUTER)
+    inet_ntop (route->prefix.family, &route->prefix.u.prefix,
+               destination, sizeof (destination));
   else
-    prefix_ls2str (&rn->route.prefix, prefix, sizeof (prefix));
+    prefix2str (&route->prefix, destination, sizeof (destination));
+  vty_out (vty, "Destination: %s%s", destination, VTY_NEWLINE);
 
-  for (linklist_head (rn->path_list, &pnode); ! linklist_end (&pnode);
-       linklist_next (&pnode))
+  /* destination type */
+  vty_out (vty, "Destination type: %s%s",
+           OSPF6_DEST_TYPE_NAME (route->type),
+           VTY_NEWLINE);
+
+  /* Time */
+  timersub (&now, &route->installed, &res);
+  timerstring (&res, duration, sizeof (duration));
+  vty_out (vty, "Installed Time: %s ago%s", duration, VTY_NEWLINE);
+
+  timersub (&now, &route->changed, &res);
+  timerstring (&res, duration, sizeof (duration));
+  vty_out (vty, "  Changed Time: %s ago%s", duration, VTY_NEWLINE);
+
+  /* Debugging info */
+  vty_out (vty, "Lock: %d Flags: %s%s%s%s%s", route->lock,
+           (CHECK_FLAG (route->flag, OSPF6_ROUTE_BEST)   ? "B" : "-"),
+           (CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD)    ? "A" : "-"),
+           (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE) ? "R" : "-"),
+           (CHECK_FLAG (route->flag, OSPF6_ROUTE_CHANGE) ? "C" : "-"),
+           VTY_NEWLINE);
+  vty_out (vty, "Memory: prev: %p this: %p next: %p%s",
+           route->prev, route, route->next, VTY_NEWLINE);
+
+  /* Path section */
+
+  /* Area-ID */
+  inet_ntop (AF_INET, &route->path.area_id, area_id, sizeof (area_id));
+  vty_out (vty, "Associated Area: %s%s", area_id, VTY_NEWLINE);
+
+  /* Path type */
+  vty_out (vty, "Path Type: %s%s",
+           OSPF6_PATH_TYPE_NAME (route->path.type), VTY_NEWLINE);
+
+  /* LS Origin */
+  inet_ntop (AF_INET, &route->path.origin.id, id, sizeof (id));
+  inet_ntop (AF_INET, &route->path.origin.adv_router, adv_router,
+             sizeof (adv_router));
+  vty_out (vty, "LS Origin: %s Id: %s Adv: %s%s",
+           OSPF6_LSTYPE_NAME (route->path.origin.type),
+           id, adv_router, VTY_NEWLINE);
+
+  /* Options */
+  ospf6_options_printbuf (route->path.options, options, sizeof (options));
+  vty_out (vty, "Options: %s%s", options, VTY_NEWLINE);
+
+  /* Router Bits */
+  ospf6_capability_printbuf (route->path.router_bits, capa, sizeof (capa));
+  vty_out (vty, "Router Bits: %s%s", capa, VTY_NEWLINE);
+
+  /* Prefix Options */
+  vty_out (vty, "Prefix Options: xxx%s", VTY_NEWLINE);
+
+  /* Metrics */
+  vty_out (vty, "Metric Type: %d%s", route->path.metric_type,
+           VTY_NEWLINE);
+  vty_out (vty, "Metric: %d (%d)%s",
+           route->path.cost, route->path.cost_e2, VTY_NEWLINE);
+
+  /* Nexthops */
+  vty_out (vty, "Nexthop:%s", VTY_NEWLINE);
+  for (i = 0; ospf6_nexthop_is_set (&route->nexthop[i]) &&
+       i < OSPF6_MULTI_PATH_LIMIT; i++)
     {
-      pn = pnode.data;
-
-      for (linklist_head (pn->nexthop_list, &nnode); ! linklist_end (&nnode);
-           linklist_next (&nnode))
-        {
-          nn = nnode.data;
-
-          inet_ntop (AF_INET6, &nn->nexthop.address, nexthop,
-                     sizeof (nexthop));
-          if (! if_indextoname (nn->nexthop.ifindex, ifname))
-            snprintf (ifname, sizeof (ifname), "%d", nn->nexthop.ifindex);
-
-          ospf6_timeval_sub (&now, &nn->installed, &res);
-          ospf6_timeval_string_summary (&res, duration, sizeof (duration));
-
-          vty_out (vty, "%c%1s %2s %-30s %-25s %6s %s%s",
-                   (HEAD ? '*' : ' '),
-                   DTYPE_ABNAME (rn->route.type),
-                   PTYPE_ABNAME (pn->path.type),
-                   prefix, nexthop, ifname, duration, VTY_NEWLINE);
-
-          nc++;
-        }
-      pc++;
+      /* nexthop */
+      inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop,
+                 sizeof (nexthop));
+      if (! if_indextoname (route->nexthop[i].ifindex, ifname))
+        snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex);
+      vty_out (vty, "  %s %s%s", nexthop, ifname, VTY_NEWLINE);
     }
+  vty_out (vty, "%s", VTY_NEWLINE);
 }
 
 void
-ospf6_route_show_detail (struct vty *vty, struct ospf6_route_node *rn)
+ospf6_route_show_table_summary (struct vty *vty,
+                                struct ospf6_route_table *table)
 {
-  struct linklist_node pnode;
-  struct linklist_node nnode;
-  struct ospf6_path_node    *pn;
-  struct ospf6_nexthop_node *nn;
+  struct ospf6_route *route, *prev = NULL;
+  int i, pathtype[OSPF6_PATH_TYPE_MAX];
+  int number = 0;
+  int nhinval = 0, ecmp = 0;
+  int multipath = 0, destination = 0;
+  int desttype = 0, desttype_mismatch = 0;
 
-  u_int pc = 0;
-  u_int nc = 0;
+  for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++)
+    pathtype[i] = 0;
 
-  char prefix[64], nexthop[64], ifname[IFNAMSIZ];
-  char area_id[16], type[16], id[16], adv[16];
-  char capa[64];
-
-  /* destination */
-  if (rn->route.prefix.family == AF_INET ||
-      rn->route.prefix.family == AF_INET6)
-    prefix2str (&rn->route.prefix, prefix, sizeof (prefix));
-  else
-    prefix_ls2str (&rn->route.prefix, prefix, sizeof (prefix));
-
-  vty_out (vty, "%s%s%s", VTY_NEWLINE, prefix, VTY_NEWLINE);
-  vty_out (vty, "    Destination Type: %s%s",
-           DTYPE_NAME (rn->route.type), VTY_NEWLINE);
-
-  for (linklist_head (rn->path_list, &pnode); ! linklist_end (&pnode);
-       linklist_next (&pnode))
+  for (route = ospf6_route_head (table); route;
+       route = ospf6_route_next (route))
     {
-      pn = pnode.data;
+      if (desttype == 0)
+        desttype = route->type;
+      else if (desttype != route->type)
+        desttype_mismatch++;
 
-      inet_ntop (AF_INET, &pn->path.area_id, area_id, sizeof (area_id));
-      ospf6_lsa_type_string (pn->path.origin.type, type, sizeof (type));
-      inet_ntop (AF_INET, &pn->path.origin.id, id, sizeof (id));
-      inet_ntop (AF_INET, &pn->path.origin.adv_router, adv, sizeof (adv));
-      ospf6_options_string (pn->path.capability, capa, sizeof (capa));
+      if (prev == NULL || ! ospf6_route_is_same (prev, route))
+        destination++;
+      else
+        multipath++;
 
-      vty_out (vty, "  Path:%s", VTY_NEWLINE);
-      vty_out (vty, "    Associated Area: %s%s", area_id, VTY_NEWLINE);
-      vty_out (vty, "    LS Origin: %s ID: %s Adv: %s%s",
-               type, id, adv, VTY_NEWLINE);
-      vty_out (vty, "    Path Type: %s%s",
-               PTYPE_NAME (pn->path.type), VTY_NEWLINE);
-      vty_out (vty, "    Metric Type: %d%s",
-               pn->path.metric_type, VTY_NEWLINE);
-      vty_out (vty, "    Cost: Type-1: %lu Type-2: %lu%s",
-               (u_long) pn->path.cost, (u_long) pn->path.cost_e2,
-               VTY_NEWLINE);
-      vty_out (vty, "    Router Bits: %s|%s|%s|%s%s",
-               (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_W) ?
-                "W" : "-"),
-               (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_V) ?
-                "V" : "-"),
-               (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_E) ?
-                "E" : "-"),
-               (CHECK_FLAG (pn->path.router_bits, OSPF6_ROUTER_LSA_BIT_B) ?
-                "B" : "-"), VTY_NEWLINE);
-      vty_out (vty, "    Optional Capabilities: %s%s", capa, VTY_NEWLINE);
-      vty_out (vty, "    Prefix Options: %s%s", "xxx", VTY_NEWLINE);
-      vty_out (vty, "    Next Hops:%s", VTY_NEWLINE);
+      if (! ospf6_nexthop_is_set (&route->nexthop[0]))
+        nhinval++;
+      else if (ospf6_nexthop_is_set (&route->nexthop[1]))
+        ecmp++;
 
-      for (linklist_head (pn->nexthop_list, &nnode); ! linklist_end (&nnode);
-           linklist_next (&nnode))
-        {
-          nn = nnode.data;
+      if (prev == NULL || ! ospf6_route_is_same (prev, route))
+        pathtype[route->path.type]++;
 
-          inet_ntop (AF_INET6, &nn->nexthop.address, nexthop,
-                     sizeof (nexthop));
-          if (! if_indextoname (nn->nexthop.ifindex, ifname))
-            snprintf (ifname, sizeof (ifname), "%d", nn->nexthop.ifindex);
-
-          vty_out (vty, "       %c%s%%%s%s",
-                   (HEAD ? '*' : ' '), nexthop, ifname, VTY_NEWLINE);
-
-          nc++;
-        }
-      pc++;
+      number++;
+      prev = route;
     }
-  vty_out (vty, "%s", VTY_NEWLINE);
+
+  assert (number == table->count);
+  vty_out (vty, "Number of Destination: %d (%d routes)%s",
+           destination, number, VTY_NEWLINE);
+  if (multipath)
+    vty_out (vty, "  Number of Multi-path: %d%s", multipath, VTY_NEWLINE);
+  if (desttype_mismatch)
+    vty_out (vty, "  Number of Different Dest-type: %d%s",
+             desttype_mismatch, VTY_NEWLINE);
+  if (ecmp)
+    vty_out (vty, "  Number of Equal Cost Multi Path: %d%s",
+             ecmp, VTY_NEWLINE);
+  if (ecmp)
+    vty_out (vty, "  Number of Invalid Nexthop: %d%s",
+             nhinval, VTY_NEWLINE);
+
+  for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++)
+    {
+      if (pathtype[i])
+        vty_out (vty, "  Number of %s routes: %d%s",
+                 OSPF6_PATH_TYPE_NAME (i), pathtype[i], VTY_NEWLINE);
+    }
 }
 
 int
 ospf6_route_table_show (struct vty *vty, int argc, char **argv,
                         struct ospf6_route_table *table)
 {
+  unsigned char flag = 0;
+#define MATCH      0x01
+#define DETAIL     0x02
+#define PREFIX     0x04
+#define SUMMARY    0x08
   int i, ret;
-  unsigned long ret_ul;
-  char *endptr;
-  struct prefix prefix;
-  int detail = 0;
-  int arg_ipv6  = 0;
-  int arg_ipv4  = 0;
-  int arg_digit = 0;
-  struct prefix_ipv6 *p6 = (struct prefix_ipv6 *) &prefix;
-  struct prefix_ls   *pl = (struct prefix_ls *) &prefix;
-  struct route_node *node;
-
-  u_int route_count = 0;
-  u_int path_count = 0;
-  u_int route_redundant = 0;
+  struct prefix prefix, *p;
+  struct ospf6_route *route;
 
   memset (&prefix, 0, sizeof (struct prefix));
 
   for (i = 0; i < argc; i++)
     {
+      /* set "detail" */
+      if (! strcmp (argv[i], "summary"))
+        {
+          SET_FLAG (flag, SUMMARY);
+          continue;
+        }
+
+      /* set "detail" */
       if (! strcmp (argv[i], "detail"))
         {
-          detail++;
-          break;
+          SET_FLAG (flag, DETAIL);
+          continue;
         }
 
-      if (! arg_ipv6 && ! arg_ipv4 && ! arg_digit)
+      /* set "match" */
+      if (! strcmp (argv[i], "match"))
         {
-
-          if ((ret = inet_pton (AF_INET6, argv[i], &p6->prefix)) == 1)
-            {
-              p6->family = AF_INET6;
-              p6->prefixlen = 128;
-              arg_ipv6++;
-              continue;
-            }
-          else if ((ret = inet_pton (AF_INET, argv[i], &pl->adv_router)) == 1)
-            {
-              pl->family = AF_UNSPEC;
-              pl->prefixlen = 64; /* xxx */
-              arg_ipv4++;
-              continue;
-            }
-          else
-            {
-              ret_ul = strtoul (argv[i], &endptr, 10);
-              if (*endptr == '\0')
-                {
-                  pl->adv_router.s_addr = htonl (ret_ul);
-                  pl->family = AF_UNSPEC;
-                  pl->prefixlen = 64; /* xxx */
-                  arg_digit++;
-                  continue;
-                }
-              else
-                {
-                  vty_out (vty, "Malformed argument: %s%s",
-                           argv[i], VTY_NEWLINE);
-                  return CMD_SUCCESS;
-                }
-            }
+          SET_FLAG (flag, MATCH);
+          continue;
         }
 
-      if (arg_ipv4 || arg_digit)
+      if (prefix.family)
         {
-          if ((ret = inet_pton (AF_INET, argv[i], &pl->id)) == 1)
-            {
-              arg_ipv4++;
-            }
-          else
-            {
-              ret_ul = strtoul (argv[i], &endptr, 10);
-              if (*endptr == '\0')
-                {
-                  pl->id.s_addr = htonl (ret_ul);
-                  arg_digit++;
-                }
-              else
-                {
-                  vty_out (vty, "Malformed argument: %s%s",
-                           argv[i], VTY_NEWLINE);
-                  return CMD_SUCCESS;
-                }
-            }
+          vty_out (vty, "Invalid argument: %s%s", argv[i], VTY_NEWLINE);
+          return CMD_SUCCESS;
         }
+
+      ret = str2prefix (argv[i], &prefix);
+      if (ret != 1 || prefix.family != AF_INET6)
+        {
+          vty_out (vty, "Malformed argument: %s%s", argv[i], VTY_NEWLINE);
+          return CMD_SUCCESS;
+        }
+
+      if (strchr (argv[i], '/'))
+        SET_FLAG (flag, PREFIX);
     }
 
-  if (arg_ipv4 || arg_ipv6 || arg_digit)
+  /* Give summary of this route table */
+  if (CHECK_FLAG (flag, SUMMARY))
     {
-      node = route_node_match (table->table, &prefix);
-      if (node && node->info)
-        ospf6_route_show_detail (vty, node->info);
+      ospf6_route_show_table_summary (vty, table);
       return CMD_SUCCESS;
     }
 
-  if (! detail)
+  /* Give exact prefix-match route */
+  if (prefix.family && ! CHECK_FLAG (flag, MATCH))
     {
-      vty_out (vty, "%s%c%1s %2s %-30s %-25s %6s%s", VTY_NEWLINE,
-               ' ', " ", " ", "Destination", "Gateway", "I/F", VTY_NEWLINE);
-      vty_out (vty, "---------------------------%s", VTY_NEWLINE);
+      /* If exact address, give best matching route */
+      if (! CHECK_FLAG (flag, PREFIX))
+        route = ospf6_route_lookup_bestmatch (&prefix, table);
+      else
+        route = ospf6_route_lookup (&prefix, table);
+
+      if (route)
+        {
+          ospf6_route_lock (route);
+          p = &route->prefix;
+        }
+
+      while (route && ospf6_route_is_prefix (p, route))
+        {
+          /* Seaching an entry will always display details */
+          if (route)
+            ospf6_route_show_detail (vty, route);
+
+          route = ospf6_route_next (route);
+        }
+
+      return CMD_SUCCESS;
     }
 
-  for (node = route_top (table->table); node; node = route_next (node))
+  if (prefix.family == 0)
+    route = ospf6_route_head (table);
+  else
+    route = ospf6_route_match_head (&prefix, table);
+
+  while (route)
     {
-      struct ospf6_route_node *route = node->info;
-
-      if (! route)
-        continue;
-
-      if (detail)
+      if (CHECK_FLAG (flag, DETAIL))
         ospf6_route_show_detail (vty, route);
       else
         ospf6_route_show (vty, route);
 
-      route_count++;
-      path_count += route->path_list->count;
-      if (route->path_list->count > 1)
-        route_redundant++;
+      if (prefix.family == 0)
+        route = ospf6_route_next (route);
+      else
+        route = ospf6_route_match_next (&prefix, route);
     }
 
-  vty_out (vty, "===========%s", VTY_NEWLINE);
-  vty_out (vty, "Route: %d Path: %d Redundant: %d%s",
-           route_count, path_count, route_redundant, VTY_NEWLINE);
-
   return CMD_SUCCESS;
 }
 
+
+int
+ospf6_lsentry_table_show (struct vty *vty, int argc, char **argv,
+                          struct ospf6_route_table *table)
+{
+  unsigned char flag = 0;
+#define MATCH      0x01
+#define DETAIL     0x02
+  int i, ret;
+  struct prefix adv_router, id, prefix;
+  struct ospf6_route *route;
+
+  memset (&adv_router, 0, sizeof (struct prefix));
+  memset (&id, 0, sizeof (struct prefix));
+
+  for (i = 0; i < argc; i++)
+    {
+      /* set "detail" */
+      if (! strcmp (argv[i], "detail"))
+        {
+          SET_FLAG (flag, DETAIL);
+          continue;
+        }
+
+      /* set "match" */
+      if (! strcmp (argv[i], "match"))
+        {
+          SET_FLAG (flag, MATCH);
+          continue;
+        }
+
+      if (adv_router.family && id.family)
+        {
+          vty_out (vty, "Invalid argument: %s%s", argv[i], VTY_NEWLINE);
+          return CMD_SUCCESS;
+        }
+
+      if (adv_router.family == 0)
+        {
+          ret = str2prefix (argv[i], &adv_router);
+          if (ret != 1)
+            {
+              if (! strcmp (argv[i], "*"))
+                {
+                  adv_router.family = AF_INET;
+                  adv_router.prefixlen = 0;
+                  ret = 1;
+                }
+            }
+          if (ret != 1)
+            {
+              vty_out (vty, "Invalid Router-ID: %s%s", argv[i], VTY_NEWLINE);
+              return CMD_SUCCESS;
+            }
+        }
+      else if (id.family == 0)
+        {
+          unsigned long val;
+          char *endptr;
+
+          ret = str2prefix (argv[i], &id);
+          if (ret != 1)
+            {
+              val = strtoul (argv[i], &endptr, 0);
+              if (val != ULONG_MAX && *endptr == '\0')
+                {
+                  id.u.prefix4.s_addr = val;
+                  ret = 1;
+                }
+            }
+
+          if (ret != 1)
+            {
+              vty_out (vty, "Invalid Link state ID: %s%s", argv[i],
+                       VTY_NEWLINE);
+              return CMD_WARNING;
+            }
+        }
+    }
+
+  /* Encode to linkstate prefix */
+  if (adv_router.family)
+    {
+      if (adv_router.prefixlen == 0 &&
+          id.family && id.prefixlen != IPV4_MAX_BITLEN)
+        {
+          vty_out (vty, "Specifying Link State ID by prefix is not allowed%s"
+                   "when specifying Router-ID as wildcard%s",
+                   VTY_NEWLINE, VTY_NEWLINE);
+          return CMD_SUCCESS;
+        }
+      else if (adv_router.prefixlen != 0 &&
+               adv_router.prefixlen != IPV4_MAX_BITLEN && id.family)
+        {
+          vty_out (vty, "Specifying Link State ID is not allowed%s"
+                   "when specifying Router-ID by prefix%s",
+                   VTY_NEWLINE, VTY_NEWLINE);
+          return CMD_SUCCESS;
+        }
+
+      if (adv_router.prefixlen == 0)
+        ospf6_linkstate_prefix (0, id.u.prefix4.s_addr, &prefix);
+      else if (adv_router.prefixlen != IPV4_MAX_BITLEN)
+        {
+          ospf6_linkstate_prefix (adv_router.u.prefix4.s_addr, 0, &prefix);
+          prefix.prefixlen = adv_router.prefixlen;
+          SET_FLAG (flag, MATCH);
+        }
+      else
+        {
+          ospf6_linkstate_prefix (adv_router.u.prefix4.s_addr,
+                                  id.u.prefix4.s_addr, &prefix);
+          prefix.prefixlen = adv_router.prefixlen + id.prefixlen;
+          if (prefix.prefixlen != 64)
+            SET_FLAG (flag, MATCH);
+        }
+    }
+
+  /* give exact match entry */
+  if (adv_router.family && adv_router.prefixlen == IPV4_MAX_BITLEN &&
+      id.family && id.prefixlen == IPV4_MAX_BITLEN)
+    {
+      route = ospf6_route_lookup (&prefix, table);
+      if (route)
+        ospf6_route_show_detail (vty, route);
+      return CMD_SUCCESS;
+    }
+
+  if (CHECK_FLAG (flag, MATCH))
+    route = ospf6_route_match_head (&prefix, table);
+  else
+    route = ospf6_route_head (table);
+
+  while (route)
+    {
+      if (! adv_router.family ||
+          (CHECK_FLAG (flag, MATCH) &&
+           prefix_match (&prefix, &route->prefix)) ||
+          (adv_router.prefixlen == 0 && id.family &&
+           ospf6_linkstate_prefix_id (&prefix) ==
+           ospf6_linkstate_prefix_id (&route->prefix)))
+        {
+          if (CHECK_FLAG (flag, DETAIL))
+            ospf6_route_show_detail (vty, route);
+          else
+            ospf6_route_show (vty, route);
+        }
+
+      if (CHECK_FLAG (flag, MATCH))
+        route = ospf6_route_match_next (&prefix, route);
+      else
+        route = ospf6_route_next (route);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_ospf6_route,
+       debug_ospf6_route_cmd,
+       "debug ospf6 route (table|intra-area|inter-area)",
+       DEBUG_STR
+       OSPF6_STR
+       "Debug route table calculation\n"
+       "Debug detail\n"
+       "Debug intra-area route calculation\n"
+       "Debug inter-area route calculation\n"
+       )
+{
+  unsigned char level = 0;
+
+  if (! strncmp (argv[0], "table", 5))
+    level = OSPF6_DEBUG_ROUTE_TABLE;
+  else if (! strncmp (argv[0], "intra", 5))
+    level = OSPF6_DEBUG_ROUTE_INTRA;
+  else if (! strncmp (argv[0], "inter", 5))
+    level = OSPF6_DEBUG_ROUTE_INTER;
+  OSPF6_DEBUG_ROUTE_ON (level);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ospf6_route,
+       no_debug_ospf6_route_cmd,
+       "no debug ospf6 route (table|intra-area|inter-area)",
+       NO_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Debug route table calculation\n"
+       "Debug intra-area route calculation\n")
+{
+  unsigned char level = 0;
+
+  if (! strncmp (argv[0], "table", 5))
+    level = OSPF6_DEBUG_ROUTE_TABLE;
+  else if (! strncmp (argv[0], "intra", 5))
+    level = OSPF6_DEBUG_ROUTE_INTRA;
+  else if (! strncmp (argv[0], "inter", 5))
+    level = OSPF6_DEBUG_ROUTE_INTER;
+  OSPF6_DEBUG_ROUTE_OFF (level);
+  return CMD_SUCCESS;
+}
+
+int
+config_write_ospf6_debug_route (struct vty *vty)
+{
+  if (IS_OSPF6_DEBUG_ROUTE (TABLE))
+    vty_out (vty, "debug ospf6 route table%s", VTY_NEWLINE);
+  if (IS_OSPF6_DEBUG_ROUTE (INTRA))
+    vty_out (vty, "debug ospf6 route intra-area%s", VTY_NEWLINE);
+  if (IS_OSPF6_DEBUG_ROUTE (INTER))
+    vty_out (vty, "debug ospf6 route inter-area%s", VTY_NEWLINE);
+  return 0;
+}
+
+void
+install_element_ospf6_debug_route ()
+{
+  install_element (ENABLE_NODE, &debug_ospf6_route_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf6_route_cmd);
+  install_element (CONFIG_NODE, &debug_ospf6_route_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf6_route_cmd);
+}
+
+
+
diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h
index 71b2562..834774c 100644
--- a/ospf6d/ospf6_route.h
+++ b/ospf6d/ospf6_route.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -22,40 +22,49 @@
 #ifndef OSPF6_ROUTE_H
 #define OSPF6_ROUTE_H
 
-#include "ospf6_hook.h"
-#include "ospf6_linklist.h"
+#define OSPF6_MULTI_PATH_LIMIT    4
 
-struct ospf6_route_table
+/* Debug option */
+extern unsigned char conf_debug_ospf6_route;
+#define OSPF6_DEBUG_ROUTE_TABLE   0x01
+#define OSPF6_DEBUG_ROUTE_INTRA   0x02
+#define OSPF6_DEBUG_ROUTE_INTER   0x04
+#define OSPF6_DEBUG_ROUTE_ON(level) \
+  (conf_debug_ospf6_route |= (level))
+#define OSPF6_DEBUG_ROUTE_OFF(level) \
+  (conf_debug_ospf6_route &= ~(level))
+#define IS_OSPF6_DEBUG_ROUTE(e) \
+  (conf_debug_ospf6_route & OSPF6_DEBUG_ROUTE_ ## e)
+
+/* Nexthop */
+struct ospf6_nexthop
 {
-  char name[128];
+  /* Interface index */
+  unsigned int ifindex;
 
-  int freeze;
-
-  /* radix tree */
-  struct route_table *table;
-
-  /* list of hooks */
-  struct linklist *hook_list[3];
-  void (*hook_add) (void *);
-  void (*hook_change) (void *);
-  void (*hook_remove) (void *);
-
-  u_int32_t route_id;
+  /* IP address, if any */
+  struct in6_addr address;
 };
 
-
-
-struct ospf6_route
-{
-  /* Destination ID */
-  struct prefix prefix;
-
-  /* Destination Type */
-  u_char type;
-};
+#define ospf6_nexthop_is_set(x)                                \
+  ((x)->ifindex || ! IN6_IS_ADDR_UNSPECIFIED (&(x)->address))
+#define ospf6_nexthop_is_same(a,b)                             \
+  ((a)->ifindex == (b)->ifindex &&                            \
+   IN6_ARE_ADDR_EQUAL (&(a)->address, &(b)->address))
+#define ospf6_nexthop_clear(x)                                \
+  do {                                                        \
+    (x)->ifindex = 0;                                         \
+    memset (&(x)->address, 0, sizeof (struct in6_addr));      \
+  } while (0)
+#define ospf6_nexthop_copy(a, b)                              \
+  do {                                                        \
+    (a)->ifindex = (b)->ifindex;                              \
+    memcpy (&(a)->address, &(b)->address,                     \
+            sizeof (struct in6_addr));                        \
+  } while (0)
 
 /* Path */
-struct ls_origin
+struct ospf6_ls_origin
 {
   u_int16_t type;
   u_int32_t id;
@@ -65,13 +74,13 @@
 struct ospf6_path
 {
   /* Link State Origin */
-  struct ls_origin origin;
+  struct ospf6_ls_origin origin;
 
   /* Router bits */
   u_char router_bits;
 
   /* Optional Capabilities */
-  u_char capability[3];
+  u_char options[3];
 
   /* Prefix Options */
   u_char prefix_options;
@@ -88,122 +97,165 @@
   u_int32_t cost_e2;
 };
 
-/* Nexthop */
-struct ospf6_nexthop
+#define OSPF6_PATH_TYPE_NONE       0
+#define OSPF6_PATH_TYPE_INTRA      1
+#define OSPF6_PATH_TYPE_INTER      2
+#define OSPF6_PATH_TYPE_EXTERNAL1  3
+#define OSPF6_PATH_TYPE_EXTERNAL2  4
+#define OSPF6_PATH_TYPE_MAX        5
+
+#include "prefix.h"
+#include "table.h"
+
+struct ospf6_route
 {
-  /* Interface index */
-  unsigned int ifindex;
+  struct route_node *rnode;
 
-  /* IP address, if any */
-  struct in6_addr address;
-};
+  struct ospf6_route *prev;
+  struct ospf6_route *next;
 
-struct ospf6_route_node
-{
-  struct ospf6_route_table *table;
-  int count;
-  u_int32_t route_id;
+  unsigned int lock;
 
-  struct route_node  *route_node;
-  struct ospf6_route  route;
-  struct linklist    *path_list;
-};
+  /* Destination Type */
+  u_char type;
 
-struct ospf6_path_node
-{
-  struct ospf6_route_node *route_node;
-  struct ospf6_path        path;
-  struct linklist         *nexthop_list;
-};
+  /* Destination ID */
+  struct prefix prefix;
 
-struct ospf6_nexthop_node
-{
-  int            flag;
+  /* Time */
   struct timeval installed;
+  struct timeval changed;
 
-  struct ospf6_path_node *path_node;
-  struct ospf6_nexthop    nexthop;
-};
+  /* flag */
+  u_char flag;
 
-struct ospf6_route_req
-{
-  struct ospf6_route_table *table;
-  struct route_node    *route_node;
-  struct linklist_node  path_lnode;
-  struct linklist_node  nexthop_lnode;
-  u_int32_t route_id;
+  /* path */
+  struct ospf6_path path;
 
-  int count;
-  struct ospf6_route   route;
-  struct ospf6_path    path;
-  struct ospf6_nexthop nexthop;
+  /* nexthop */
+  struct ospf6_nexthop nexthop[OSPF6_MULTI_PATH_LIMIT];
+
+  /* route option */
+  void *route_option;
 };
 
 #define OSPF6_DEST_TYPE_NONE       0
 #define OSPF6_DEST_TYPE_ROUTER     1
 #define OSPF6_DEST_TYPE_NETWORK    2
 #define OSPF6_DEST_TYPE_DISCARD    3
-#define OSPF6_DEST_TYPE_MAX        4
+#define OSPF6_DEST_TYPE_LINKSTATE  4
+#define OSPF6_DEST_TYPE_MAX        5
 
-#define OSPF6_PATH_TYPE_NONE       0
-#define OSPF6_PATH_TYPE_INTRA      1
-#define OSPF6_PATH_TYPE_INTER      2
-#define OSPF6_PATH_TYPE_EXTERNAL1  3
-#define OSPF6_PATH_TYPE_EXTERNAL2  4
-#define OSPF6_PATH_TYPE_ZOFFSET    5
-#define OSPF6_PATH_TYPE_ZSYSTEM  (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_SYSTEM)
-#define OSPF6_PATH_TYPE_ZKERNEL  (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_KERNEL)
-#define OSPF6_PATH_TYPE_ZCONNECT (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_CONNECT)
-#define OSPF6_PATH_TYPE_ZSTATIC  (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_STATIC)
-#define OSPF6_PATH_TYPE_ZRIP     (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_RIP)
-#define OSPF6_PATH_TYPE_ZRIPNG   (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_RIPNG)
-#define OSPF6_PATH_TYPE_ZOSPF    (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_OSPF)
-#define OSPF6_PATH_TYPE_ZOSPF6   (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_OSPF6)
-#define OSPF6_PATH_TYPE_ZBGP     (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_BGP)
-#define OSPF6_PATH_TYPE_MAX      (OSPF6_PATH_TYPE_ZOFFSET + ZEBRA_ROUTE_MAX)
+#define OSPF6_ROUTE_CHANGE      0x01
+#define OSPF6_ROUTE_ADD         0x02
+#define OSPF6_ROUTE_REMOVE      0x04
+#define OSPF6_ROUTE_BEST        0x08
 
-#define OSPF6_ROUTE_FLAG_ROUTE_CHANGE      0x01
-#define OSPF6_ROUTE_FLAG_PATH_CHANGE       0x02
-#define OSPF6_ROUTE_FLAG_ADD               0x04
-#define OSPF6_ROUTE_FLAG_REMOVE            0x08
-#define OSPF6_ROUTE_FLAG_CHANGE            0x10
+struct ospf6_route_table
+{
+  /* patricia tree */
+  struct route_table *table;
 
-int ospf6_route_lookup (struct ospf6_route_req *request,
-                        struct prefix *prefix,
-                        struct ospf6_route_table *table);
-void ospf6_route_head  (struct ospf6_route_req *request,
-                        struct ospf6_route_table *table);
-int  ospf6_route_end   (struct ospf6_route_req *request);
-void ospf6_route_next  (struct ospf6_route_req *request);
+  u_int32_t count;
 
-void ospf6_route_add (struct ospf6_route_req *, struct ospf6_route_table *);
-void ospf6_route_remove (struct ospf6_route_req *, struct ospf6_route_table *);
+  /* hooks */
+  void (*hook_add) (struct ospf6_route *);
+  void (*hook_change) (struct ospf6_route *);
+  void (*hook_remove) (struct ospf6_route *);
+};
+
+extern char *ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX];
+extern char *ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX];
+#define OSPF6_DEST_TYPE_NAME(x)                       \
+  (0 < (x) && (x) < OSPF6_DEST_TYPE_MAX ?             \
+   ospf6_dest_type_str[(x)] : ospf6_dest_type_str[0])
+#define OSPF6_DEST_TYPE_SUBSTR(x)                           \
+  (0 < (x) && (x) < OSPF6_DEST_TYPE_MAX ?                   \
+   ospf6_dest_type_substr[(x)] : ospf6_dest_type_substr[0])
+
+extern char *ospf6_path_type_str[OSPF6_PATH_TYPE_MAX];
+extern char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX];
+#define OSPF6_PATH_TYPE_NAME(x)                       \
+  (0 < (x) && (x) < OSPF6_PATH_TYPE_MAX ?             \
+   ospf6_path_type_str[(x)] : ospf6_path_type_str[0])
+#define OSPF6_PATH_TYPE_SUBSTR(x)                           \
+  (0 < (x) && (x) < OSPF6_PATH_TYPE_MAX ?                   \
+   ospf6_path_type_substr[(x)] : ospf6_path_type_substr[0])
+
+#define OSPF6_ROUTE_ADDRESS_STR "Display the route bestmatches the address\n"
+#define OSPF6_ROUTE_PREFIX_STR  "Display the route\n"
+#define OSPF6_ROUTE_MATCH_STR   "Display the route matches the prefix\n"
+
+#define ospf6_route_is_prefix(p, r) \
+  (memcmp (p, &(r)->prefix, sizeof (struct prefix)) == 0)
+#define ospf6_route_is_same(ra, rb) \
+  (prefix_same (&(ra)->prefix, &(rb)->prefix))
+#define ospf6_route_is_same_origin(ra, rb) \
+  ((ra)->path.area_id == (rb)->path.area_id && \
+   memcmp (&(ra)->path.origin, &(rb)->path.origin, \
+           sizeof (struct ospf6_ls_origin)) == 0)
+#define ospf6_route_is_identical(ra, rb) \
+  ((ra)->type == (rb)->type && \
+   memcmp (&(ra)->prefix, &(rb)->prefix, sizeof (struct prefix)) == 0 && \
+   memcmp (&(ra)->path, &(rb)->path, sizeof (struct ospf6_path)) == 0 && \
+   memcmp (&(ra)->nexthop, &(rb)->nexthop,                               \
+           sizeof (struct ospf6_nexthop) * OSPF6_MULTI_PATH_LIMIT) == 0)
+#define ospf6_route_is_best(r) (CHECK_FLAG ((r)->flag, OSPF6_ROUTE_BEST))
+
+#define ospf6_linkstate_prefix_adv_router(x) \
+  (*(u_int32_t *)(&(x)->u.prefix6.s6_addr[0]))
+#define ospf6_linkstate_prefix_id(x) \
+  (*(u_int32_t *)(&(x)->u.prefix6.s6_addr[4]))
+
+/* Function prototype */
+void ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id,
+                             struct prefix *prefix);
+void ospf6_linkstate_prefix2str (struct prefix *prefix, char *buf, int size);
+
+struct ospf6_route *ospf6_route_create ();
+void ospf6_route_delete (struct ospf6_route *);
+struct ospf6_route *ospf6_route_copy (struct ospf6_route *route);
+
+void ospf6_route_lock (struct ospf6_route *route);
+void ospf6_route_unlock (struct ospf6_route *route);
+
+struct ospf6_route *
+ospf6_route_lookup (struct prefix *prefix,
+                    struct ospf6_route_table *table);
+struct ospf6_route *
+ospf6_route_lookup_identical (struct ospf6_route *route,
+                              struct ospf6_route_table *table);
+struct ospf6_route *
+ospf6_route_lookup_bestmatch (struct prefix *prefix,
+                              struct ospf6_route_table *table);
+
+struct ospf6_route *
+ospf6_route_add (struct ospf6_route *route, struct ospf6_route_table *table);
+void
+ospf6_route_remove (struct ospf6_route *route, struct ospf6_route_table *table);
+
+struct ospf6_route *ospf6_route_head (struct ospf6_route_table *table);
+struct ospf6_route *ospf6_route_next (struct ospf6_route *route);
+struct ospf6_route *ospf6_route_best_next (struct ospf6_route *route);
+
+struct ospf6_route *ospf6_route_match_head (struct prefix *prefix,
+                                            struct ospf6_route_table *table);
+struct ospf6_route *ospf6_route_match_next (struct prefix *prefix,
+                                            struct ospf6_route *route);
+
 void ospf6_route_remove_all (struct ospf6_route_table *);
-
 struct ospf6_route_table *ospf6_route_table_create ();
 void ospf6_route_table_delete (struct ospf6_route_table *);
-
-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 *),
-                           void (*remove) (struct ospf6_route_req *),
-                           struct ospf6_route_table *table);
-void
-ospf6_route_hook_unregister (void (*add)    (struct ospf6_route_req *),
-                             void (*change) (struct ospf6_route_req *),
-                             void (*remove) (struct ospf6_route_req *),
-                             struct ospf6_route_table *table);
-
-void ospf6_route_init ();
+void ospf6_route_dump (struct ospf6_route_table *table);
 
 int ospf6_route_table_show (struct vty *, int, char **,
                             struct ospf6_route_table *);
+int ospf6_lsentry_table_show (struct vty *, int, char **,
+                              struct ospf6_route_table *);
+
+int config_write_ospf6_debug_route (struct vty *vty);
+void install_element_ospf6_debug_route ();
+void ospf6_route_init ();
 
 #endif /* OSPF6_ROUTE_H */
 
diff --git a/ospf6d/ospf6_routemap.c b/ospf6d/ospf6_routemap.c
deleted file mode 100644
index f617e91..0000000
--- a/ospf6d/ospf6_routemap.c
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * OSPFv3 Route-Map
- * Copyright (C) 1999 Yasuhiro Ohara
- *
- * 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 "log.h"
-#include "memory.h"
-#include "linklist.h"
-#include "prefix.h"
-#include "command.h"
-#include "vty.h"
-#include "routemap.h"
-#include "table.h"
-#include "plist.h"
-
-#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,
-                                              struct prefix *prefix,
-                                              route_map_object_t type,
-                                              void *object)
-{
-  struct prefix_list *plist;
-
-  if (type != RMAP_OSPF6)
-    return RMAP_NOMATCH;
-
-  plist = prefix_list_lookup (AFI_IP6, (char *) rule);
-
-  if (plist == NULL)
-    return RMAP_NOMATCH;
-
-  return (prefix_list_apply (plist, prefix) == PREFIX_DENY ?
-          RMAP_NOMATCH : RMAP_MATCH);
-}
-
-void *
-ospf6_routemap_rule_match_address_prefixlist_compile (char *arg)
-{
-  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
-}
-
-void
-ospf6_routemap_rule_match_address_prefixlist_free (void *rule)
-{
-  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
-}
-
-struct route_map_rule_cmd
-ospf6_routemap_rule_match_address_prefixlist_cmd =
-{
-  "ipv6 address prefix-list",
-  ospf6_routemap_rule_match_address_prefixlist,
-  ospf6_routemap_rule_match_address_prefixlist_compile,
-  ospf6_routemap_rule_match_address_prefixlist_free,
-};
-
-route_map_result_t
-ospf6_routemap_rule_set_metric_type (void *rule, struct prefix *prefix,
-                                     route_map_object_t type, void *object)
-{
-  char *metric_type = rule;
-  struct ospf6_external_info *info = object;
-
-  if (type != RMAP_OSPF6)
-    return RMAP_OKAY;
-
-  if (strcmp (metric_type, "type-2") == 0)
-    info->metric_type = 2;
-  else
-    info->metric_type = 1;
-
-  return RMAP_OKAY;
-}
-
-void *
-ospf6_routemap_rule_set_metric_type_compile (char *arg)
-{
-  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
-}
-
-void
-ospf6_routemap_rule_set_metric_type_free (void *rule)
-{
-  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
-}
-
-struct route_map_rule_cmd
-ospf6_routemap_rule_set_metric_type_cmd =
-{
-  "metric-type",
-  ospf6_routemap_rule_set_metric_type,
-  ospf6_routemap_rule_set_metric_type_compile,
-  ospf6_routemap_rule_set_metric_type_free,
-};
-
-route_map_result_t
-ospf6_routemap_rule_set_metric (void *rule, struct prefix *prefix,
-                                route_map_object_t type, void *object)
-{
-  char *metric = rule;
-  struct ospf6_external_info *info = object;
-
-  if (type != RMAP_OSPF6)
-    return RMAP_OKAY;
-
-  info->metric = atoi (metric);
-  return RMAP_OKAY;
-}
-
-void *
-ospf6_routemap_rule_set_metric_compile (char *arg)
-{
-  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
-}
-
-void
-ospf6_routemap_rule_set_metric_free (void *rule)
-{
-  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
-}
-
-struct route_map_rule_cmd
-ospf6_routemap_rule_set_metric_cmd =
-{
-  "metric",
-  ospf6_routemap_rule_set_metric,
-  ospf6_routemap_rule_set_metric_compile,
-  ospf6_routemap_rule_set_metric_free,
-};
-
-route_map_result_t
-ospf6_routemap_rule_set_forwarding (void *rule, struct prefix *prefix,
-                                    route_map_object_t type, void *object)
-{
-  char *forwarding = rule;
-  struct ospf6_external_info *info = object;
-
-  if (type != RMAP_OSPF6)
-    return RMAP_OKAY;
-
-  if (inet_pton (AF_INET6, forwarding, &info->forwarding) != 1)
-    {
-      memset (&info->forwarding, 0, sizeof (struct in6_addr));
-      return RMAP_ERROR;
-    }
-
-  return RMAP_OKAY;
-}
-
-void *
-ospf6_routemap_rule_set_forwarding_compile (char *arg)
-{
-  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
-}
-
-void
-ospf6_routemap_rule_set_forwarding_free (void *rule)
-{
-  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
-}
-
-struct route_map_rule_cmd
-ospf6_routemap_rule_set_forwarding_cmd =
-{
-  "forwarding-address",
-  ospf6_routemap_rule_set_forwarding,
-  ospf6_routemap_rule_set_forwarding_compile,
-  ospf6_routemap_rule_set_forwarding_free,
-};
-
-int
-route_map_command_status (struct vty *vty, int ret)
-{
-  if (! ret)
-    return CMD_SUCCESS;
-
-  switch (ret)
-    {
-    case RMAP_RULE_MISSING:
-      vty_out (vty, "Can't find rule.%s", VTY_NEWLINE);
-      break;
-    case RMAP_COMPILE_ERROR:
-      vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE);
-      break;
-    default:                          
-      vty_out (vty, "route-map add set failed.%s", VTY_NEWLINE);
-      break;
-    }
-  return CMD_WARNING;
-}
-
-/* add "match address" */
-DEFUN (match_ipv6_address_prefix_list,
-       match_ipv6_address_prefix_list_cmd,
-       "match ipv6 address prefix-list WORD",
-       MATCH_STR
-       IPV6_STR
-       "Match address of route\n"
-       "Match entries of prefix-lists\n"
-       "IP prefix-list name\n")
-{
-  int ret = route_map_add_match ((struct route_map_index *) vty->index,
-                                 "ipv6 address prefix-list", argv[0]);
-  return route_map_command_status (vty, ret);
-}
-
-/* delete "match address" */
-DEFUN (no_match_ipv6_address_prefix_list,
-       no_match_ipv6_address_prefix_list_cmd,
-       "no match ipv6 address prefix-list WORD",
-       NO_STR
-       MATCH_STR
-       IPV6_STR
-       "Match address of route\n"
-       "Match entries of prefix-lists\n"
-       "IP prefix-list name\n")
-{
-  int ret = route_map_delete_match ((struct route_map_index *) vty->index,
-                                    "ipv6 address prefix-list", argv[0]);
-  return route_map_command_status (vty, ret);
-}
-
-/* add "set metric-type" */
-DEFUN (set_metric_type,
-       set_metric_type_cmd,
-       "set metric-type (type-1|type-2)",
-       SET_STR
-       "Type of metric for destination routing protocol\n"
-       "OSPF[6] external type 1 metric\n"
-       "OSPF[6] external type 2 metric\n")
-{
-  int ret = route_map_add_set ((struct route_map_index *) vty->index,
-                               "metric-type", argv[0]);
-  return route_map_command_status (vty, ret);
-}
-
-/* delete "set metric-type" */
-DEFUN (no_set_metric_type,
-       no_set_metric_type_cmd,
-       "no set metric-type",
-       NO_STR
-       SET_STR
-       "Type of metric for destination routing protocol\n")
-{
-  int ret;
-  if (argc == 0)
-    ret = route_map_delete_set ((struct route_map_index *) vty->index,
-                                  "metric-type", NULL);
-  else
-    ret = route_map_delete_set ((struct route_map_index *) vty->index,
-                                  "metric-type", argv[0]);
-  return route_map_command_status (vty, ret);
-}
-
-ALIAS (no_set_metric_type,
-       no_set_metric_type_val_cmd,
-       "no set metric-type (type-1|type-2)",
-       NO_STR
-       SET_STR
-       "Type of metric for destination routing protocol\n"
-       "OSPF[6] external type 1 metric\n"
-       "OSPF[6] external type 2 metric\n")
-
-/* add "set metric" */
-DEFUN (set_metric,
-       set_metric_cmd,
-       "set metric <0-4294967295>",
-       SET_STR
-       "Metric value for destination routing protocol\n"
-       "Metric value\n")
-{
-  int ret = route_map_add_set ((struct route_map_index *) vty->index,
-                               "metric", argv[0]);
-  return route_map_command_status (vty, ret);
-}
-
-/* delete "set metric" */
-DEFUN (no_set_metric,
-       no_set_metric_cmd,
-       "no set metric",
-       NO_STR
-       SET_STR
-       "Metric value for destination routing protocol\n")
-{
-  int ret;
-  if (argc == 0)
-    ret = route_map_delete_set ((struct route_map_index *) vty->index,
-                                  "metric", NULL);
-  else
-    ret = route_map_delete_set ((struct route_map_index *) vty->index,
-                                  "metric", argv[0]);
-  return route_map_command_status (vty, ret);
-}
-
-ALIAS (no_set_metric,
-       no_set_metric_val_cmd,
-       "no set metric <0-4294967295>",
-       NO_STR
-       SET_STR
-       "Metric value for destination routing protocol\n"
-       "Metric value\n")
-
-/* add "set forwarding-address" */
-DEFUN (ospf6_routemap_set_forwarding,
-       ospf6_routemap_set_forwarding_cmd,
-       "set forwarding-address X:X::X:X",
-       "Set value\n"
-       "Forwarding Address\n"
-       "IPv6 Address\n")
-{
-  int ret = route_map_add_set ((struct route_map_index *) vty->index,
-                               "forwarding-address", argv[0]);
-  return route_map_command_status (vty, ret);
-}
-
-/* delete "set forwarding-address" */
-DEFUN (ospf6_routemap_no_set_forwarding,
-       ospf6_routemap_no_set_forwarding_cmd,
-       "no set forwarding-address X:X::X:X",
-       NO_STR
-       "Set value\n"
-       "Forwarding Address\n"
-       "IPv6 Address\n")
-{
-  int ret = route_map_delete_set ((struct route_map_index *) vty->index,
-                                  "forwarding-address", argv[0]);
-  return route_map_command_status (vty, ret);
-}
-
-void
-ospf6_routemap_init ()
-{
-  route_map_init ();
-  route_map_init_vty ();
-  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);
-  route_map_install_set (&ospf6_routemap_rule_set_metric_cmd);
-  route_map_install_set (&ospf6_routemap_rule_set_forwarding_cmd);
-
-  /* Match address prefix-list */
-  install_element (RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
-  install_element (RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
-
-  /* ASE Metric Type (e.g. Type-1/Type-2) */
-  install_element (RMAP_NODE, &set_metric_type_cmd);
-  install_element (RMAP_NODE, &no_set_metric_type_cmd);
-  install_element (RMAP_NODE, &no_set_metric_type_val_cmd);
-
-  /* ASE Metric */
-  install_element (RMAP_NODE, &set_metric_cmd);
-  install_element (RMAP_NODE, &no_set_metric_cmd);
-  install_element (RMAP_NODE, &no_set_metric_val_cmd);
-
-  /* ASE Metric */
-  install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd);
-  install_element (RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd);
-}
-
diff --git a/ospf6d/ospf6_routemap.h b/ospf6d/ospf6_routemap.h
deleted file mode 100644
index c68e0ff..0000000
--- a/ospf6d/ospf6_routemap.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * OSPFv3 Route-Map
- * Copyright (C) 2000 Kunihiro Ishiguro
- *
- * 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.  
- */
-
-#ifndef OSPF6_ROUTEMAP_H
-
-void ospf6_routemap_init ();
-
-#endif /* OSPF6_ROUTEMAP_H */
diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c
index fd7fc77..10b73b8 100644
--- a/ospf6d/ospf6_spf.c
+++ b/ospf6d/ospf6_spf.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -18,1437 +18,627 @@
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
  * Boston, MA 02111-1307, USA.  
  */
+
 /* Shortest Path First calculation for OSPFv3 */
 
-#include "ospf6d.h"
+#include <zebra.h>
 
-#include "linklist.h"
+#include "log.h"
+#include "memory.h"
+#include "command.h"
+#include "vty.h"
 #include "prefix.h"
-#include "table.h"
+#include "pqueue.h"
+#include "linklist.h"
+#include "thread.h"
 
-#include "ospf6_proto.h"
+#include "ospf6d.h"
 #include "ospf6_lsa.h"
 #include "ospf6_lsdb.h"
 #include "ospf6_route.h"
-#include "ospf6_spf.h"
-#include "ospf6_neighbor.h"
-#include "ospf6_interface.h"
 #include "ospf6_area.h"
+#include "ospf6_spf.h"
+#include "ospf6_intra.h"
+#include "ospf6_interface.h"
 
-#include "ospf6_bintree.h"
-#include "ospf6_linklist.h"
-
-struct bintree *_candidate_list;
-struct linklist *nexthop_list;
-
-struct ospf6_spf_candidate_node
-{
-  u_int32_t cost;
-  struct linklist *list;
-};
+unsigned char conf_debug_ospf6_spf = 0;
 
 int
-ospf6_spf_candidate_node_cmp (void *a, void *b)
+ospf6_vertex_cmp (void *a, void *b)
 {
-  struct ospf6_spf_candidate_node *ca = a;
-  struct ospf6_spf_candidate_node *cb = b;
-  return ca->cost - cb->cost;
+  struct ospf6_vertex *va = (struct ospf6_vertex *) a;
+  struct ospf6_vertex *vb = (struct ospf6_vertex *) b;
+
+  /* ascending order */
+  return (va->cost - vb->cost);
 }
 
 int
-ospf6_spf_vertex_cmp (void *a, void *b)
+ospf6_vertex_id_cmp (void *a, void *b)
 {
-  return 1;
-}
+  struct ospf6_vertex *va = (struct ospf6_vertex *) a;
+  struct ospf6_vertex *vb = (struct ospf6_vertex *) b;
+  int ret = 0;
 
-void
-ospf6_spf_candidate_node_print (int indent_num, void *node)
-{
-  struct ospf6_spf_candidate_node *cn = node;
-  char format[256];
+  ret = ntohl (ospf6_linkstate_prefix_adv_router (&va->vertex_id)) -
+        ntohl (ospf6_linkstate_prefix_adv_router (&vb->vertex_id));
+  if (ret)
+    return ret;
 
-  snprintf (format, sizeof (format), "%%%ds %%d (num: %%d)",
-            indent_num * 2 + 1);
-  zlog_info (format, " ", cn->cost, cn->list->count);
-}
-
-void
-ospf6_spf_candidate_init ()
-{
-  _candidate_list = bintree_create ();
-  _candidate_list->cmp = ospf6_spf_candidate_node_cmp;
-}
-
-u_int32_t
-ospf6_spf_candidate_count ()
-{
-  u_int32_t count = 0;
-  struct bintree_node node;
-  struct ospf6_spf_candidate_node *cnode;
-
-  for (bintree_head (_candidate_list, &node); ! bintree_end (&node);
-       bintree_next (&node))
-    {
-      cnode = node.data;
-      count += cnode->list->count;
-    }
-
-  return count;
-}
-
-void
-ospf6_spf_candidate_print ()
-{
-  zlog_info ("---------------------------");
-  bintree_print (ospf6_spf_candidate_node_print, _candidate_list);
-  zlog_info ("---------------------------");
-}
-
-void
-ospf6_spf_candidate_enqueue (struct ospf6_vertex *v)
-{
-  struct ospf6_spf_candidate_node req, *node;
-
-  memset (&req, 0, sizeof (req));
-  req.cost = v->distance;
-  node = bintree_lookup (&req, _candidate_list);
-
-  if (node == NULL)
-    {
-      node = malloc (sizeof (struct ospf6_spf_candidate_node));
-      node->cost = v->distance;
-      node->list = linklist_create ();
-      node->list->cmp = ospf6_spf_vertex_cmp;
-      bintree_add (node, _candidate_list);
-    }
-
-  linklist_add (v, node->list);
-
-#if 0
-  if (IS_OSPF6_DUMP_SPF)
-    ospf6_spf_candidate_print ();
-#endif
-}
-
-struct ospf6_vertex *
-ospf6_spf_candidate_dequeue ()
-{
-  struct ospf6_spf_candidate_node *node;
-  struct linklist_node lnode;
-  struct ospf6_vertex *ret;
-
-  node = bintree_lookup_min (_candidate_list);
-  if (node == NULL)
-    return NULL;
-
-  linklist_head (node->list, &lnode);
-  ret = lnode.data;
-
-  linklist_remove (ret, node->list);
-  if (node->list->count == 0)
-    {
-      linklist_delete (node->list);
-      bintree_remove (node, _candidate_list);
-    }
-
-#if 0
-  if (IS_OSPF6_DUMP_SPF)
-    ospf6_spf_candidate_print ();
-#endif
-
+  ret = ntohl (ospf6_linkstate_prefix_id (&va->vertex_id)) -
+        ntohl (ospf6_linkstate_prefix_id (&vb->vertex_id));
   return ret;
 }
 
+struct ospf6_vertex *
+ospf6_vertex_create (struct ospf6_lsa *lsa)
+{
+  struct ospf6_vertex *v;
+  int i;
+
+  v = (struct ospf6_vertex *)
+    XMALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_vertex));
+
+  /* type */
+  if (ntohs (lsa->header->type) == OSPF6_LSTYPE_ROUTER)
+    v->type = OSPF6_VERTEX_TYPE_ROUTER;
+  else if (ntohs (lsa->header->type) == OSPF6_LSTYPE_NETWORK)
+    v->type = OSPF6_VERTEX_TYPE_NETWORK;
+  else
+    assert (0);
+
+  /* vertex_id */
+  ospf6_linkstate_prefix (lsa->header->adv_router, lsa->header->id,
+                          &v->vertex_id);
+
+  /* name */
+  ospf6_linkstate_prefix2str (&v->vertex_id, v->name, sizeof (v->name));
+
+  /* Associated LSA */
+  v->lsa = lsa;
+
+  /* capability bits + options */
+  v->capability = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header));
+  v->options[0] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 1);
+  v->options[1] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 2);
+  v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 3);
+
+  for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
+    ospf6_nexthop_clear (&v->nexthop[i]);
+
+  v->parent = NULL;
+  v->child_list = list_new ();
+  v->child_list->cmp = ospf6_vertex_id_cmp;
+
+  return v;
+}
+
 void
-ospf6_spf_candidate_remove (struct ospf6_vertex *v)
+ospf6_vertex_delete (struct ospf6_vertex *v)
 {
-  struct bintree_node node;
-  struct ospf6_spf_candidate_node *cnode = NULL;
-
-  for (bintree_head (_candidate_list, &node); ! bintree_end (&node);
-       bintree_next (&node))
-    {
-      cnode = node.data;
-      if (linklist_lookup (v, cnode->list))
-        {
-          linklist_remove (v, cnode->list);
-          break;
-        }
-    }
-
-  if (cnode->list->count == 0)
-    {
-      linklist_delete (cnode->list);
-      bintree_remove (cnode, _candidate_list);
-    }
-}
-
-
-#define TIMER_SEC_MICRO 1000000
-
-/* timeval calculation */
-static void
-ospf6_timeval_add (const struct timeval *t1, const struct timeval *t2,
-                   struct timeval *result)
-{
-  long moveup = 0;
-
-  result->tv_usec = t1->tv_usec + t2->tv_usec;
-  while (result->tv_usec > TIMER_SEC_MICRO)
-    {
-      result->tv_usec -= TIMER_SEC_MICRO;
-      moveup ++;
-    }
-
-  result->tv_sec = t1->tv_sec + t2->tv_sec + moveup;
-}
-
-static void
-ospf6_timeval_add_equal (const struct timeval *t, struct timeval *result)
-{
-  struct timeval tmp;
-  ospf6_timeval_add (t, result, &tmp);
-  result->tv_sec = tmp.tv_sec;
-  result->tv_usec = tmp.tv_usec;
-}
-
-/* Compare timeval a and b.  It returns an integer less than, equal
-   to, or great than zero if a is found, respectively, to be less
-   than, to match, or be greater than b.  */
-static int
-ospf6_timeval_cmp (const struct timeval t1, const struct timeval t2)
-{
-  return (t1.tv_sec == t2.tv_sec
-	  ? t1.tv_usec - t2.tv_usec : t1.tv_sec - t2.tv_sec);
-}
-
-
-static int
-ospf6_spf_lsd_num (struct ospf6_vertex *V, struct ospf6_area *o6a)
-{
-  u_int16_t type;
-  u_int32_t id, adv_router;
-  struct ospf6_lsa *lsa;
-
-  if (V->vertex_id.id.s_addr)
-    type = htons (OSPF6_LSA_TYPE_NETWORK);
-  else
-    type = htons (OSPF6_LSA_TYPE_ROUTER);
-  id = V->vertex_id.id.s_addr;
-  adv_router = V->vertex_id.adv_router.s_addr;
-
-  lsa = ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6a->lsdb);
-  if (! lsa)
-    {
-      zlog_err ("SPF: Can't find associated LSA for %s", V->string);
-      return 0;
-    }
-
-  return ospf6_lsa_lsd_num ((struct ospf6_lsa_header *) lsa->header);
-}
-
-/* RFC2328 section 16.1.1:
-   Check if there is at least one router in the path
-   from the root to this vertex. */
-static int
-ospf6_spf_is_router_to_root (struct ospf6_vertex *c,
-                             struct ospf6_spftree *spf_tree)
-{
-  listnode node;
-  struct ospf6_vertex *p;
-
-  if (spf_tree->root == c)
-    return 0;
-
-  for (node = listhead (c->parent_list); node; nextnode (node))
-    {
-      p = (struct ospf6_vertex *) getdata (node);
-
-      if (p == spf_tree->root)
-        return 0;
-
-      if (p->vertex_id.id.s_addr == 0) /* this is router */
-        continue;
-      else if (ospf6_spf_is_router_to_root (p, spf_tree))
-        continue;
-
-      return 0;
-    }
-
-  return 1;
-}
-
-static struct in6_addr *
-ospf6_spf_get_ipaddr (u_int32_t id, u_int32_t adv_router, u_int32_t ifindex)
-{
-  char buf[64], nhbuf[64];
-  struct ospf6_interface *o6i;
-  struct ospf6_neighbor *o6n;
-  struct ospf6_lsa *lsa;
-  struct ospf6_lsdb_node node;
-
-  o6i = ospf6_interface_lookup_by_index (ifindex);
-  if (! o6i)
-    {
-      zlog_err ("SPF: Can't find interface: index %d", ifindex);
-      return (struct in6_addr *) NULL;
-    }
-
-  /* Find Link-LSA of the vertex in question */
-  lsa = NULL;
-  for (ospf6_lsdb_type_router (&node, htons (OSPF6_LSA_TYPE_LINK),
-                               adv_router, o6i->lsdb);
-       ! ospf6_lsdb_is_end (&node);
-       ospf6_lsdb_next (&node))
-    lsa = node.lsa;
-
-  /* return Linklocal Address field if the Link-LSA exists */
-  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",
-             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, "
-                "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;
-}
-
-static int
-ospf6_spf_nexthop_calculation (struct ospf6_vertex *W,
-                               u_int32_t ifindex,
-                               struct ospf6_vertex *V,
-                               struct ospf6_spftree *spf_tree)
-{
-  struct ospf6_nexthop *nexthop, *n;
-  u_int32_t adv_router, id;
-  struct in6_addr nexthop_ipaddr, *ipaddr;
-  unsigned int nexthop_ifindex;
-  struct linklist_node node;
-
-  /* until this, nexthop_list should be untouched */
-  assert (list_isempty (W->nexthop_list));
-
-  /* If ther is at least one intervening router from root to W */
-  if (ospf6_spf_is_router_to_root (W, spf_tree))
-    {
-      /* Create no new nexthop, Inherit from the intervening router */
-      for (linklist_head (V->nexthop_list, &node); ! linklist_end (&node);
-           linklist_next (&node))
-        linklist_add (node.data, W->nexthop_list);
-      return 0;
-    }
-
-  /* Create new nexthop */
-
-  adv_router = W->vertex_id.adv_router.s_addr;
-  id = W->vertex_id.id.s_addr;
-
-  nexthop_ifindex = 0;
-  memset (&nexthop_ipaddr, 0, sizeof (struct in6_addr));
-  if (spf_tree->root && V == spf_tree->root)
-    {
-      nexthop_ifindex = ifindex;
-      if (! id) /* xxx, if V is router */
-        {
-          ipaddr = ospf6_spf_get_ipaddr (id, adv_router, ifindex);
-          if (! ipaddr)
-            {
-              /* xxx, should trigger error and quit SPF calculation... */
-              memset (&nexthop_ipaddr, 0xff, sizeof (struct in6_addr));
-              return -1;
-            }
-          else
-            memcpy (&nexthop_ipaddr, ipaddr, sizeof (struct in6_addr));
-        }
-    }
-  else
-    {
-      /* V is broadcast network, W is router */
-      assert (V->vertex_id.id.s_addr != 0);
-      assert (W->vertex_id.id.s_addr == 0);
- 
-      linklist_head (V->nexthop_list, &node);
-      n = (struct ospf6_nexthop *) node.data;
-      nexthop_ifindex = n->ifindex;
-      ipaddr = ospf6_spf_get_ipaddr (id, adv_router, n->ifindex);
-      if (! ipaddr)
-        {
-          /* xxx, should trigger error and quit SPF calculation... */
-          memset (&nexthop_ipaddr, 0xff, sizeof (struct in6_addr));
-          return -1;
-        }
-      else
-        memcpy (&nexthop_ipaddr, ipaddr, sizeof (struct in6_addr));
-    }
-
-  nexthop = XCALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_nexthop));
-  nexthop->ifindex = nexthop_ifindex;
-  memcpy (&nexthop->address, &nexthop_ipaddr, sizeof (nexthop->address));
-
-  linklist_add (nexthop, W->nexthop_list);
-
-  /* to hold malloced memory */
-  linklist_add (nexthop, nexthop_list);
-
-  return 0;
-}
-
-static struct ospf6_vertex *
-ospf6_spf_vertex_create (int index, struct ospf6_vertex *V,
-                         struct ospf6_area *o6a)
-{
-  struct ospf6_lsa *lsa;
-  struct ospf6_router_lsa *router_lsa;
-  struct ospf6_router_lsd *router_lsd;
-  struct ospf6_network_lsa *network_lsa;
-  struct ospf6_network_lsd *network_lsd;
-  u_int32_t id, adv_router;
-  u_int16_t type;
-  void *lsd;
-  struct ospf6_vertex *W;
-  u_int16_t distance;
-  u_int32_t ifindex;
-  int backreference, lsdnum, i;
-  char buf_router[16], buf_id[16];
-
-  type = id = adv_router = 0;
-
-  /* Get Linkstate description */
-  lsd = ospf6_lsa_lsd_get (index, (struct ospf6_lsa_header *) V->lsa->header);
-  if (! lsd)
-    {
-      zlog_err ("SPF: Can't find %dth Link description from %s",
-                index, V->lsa->str);
-      return (struct ospf6_vertex *) NULL;
-    }
-
-  /* Check Link state description */
-  distance = 0;
-  ifindex = 0;
-  if (V->lsa->header->type == htons (OSPF6_LSA_TYPE_ROUTER))
-    {
-      router_lsd = lsd;
-      if (router_lsd->type == OSPF6_ROUTER_LSD_TYPE_POINTTOPOINT)
-        {
-          type = htons (OSPF6_LSA_TYPE_ROUTER);
-          id = htonl (0);
-        }
-      else if (router_lsd->type == OSPF6_ROUTER_LSD_TYPE_TRANSIT_NETWORK)
-        {
-          type = htons (OSPF6_LSA_TYPE_NETWORK);
-          id = router_lsd->neighbor_interface_id;
-        }
-      adv_router = router_lsd->neighbor_router_id;
-      distance = ntohs (router_lsd->metric);
-      ifindex = ntohl (router_lsd->interface_id);
-    }
-  else if (V->lsa->header->type == htons (OSPF6_LSA_TYPE_NETWORK))
-    {
-      network_lsd = lsd;
-      type = htons (OSPF6_LSA_TYPE_ROUTER);
-      id = htonl (0);
-      adv_router = network_lsd->adv_router;
-    }
-
-  /* Avoid creating candidate of myself */
-  if (adv_router == o6a->ospf6->router_id &&
-      type == htons (OSPF6_LSA_TYPE_ROUTER))
-    {
-      return (struct ospf6_vertex *) NULL;
-    }
-
-  /* Find Associated LSA for W */
-  lsa = ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6a->lsdb);
-
-  if (! lsa)
-    {
-      inet_ntop (AF_INET, &adv_router, buf_router, sizeof (buf_router));
-      inet_ntop (AF_INET, &id, buf_id, sizeof (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))
-    {
-      if (IS_OSPF6_DUMP_SPF)
-        zlog_info ("SPF: Associated LSA for W is MaxAge: %s", lsa->str);
-      return (struct ospf6_vertex *) NULL;
-    }
-
-  /* Check back reference from W's lsa to V's lsa */
-  backreference = 0;
-  lsdnum = ospf6_lsa_lsd_num ((struct ospf6_lsa_header *) lsa->header);
-  for (i = 0; i < lsdnum; i++)
-    {
-      if (ospf6_lsa_lsd_is_refer_ok (i, (struct ospf6_lsa_header *) lsa->header,
-                                     index, (struct ospf6_lsa_header *) V->lsa->header))
-        backreference++;
-    }
-  if (! backreference)
-    {
-      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;
-    }
-
-  /* Allocate new ospf6_vertex for W */
-  W = (struct ospf6_vertex *) XMALLOC (MTYPE_OSPF6_VERTEX,
-                                       sizeof (struct ospf6_vertex));
-  if (! W)
-    {
-      zlog_err ("SPF: Can't allocate memory for Vertex");
-      return (struct ospf6_vertex *) NULL;
-    }
-  memset (W, 0, sizeof (struct ospf6_vertex));
-
-  /* Initialize */
-  W->vertex_id.family = AF_UNSPEC;
-  W->vertex_id.prefixlen = 64; /* xxx */
-  W->lsa = lsa;
-  if (type == htons (OSPF6_LSA_TYPE_ROUTER))
-    W->vertex_id.id.s_addr = htonl (0); /* XXX */
-  else
-    W->vertex_id.id.s_addr = W->lsa->header->id;
-  W->vertex_id.adv_router.s_addr = W->lsa->header->adv_router;
-  W->nexthop_list = linklist_create ();
-  W->path_list = list_new ();
-  W->parent_list = list_new ();
-  W->distance = V->distance + distance;
-  W->depth = V->depth + 1;
-
-  inet_ntop (AF_INET, &W->vertex_id.adv_router.s_addr,
-             buf_router, sizeof (buf_router));
-  inet_ntop (AF_INET, &W->vertex_id.id.s_addr, buf_id, sizeof (buf_id));
-  snprintf (W->string, sizeof (W->string), "[%s-%s (%d)]",
-            buf_router, buf_id, W->distance);
-
-  /* capability bits and optional capabilities */
-  if (W->vertex_id.id.s_addr == 0)
-    {
-      router_lsa = (struct ospf6_router_lsa *) (W->lsa->header + 1);
-      W->capability_bits = router_lsa->bits;
-      memcpy (W->opt_capability, router_lsa->options,
-              sizeof (W->opt_capability));
-    }
-  else
-    {
-      network_lsa = (struct ospf6_network_lsa *) (W->lsa->header + 1);
-      W->capability_bits = network_lsa->reserved;
-      memcpy (W->opt_capability, network_lsa->options,
-              sizeof (W->opt_capability));
-    }
-
-  /* Link to Parent node */
-  listnode_add (W->parent_list, V);
-
-  /* Nexthop Calculation */
-  if (ospf6_spf_nexthop_calculation (W, ifindex, V, o6a->spf_tree) < 0)
-    return NULL;
-
-  return W;
-}
-
-static void
-ospf6_spf_vertex_delete (struct ospf6_vertex *v)
-{
-  linklist_delete (v->nexthop_list);
-  list_delete (v->path_list);
-  list_delete (v->parent_list);
+  list_delete (v->child_list);
   XFREE (MTYPE_OSPF6_VERTEX, v);
 }
 
-static void
-ospf6_spf_vertex_merge (struct ospf6_vertex *w, struct ospf6_vertex *x)
+struct ospf6_lsa *
+ospf6_lsdesc_lsa (caddr_t lsdesc, struct ospf6_vertex *v)
 {
-  listnode node;
-  struct linklist_node lnode;
-
-  /* merge should be done on two nodes which are
-     almost the same */
-
-  /* these w and x should be both candidate.
-     candidate should not have any children */
-  assert (list_isempty (w->path_list));
-  assert (list_isempty (x->path_list));
-
-  /* merge parent list */
-  for (node = listhead (w->parent_list); node; nextnode (node))
-    {
-      if (listnode_lookup (x->parent_list, getdata (node)))
-        continue;
-      listnode_add (x->parent_list, getdata (node));
-    }
-
-  /* merge nexthop list */
-  for (linklist_head (w->nexthop_list, &lnode); ! linklist_end (&lnode);
-       linklist_next (&lnode))
-    linklist_add (lnode.data, x->nexthop_list);
-}
-
-static void
-ospf6_spf_initialize (list candidate_list, struct ospf6_area *o6a)
-{
-  listnode node;
-  struct ospf6_vertex *v;
   struct ospf6_lsa *lsa;
-  u_int16_t type;
-  u_int32_t id, adv_router;
-  struct linklist_node lnode;
+  u_int16_t type = 0;
+  u_int32_t id = 0, adv_router = 0;
 
-  struct ospf6_nexthop *nexthop;
-  struct interface *ifp;
-  char buf_router[64], buf_id[64];
-
-  /* delete topology routing table for this area */
-  ospf6_route_remove_all (o6a->table_topology);
-
-  /* Delete previous spf tree */
-  for (node = listhead (o6a->spf_tree->list); node; nextnode (node))
+  if (VERTEX_IS_TYPE (NETWORK, v))
     {
-      v = (struct ospf6_vertex *) getdata (node);
-      ospf6_spf_vertex_delete (v);
+      type = htons (OSPF6_LSTYPE_ROUTER);
+      id = htonl (0);
+      adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc);
     }
-  list_delete_all_node (o6a->spf_tree->list);
-
-  for (linklist_head (nexthop_list, &lnode); ! linklist_end (&lnode);
-       linklist_next (&lnode))
-    XFREE (MTYPE_OSPF6_VERTEX, lnode.data);
-  linklist_remove_all (nexthop_list);
-
-  /* Find self originated Router-LSA */
-  type = htons (OSPF6_LSA_TYPE_ROUTER);
-  id = htonl (0);
-  adv_router = ospf6->router_id;
-
-  lsa = ospf6_lsdb_lookup_lsdb (type, id, adv_router, o6a->lsdb);
-
-  if (! lsa)
-    {
-      if (IS_OSPF6_DUMP_SPF)
-        zlog_info ("SPF: Can't find self originated Router-LSA");
-      return;
-    }
-  if (IS_LSA_MAXAGE (lsa))
-    {
-      zlog_err ("SPF: MaxAge self originated Router-LSA");
-      return;
-    }
-
-  /* Create root vertex */
-  v = (struct ospf6_vertex *) XMALLOC (MTYPE_OSPF6_VERTEX,
-                                       sizeof (struct ospf6_vertex));
-  if (! v)
-    {
-      zlog_err ("SPF: Can't allocate memory for root vertex");
-      return;
-    }
-  memset (v, 0, sizeof (struct ospf6_vertex));
-
-  v->vertex_id.family = AF_UNSPEC; /* XXX */
-  v->vertex_id.prefixlen = 64; /* XXX */
-  v->vertex_id.id.s_addr = htonl (0);
-  v->vertex_id.adv_router.s_addr = ospf6->router_id;
-  if (ospf6_is_asbr (ospf6))
-    OSPF6_OPT_SET (v->opt_capability, OSPF6_OPT_E);
-  OSPF6_OPT_SET (v->opt_capability, OSPF6_OPT_V6);
-  OSPF6_OPT_SET (v->opt_capability, OSPF6_OPT_R);
-  v->nexthop_list = linklist_create ();
-  v->path_list = list_new ();
-  v->parent_list = list_new ();
-  v->distance = 0;
-  v->depth = 0;
-  v->lsa = lsa;
-
-  inet_ntop (AF_INET, &v->vertex_id.adv_router.s_addr,
-             buf_router, sizeof (buf_router));
-  inet_ntop (AF_INET, &v->vertex_id.id.s_addr, buf_id, sizeof (buf_id));
-  snprintf (v->string, sizeof (v->string), "[%s-%s (%d)]",
-            buf_router, buf_id, v->distance);
-
-  nexthop = XCALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_nexthop));
-  ifp = if_lookup_by_name ("lo0");
-  if (ifp)
-    nexthop->ifindex = ifp->ifindex;
-  inet_pton (AF_INET6, "::1", &nexthop->address);
-  linklist_add (nexthop, v->nexthop_list);
-  linklist_add (nexthop, nexthop_list);
-
-  o6a->spf_tree->root = v;
-  listnode_add (candidate_list, v);
-
-  ospf6_spf_candidate_enqueue (v);
-}
-
-static struct ospf6_vertex *
-ospf6_spf_get_closest_candidate (list candidate_list)
-{
-  listnode node;
-  struct ospf6_vertex *candidate, *closest;
-
-  closest = (struct ospf6_vertex *) NULL;
-  for (node = listhead (candidate_list); node; nextnode (node))
-    {
-      candidate = (struct ospf6_vertex *) getdata (node);
-
-      if (closest && candidate->distance > closest->distance)
-        continue;
-
-      /* always choose network vertices if those're the same cost */
-      if (closest && candidate->distance == closest->distance
-          && closest->vertex_id.id.s_addr != 0)
-        continue;
-
-      closest = candidate;
-    }
-
-  return closest;
-}
-
-static struct ospf6_vertex *
-ospf6_spf_get_same_candidate (struct ospf6_vertex *w, list candidate_list)
-{
-  listnode node;
-  struct ospf6_vertex *c, *same;
-
-  same = (struct ospf6_vertex *) NULL;
-  for (node = listhead (candidate_list); node; nextnode (node))
-    {
-      c = (struct ospf6_vertex *) getdata (node);
-      if (w->vertex_id.adv_router.s_addr != c->vertex_id.adv_router.s_addr)
-        continue;
-      if (w->vertex_id.id.s_addr != c->vertex_id.id.s_addr)
-        continue;
-
-      if (same)
-        zlog_warn ("SPF: duplicate candidates in candidate_list");
-
-      same = c;
-    }
-
-  return same;
-}
-
-static void
-ospf6_spf_install (struct ospf6_vertex *vertex, struct ospf6_area *o6a)
-{
-  listnode node;
-  struct ospf6_vertex *parent;
-  struct ospf6_nexthop *nexthop;
-  struct ospf6_route_req request;
-  struct linklist_node lnode;
-
-  struct ospf6_router_lsa *router_lsa;
-  struct ospf6_network_lsa *network_lsa;
-
-  router_lsa = OSPF6_LSA_HEADER_END (vertex->lsa->header);
-  network_lsa = OSPF6_LSA_HEADER_END (vertex->lsa->header);
-
-  if (IS_OSPF6_DUMP_SPF)
-    {
-      zlog_info ("SPF: Install: %s", vertex->string);
-    }
-
-  listnode_add (o6a->spf_tree->list, vertex);
-
-  for (node = listhead (vertex->parent_list); node; nextnode (node))
-    {
-      parent = (struct ospf6_vertex *) getdata (node);
-      listnode_add (parent->path_list, vertex);
-      vertex->depth = parent->depth + 1;
-    }
-
-#if 0
-  if (vertex == o6a->spf_tree->root)
-    return;
-#endif /*0*/
-
-  /* install route to topology table */
-  memset (&request, 0, sizeof (request));
-  if (vertex->vertex_id.id.s_addr) /* xxx */
-    request.route.type = OSPF6_DEST_TYPE_NETWORK;
   else
-    request.route.type = OSPF6_DEST_TYPE_ROUTER;
-  memcpy (&request.route.prefix, &vertex->vertex_id,
-          sizeof (struct prefix));
-
-  request.path.area_id = o6a->area_id;
-  request.path.type = OSPF6_PATH_TYPE_INTRA;
-  request.path.cost = vertex->distance;
-  request.path.cost_e2 = 0;
-  request.path.origin.type = vertex->lsa->header->type;
-  request.path.origin.id = vertex->lsa->header->id;
-  request.path.origin.adv_router = vertex->lsa->header->adv_router;
-  if (vertex->lsa->header->type == htons (OSPF6_LSA_TYPE_ROUTER))
-    request.path.router_bits = router_lsa->bits;
-  memcpy (&request.path.capability, vertex->opt_capability,
-          sizeof (request.path.capability));
-
-#if 0
-  if (IS_OSPF6_DUMP_SPF)
-    zlog_info ("SPF:   install %d nexthops for %s",
-               listcount (vertex->nexthop_list), vertex->string);
-#endif
-
-  for (linklist_head (vertex->nexthop_list, &lnode); ! linklist_end (&lnode);
-       linklist_next (&lnode))
     {
-      nexthop = lnode.data;
-
-      request.nexthop.ifindex = nexthop->ifindex;
-      memcpy (&request.nexthop.address, &nexthop->address,
-              sizeof (request.nexthop.address));
-
-      ospf6_route_add (&request, o6a->table_topology);
-    }
-}
-
-struct ospf6_vertex *
-ospf6_spf_lookup (struct ospf6_vertex *w, struct ospf6_area *o6a)
-{
-  listnode node;
-  struct ospf6_vertex *v;
-
-  for (node = listhead (o6a->spf_tree->list); node; nextnode (node))
-    {
-      v = (struct ospf6_vertex *) getdata (node);
-
-      if (w->vertex_id.adv_router.s_addr != v->vertex_id.adv_router.s_addr)
-        continue;
-      if (w->vertex_id.id.s_addr != v->vertex_id.id.s_addr)
-        continue;
-
-      return v;
-    }
-
-  return (struct ospf6_vertex *) NULL;
-}
-
-u_int32_t stat_node = 0;
-u_int32_t stat_candidate = 0;
-u_int32_t stat_candidate_max = 0;
-u_int32_t stat_spf = 0;
-
-
-/* RFC2328 section 16.1 , RFC2740 section 3.8.1 */
-static int
-ospf6_spf_calculation (struct ospf6_area *o6a)
-{
-  list candidate_list;
-  struct ospf6_vertex *V, *W, *X;
-  int ldnum, i;
-
-  if (! o6a || ! o6a->spf_tree)
-    {
-      zlog_err ("SPF: Can't calculate SPF tree: malformed area");
-      return -1;
-    }
-
-  stat_spf ++;
-  stat_node = 0;
-  stat_candidate = 0;
-  stat_candidate_max = 0;
-
-  if (IS_OSPF6_DUMP_SPF)
-    zlog_info ("SPF: Calculation for area %s", o6a->str);
-
-  ospf6_route_table_freeze (o6a->table_topology);
-  ospf6_route_remove_all (o6a->table_topology);
-
-  /* (1): Initialize the algorithm's data structures */
-  candidate_list = list_new ();
-  ospf6_spf_initialize (candidate_list, o6a);
-  stat_candidate ++;
-
-  /* (3): Install closest from candidate list; if empty, break */
-  while (listcount (candidate_list))
-    {
-      V = ospf6_spf_get_closest_candidate (candidate_list);
-      listnode_delete (candidate_list, V);
-
-      {
-        struct ospf6_vertex *V_;
-
-        if (stat_candidate_max < ospf6_spf_candidate_count ())
-          stat_candidate_max = ospf6_spf_candidate_count ();
-
-        V_ = ospf6_spf_candidate_dequeue ();
-
-#if 0
-        if (IS_OSPF6_DUMP_SPF)
-          {
-            zlog_info ("Candidate list count: %lu",
-                       (u_long)ospf6_spf_candidate_count ());
-            zlog_info ("*** Candidate %s: %p <-> %p",
-                       (V == V_ ? "same" : "*** differ ***"), V, V_);
-            zlog_info ("  %p: %s", V, V->string);
-            zlog_info ("  %p: %s", V_, V_->string);
-          }
-#endif
-
-      }
-
-      stat_node++;
-      ospf6_spf_install (V, o6a);
-
-      /* (2): Examin LSA of just added vertex */
-      ldnum = ospf6_spf_lsd_num (V, o6a);
-      for (i = 0; i < ldnum; i++)
+      if (ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc))
         {
-          /* (b): If no LSA, or MaxAge, or LinkBack fail, examin next */
-          W = ospf6_spf_vertex_create (i, V, o6a);
-          if (! W)
-            continue;
-
-          stat_candidate ++;
-
-          /* (c) */
-          if (ospf6_spf_lookup (W, o6a))
-            {
-              if (IS_OSPF6_DUMP_SPF)
-                zlog_info ("SPF:   %s: Already in SPF tree", W->string);
-              ospf6_spf_vertex_delete (W);
-              continue;
-            }
-
-          /* (d) */
-          X = ospf6_spf_get_same_candidate (W, candidate_list);
-          if (X && X->distance < W->distance)
-            {
-              if (IS_OSPF6_DUMP_SPF)
-                zlog_info ("SPF:   %s: More closer found", W->string);
-              ospf6_spf_vertex_delete (W);
-              continue;
-            }
-          if (X && X->distance == W->distance)
-            {
-              if (IS_OSPF6_DUMP_SPF)
-                zlog_info ("SPF:   %s: new ECMP candidate", W->string);
-              ospf6_spf_vertex_merge (W, X);
-              ospf6_spf_vertex_delete (W);
-              continue;
-            }
-
-          if (X)
-            {
-              if (IS_OSPF6_DUMP_SPF)
-                zlog_info ("SPF:   %s: Swap with old candidate", W->string);
-              listnode_delete (candidate_list, X);
-              ospf6_spf_candidate_remove (X);
-              ospf6_spf_vertex_delete (X);
-            }
-          else
-            {
-              if (IS_OSPF6_DUMP_SPF)
-                zlog_info ("SPF:   %s: New Candidate", W->string);
-            }
-
-          if (stat_candidate_max < ospf6_spf_candidate_count ())
-            stat_candidate_max = ospf6_spf_candidate_count ();
-
-          listnode_add (candidate_list, W);
-          ospf6_spf_candidate_enqueue (W);
+          type = htons (OSPF6_LSTYPE_ROUTER);
+          id = htonl (0);
+          adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc);
+        }
+      else if (ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, lsdesc))
+        {
+          type = htons (OSPF6_LSTYPE_NETWORK);
+          id = htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc));
+          adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc);
         }
     }
 
-  assert (listcount (candidate_list) == 0);
-  list_free (candidate_list);
-  assert (ospf6_spf_candidate_count () == 0);
+  lsa = ospf6_lsdb_lookup (type, id, adv_router, v->area->lsdb);
 
-  /* Clear thread timer */
-  o6a->spf_tree->t_spf_calculation = (struct thread *) NULL;
-
-  if (IS_OSPF6_DUMP_SPF)
+  if (IS_OSPF6_DEBUG_SPF (DETAIL))
     {
-      zlog_info ("SPF: Calculation for area %s done", o6a->str);
-      zlog_info ("SPF:   Statistics: %luth", (u_long)stat_spf);
-      zlog_info ("SPF:   Node Number: %lu", (u_long)stat_node);
-      zlog_info ("SPF:   Candidate Number: %lu Max: %lu",
-                 (u_long) stat_candidate, (u_long) stat_candidate_max);
+      char ibuf[16], abuf[16];
+      inet_ntop (AF_INET, &id, ibuf, sizeof (ibuf));
+      inet_ntop (AF_INET, &adv_router, abuf, sizeof (abuf));
+      if (lsa)
+        zlog_info ("  Link to: %s", lsa->name);
+      else
+        zlog_info ("  Link to: [%s Id:%s Adv:%s] No LSA",
+                   OSPF6_LSTYPE_NAME (type), ibuf, abuf);
     }
 
-  ospf6_route_table_thaw (o6a->table_topology);
+  return lsa;
+}
+
+char *
+ospf6_lsdesc_backlink (struct ospf6_lsa *lsa,
+                       caddr_t lsdesc, struct ospf6_vertex *v)
+{
+  caddr_t backlink, found = NULL;
+  int size;
+
+  size = (OSPF6_LSA_IS_TYPE (ROUTER, lsa) ?
+          sizeof (struct ospf6_router_lsdesc) :
+          sizeof (struct ospf6_network_lsdesc));
+  for (backlink = OSPF6_LSA_HEADER_END (lsa->header) + 4;
+       backlink + size <= OSPF6_LSA_END (lsa->header); backlink += size)
+    {
+      assert (! (OSPF6_LSA_IS_TYPE (NETWORK, lsa) &&
+                 VERTEX_IS_TYPE (NETWORK, v)));
+
+      if (OSPF6_LSA_IS_TYPE (NETWORK, lsa) &&
+          NETWORK_LSDESC_GET_NBR_ROUTERID (backlink)
+            == v->lsa->header->adv_router)
+        found = backlink;
+      else if (VERTEX_IS_TYPE (NETWORK, v) &&
+          ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, backlink) &&
+          ROUTER_LSDESC_GET_NBR_ROUTERID (backlink)
+            == v->lsa->header->adv_router &&
+          ROUTER_LSDESC_GET_NBR_IFID (backlink)
+            == ntohl (v->lsa->header->id))
+        found = backlink;
+      else
+        {
+          if (! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, backlink) ||
+              ! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc))
+            continue;
+          if (ROUTER_LSDESC_GET_NBR_IFID (backlink) !=
+              ROUTER_LSDESC_GET_IFID (lsdesc) ||
+              ROUTER_LSDESC_GET_NBR_IFID (lsdesc) !=
+              ROUTER_LSDESC_GET_IFID (backlink))
+            continue;
+          if (ROUTER_LSDESC_GET_NBR_ROUTERID (backlink) !=
+              v->lsa->header->adv_router ||
+              ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc) !=
+              lsa->header->adv_router)
+            continue;
+          found = backlink;
+        }
+    }
+
+  if (IS_OSPF6_DEBUG_SPF (DETAIL))
+    zlog_info ("  Backlink %s", (found ? "OK" : "FAIL"));
+
+  return found;
+}
+
+void
+ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v,
+                    caddr_t lsdesc)
+{
+  int i, ifindex;
+  struct ospf6_interface *oi;
+  u_int16_t type;
+  u_int32_t adv_router;
+  struct ospf6_lsa *lsa;
+  struct ospf6_link_lsa *link_lsa;
+  char buf[64];
+
+  assert (VERTEX_IS_TYPE (ROUTER, w));
+  ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? v->nexthop[0].ifindex :
+             ROUTER_LSDESC_GET_IFID (lsdesc));
+  oi = ospf6_interface_lookup_by_ifindex (ifindex);
+  if (oi == NULL)
+    {
+      if (IS_OSPF6_DEBUG_SPF (SUMMARY))
+        zlog_warn ("Can't find interface in SPF: ifindex %d", ifindex);
+      return;
+    }
+
+  type = htons (OSPF6_LSTYPE_LINK);
+  adv_router = (VERTEX_IS_TYPE (NETWORK, v) ?
+                NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc) :
+                ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc));
+
+  i = 0;
+  for (lsa = ospf6_lsdb_type_router_head (type, adv_router, oi->lsdb); lsa;
+       lsa = ospf6_lsdb_type_router_next (type, adv_router, lsa))
+    {
+      if (VERTEX_IS_TYPE (ROUTER, v) &&
+          htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc)) != lsa->header->id)
+        continue;
+
+      link_lsa = (struct ospf6_link_lsa *) OSPF6_LSA_HEADER_END (lsa->header);
+      if (IS_OSPF6_DEBUG_SPF (DETAIL))
+        {
+          inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, sizeof (buf));
+          zlog_info ("  nexthop %s from %s", buf, lsa->name);
+        }
+
+      if (i < OSPF6_MULTI_PATH_LIMIT)
+        {
+          memcpy (&w->nexthop[i].address, &link_lsa->linklocal_addr,
+                  sizeof (struct in6_addr));
+          w->nexthop[i].ifindex = ifindex;
+          i++;
+        }
+    }
+
+  if (i == 0 && IS_OSPF6_DEBUG_SPF (SUMMARY))
+    zlog_info ("No nexthop for %s found", w->name);
+}
+
+int
+ospf6_spf_install (struct ospf6_vertex *v,
+                   struct ospf6_route_table *result_table)
+{
+  struct ospf6_route *route;
+  int i, j;
+  struct ospf6_vertex *prev, *w;
+  listnode node;
+
+  if (IS_OSPF6_DEBUG_SPF (SUMMARY))
+    zlog_info ("SPF install %s hops %d cost %d",
+               v->name, v->hops, v->cost);
+
+  route = ospf6_route_lookup (&v->vertex_id, result_table);
+  if (route && route->path.cost < v->cost)
+    {
+      if (IS_OSPF6_DEBUG_SPF (SUMMARY))
+        zlog_info ("  already installed with lower cost (%d), ignore",
+                   route->path.cost);
+      ospf6_vertex_delete (v);
+      return -1;
+    }
+  else if (route && route->path.cost == v->cost)
+    {
+      if (IS_OSPF6_DEBUG_SPF (SUMMARY))
+        zlog_info ("  another path found, merge");
+
+      for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
+           i < OSPF6_MULTI_PATH_LIMIT; i++)
+        {
+          for (j = 0; j < OSPF6_MULTI_PATH_LIMIT; j++)
+            {
+              if (ospf6_nexthop_is_set (&route->nexthop[j]))
+                {
+                  if (ospf6_nexthop_is_same (&route->nexthop[j],
+                                             &v->nexthop[i]))
+                    break;
+                  else
+                    continue;
+                }
+              ospf6_nexthop_copy (&route->nexthop[j], &v->nexthop[i]);
+              break;
+            }
+        }
+
+      prev = (struct ospf6_vertex *) route->route_option;
+      if (prev->hops > v->hops)
+        {
+          LIST_LOOP (prev->child_list, w, node)
+            {
+              assert (w->parent == prev);
+              w->parent = v;
+              listnode_add_sort (v->child_list, w);
+            }
+          listnode_delete (prev->parent->child_list, prev);
+          listnode_add_sort (v->parent->child_list, v);
+
+          ospf6_vertex_delete (prev);
+          route->route_option = v;
+        }
+      else
+        ospf6_vertex_delete (v);
+
+      return -1;
+    }
+
+  /* There should be no case where candidate being installed (variable
+     "v") is closer than the one in the SPF tree (variable "route").
+     In the case something's gone wrong with the behavior of
+     Priority-Queue. */
+  assert (route == NULL);
+
+  route = ospf6_route_create ();
+  memcpy (&route->prefix, &v->vertex_id, sizeof (struct prefix));
+  route->type = OSPF6_DEST_TYPE_LINKSTATE;
+  route->path.type = OSPF6_PATH_TYPE_INTRA;
+  route->path.origin.type = v->lsa->header->type;
+  route->path.origin.id = v->lsa->header->id;
+  route->path.origin.adv_router = v->lsa->header->adv_router;
+  route->path.metric_type = 1;
+  route->path.cost = v->cost;
+  route->path.cost_e2 = v->hops;
+  route->path.router_bits = v->capability;
+  route->path.options[0] = v->options[0];
+  route->path.options[1] = v->options[1];
+  route->path.options[2] = v->options[2];
+
+  for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
+       i < OSPF6_MULTI_PATH_LIMIT; i++)
+    ospf6_nexthop_copy (&route->nexthop[i], &v->nexthop[i]);
+
+  if (v->parent)
+    listnode_add_sort (v->parent->child_list, v);
+  route->route_option = v;
+
+  ospf6_route_add (route, result_table);
   return 0;
 }
 
+void
+ospf6_spf_table_finish (struct ospf6_route_table *result_table)
+{
+  struct ospf6_route *route;
+  struct ospf6_vertex *v;
+  for (route = ospf6_route_head (result_table); route;
+       route = ospf6_route_next (route))
+    {
+      v = (struct ospf6_vertex *) route->route_option;
+      ospf6_vertex_delete (v);
+      ospf6_route_remove (route, result_table);
+    }
+}
+
+void
+ospf6_spf_calculation (u_int32_t router_id,
+                       struct ospf6_route_table *result_table,
+                       struct ospf6_area *oa)
+{
+  struct pqueue *candidate_list;
+  struct ospf6_vertex *root, *v, *w;
+  int i;
+  int size;
+  caddr_t lsdesc;
+  struct ospf6_lsa *lsa;
+
+  /* initialize */
+  candidate_list = pqueue_create ();
+  candidate_list->cmp = ospf6_vertex_cmp;
+
+  ospf6_spf_table_finish (result_table);
+
+  /* Install the calculating router itself as the root of the SPF tree */
+  /* construct root vertex */
+  lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_ROUTER), htonl (0),
+                           router_id, oa->lsdb);
+  if (lsa == NULL)
+    return;
+  root = ospf6_vertex_create (lsa);
+  root->area = oa;
+  root->cost = 0;
+  root->hops = 0;
+  root->nexthop[0].ifindex = 0; /* should have been loopbak I/F ... */
+  inet_pton (AF_INET6, "::1", &root->nexthop[0].address);
+
+  /* Actually insert root to the candidate-list as the only candidate */
+  pqueue_enqueue (root, candidate_list);
+
+  /* Iterate until candidate-list becomes empty */
+  while (candidate_list->size)
+    {
+      /* get closest candidate from priority queue */
+      v = pqueue_dequeue (candidate_list);
+
+      /* install may result in merging and rejecting of the vertex */
+      if (ospf6_spf_install (v, result_table) < 0)
+        continue;
+
+      /* For each LS description in the just-added vertex V's LSA */
+      size = (VERTEX_IS_TYPE (ROUTER, v) ?
+              sizeof (struct ospf6_router_lsdesc) :
+              sizeof (struct ospf6_network_lsdesc));
+      for (lsdesc = OSPF6_LSA_HEADER_END (v->lsa->header) + 4;
+           lsdesc + size <= OSPF6_LSA_END (v->lsa->header); lsdesc += size)
+        {
+          lsa = ospf6_lsdesc_lsa (lsdesc, v);
+          if (lsa == NULL)
+            continue;
+
+          if (! ospf6_lsdesc_backlink (lsa, lsdesc, v))
+            continue;
+
+          w = ospf6_vertex_create (lsa);
+          w->area = oa;
+          w->parent = v;
+          if (VERTEX_IS_TYPE (ROUTER, v))
+            {
+              w->cost = v->cost + ROUTER_LSDESC_GET_METRIC (lsdesc);
+              w->hops = v->hops + (VERTEX_IS_TYPE (NETWORK, w) ? 0 : 1);
+            }
+          else /* NETWORK */
+            {
+              w->cost = v->cost;
+              w->hops = v->hops + 1;
+            }
+
+          /* nexthop calculation */
+          if (w->hops == 0)
+            w->nexthop[0].ifindex = ROUTER_LSDESC_GET_IFID (lsdesc);
+          else if (w->hops == 1 && v->hops == 0)
+            ospf6_nexthop_calc (w, v, lsdesc);
+          else
+            {
+              for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) &&
+                   i < OSPF6_MULTI_PATH_LIMIT; i++)
+                ospf6_nexthop_copy (&w->nexthop[i], &v->nexthop[i]);
+            }
+
+          /* add new candidate to the candidate_list */
+          if (IS_OSPF6_DEBUG_SPF (SUMMARY))
+            zlog_info ("  New candidate: %s hops %d cost %d",
+                       w->name, w->hops, w->cost);
+          pqueue_enqueue (w, candidate_list);
+        }
+    }
+
+  pqueue_delete (candidate_list);
+}
+
 int
 ospf6_spf_calculation_thread (struct thread *t)
 {
-  struct ospf6_area *o6a;
-  struct timeval start, end, runtime, interval;
+  struct ospf6_area *oa;
+  struct timeval start, end, runtime;
 
-  o6a = (struct ospf6_area *) THREAD_ARG (t);
-  if (! o6a)
-    {
-      zlog_err ("SPF: Thread error");
-      return -1;
-    }
+  oa = (struct ospf6_area *) THREAD_ARG (t);
+  oa->thread_spf_calculation = NULL;
 
-  if (! o6a->spf_tree)
-    {
-      zlog_err ("SPF: Can't find SPF Tree for area: %s", o6a->str);
-      return -1;
-    }
+  if (IS_OSPF6_DEBUG_SPF (SUMMARY))
+    zlog_info ("SPF calculation for area %s", oa->name);
 
   /* execute SPF calculation */
   gettimeofday (&start, (struct timezone *) NULL);
-  ospf6_spf_calculation (o6a);
+  ospf6_spf_calculation (oa->ospf6->router_id, oa->spf_table, oa);
   gettimeofday (&end, (struct timezone *) NULL);
 
-  /* update statistics */
-  o6a->spf_tree->timerun ++;
-  ospf6_timeval_sub (&end, &start, &runtime);
-  ospf6_timeval_add_equal (&runtime, &o6a->spf_tree->runtime_total);
-
-  if (o6a->spf_tree->timerun == 1)
+  if (IS_OSPF6_DEBUG_SPF (SUMMARY))
     {
-      o6a->spf_tree->runtime_min.tv_sec = runtime.tv_sec;
-      o6a->spf_tree->runtime_min.tv_usec = runtime.tv_usec;
-      o6a->spf_tree->runtime_max.tv_sec = runtime.tv_sec;
-      o6a->spf_tree->runtime_max.tv_usec = runtime.tv_usec;
-    }
-  if (ospf6_timeval_cmp (o6a->spf_tree->runtime_min, runtime) > 0)
-    {
-      o6a->spf_tree->runtime_min.tv_sec = runtime.tv_sec;
-      o6a->spf_tree->runtime_min.tv_usec = runtime.tv_usec;
-    }
-  if (ospf6_timeval_cmp (runtime, o6a->spf_tree->runtime_max) > 0)
-    {
-      o6a->spf_tree->runtime_max.tv_sec = runtime.tv_sec;
-      o6a->spf_tree->runtime_max.tv_usec = runtime.tv_usec;
+      timersub (&end, &start, &runtime);
+      zlog_info ("SPF calculation for area %s: runtime %ld sec %ld usec",
+                 oa->name, runtime.tv_sec, runtime.tv_usec);
     }
 
-  if (o6a->spf_tree->timerun == 1)
-    {
-      ospf6_timeval_sub (&start, &ospf6->starttime, &interval);
-      ospf6_timeval_add_equal (&interval, &o6a->spf_tree->interval_total);
-      o6a->spf_tree->interval_min.tv_sec = interval.tv_sec;
-      o6a->spf_tree->interval_min.tv_usec = interval.tv_usec;
-      o6a->spf_tree->interval_max.tv_sec = interval.tv_sec;
-      o6a->spf_tree->interval_max.tv_usec = interval.tv_usec;
-    }
-  else
-    {
-      ospf6_timeval_sub (&start, &o6a->spf_tree->updated_time, &interval);
-      ospf6_timeval_add_equal (&interval, &o6a->spf_tree->interval_total);
-      if (ospf6_timeval_cmp (o6a->spf_tree->interval_min, interval) > 0)
-        {
-          o6a->spf_tree->interval_min.tv_sec = interval.tv_sec;
-          o6a->spf_tree->interval_min.tv_usec = interval.tv_usec;
-        }
-      if (ospf6_timeval_cmp (interval, o6a->spf_tree->interval_max) > 0)
-        {
-          o6a->spf_tree->interval_max.tv_sec = interval.tv_sec;
-          o6a->spf_tree->interval_max.tv_usec = interval.tv_usec;
-        }
-    }
-  o6a->spf_tree->updated_time.tv_sec = end.tv_sec;
-  o6a->spf_tree->updated_time.tv_usec = end.tv_usec;
-
-  /* clear thread */
-  o6a->spf_tree->t_spf_calculation = (struct thread *) NULL;
+  ospf6_intra_route_calculation (oa);
+  ospf6_intra_asbr_calculation (oa);
 
   return 0;
 }
 
 void
-ospf6_spf_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new)
+ospf6_spf_schedule (struct ospf6_area *oa)
 {
-  struct ospf6_area *o6a = NULL;
-  struct ospf6_interface *o6i = NULL;
-
-  if (new->header->type == htons (OSPF6_LSA_TYPE_ROUTER) ||
-      new->header->type == htons (OSPF6_LSA_TYPE_NETWORK))
-    o6a = new->scope;
-  else if (new->header->type == htons (OSPF6_LSA_TYPE_LINK))
-    {
-      o6i = new->scope;
-      o6a = o6i->area;
-    }
-
-  if (o6a)
-    ospf6_spf_calculation_schedule (o6a->area_id);
-}
-
-void
-ospf6_spf_calculation_schedule (u_int32_t area_id)
-{
-  struct ospf6_area *o6a;
-  char buf[64];
-
-  o6a = ospf6_area_lookup (area_id, ospf6);
-  if (! o6a)
-    {
-      inet_ntop (AF_INET, &area_id, buf, sizeof (buf));
-      zlog_err ("SPF: Can't find area: %s", buf);
-      return;
-    }
-
-  if (! o6a->spf_tree)
-    {
-      zlog_err ("SPF: Can't find SPF Tree for area: %s", o6a->str);
-      return;
-    }
-
-  if (o6a->spf_tree->t_spf_calculation)
+  if (oa->thread_spf_calculation)
     return;
-
-  o6a->spf_tree->t_spf_calculation =
-    thread_add_event (master, ospf6_spf_calculation_thread, o6a, 0);
-}
-
-struct ospf6_spftree *
-ospf6_spftree_create ()
-{
-  struct ospf6_spftree *spf_tree;
-  spf_tree = (struct ospf6_spftree *) XMALLOC (MTYPE_OSPF6_SPFTREE,
-                                               sizeof (struct ospf6_spftree));
-  if (! spf_tree)
-    {
-      zlog_err ("SPF: Can't allocate memory for SPF tree");
-      return (struct ospf6_spftree *) NULL;
-    }
-  memset (spf_tree, 0, sizeof (spf_tree));
-
-  spf_tree->list = list_new ();
-
-  return spf_tree;
+  oa->thread_spf_calculation =
+    thread_add_event (master, ospf6_spf_calculation_thread, oa, 0);
 }
 
 void
-ospf6_spftree_delete (struct ospf6_spftree *spf_tree)
+ospf6_spf_display_subtree (struct vty *vty, char *prefix, int rest,
+                           struct ospf6_vertex *v)
 {
   listnode node;
-  struct ospf6_vertex *v;
-
-  /* Delete spf tree */
-  for (node = listhead (spf_tree->list); node; nextnode (node))
-    {
-      v = (struct ospf6_vertex *) getdata (node);
-      ospf6_spf_vertex_delete (v);
-    }
-  list_delete_all_node (spf_tree->list);
-
-  XFREE (MTYPE_OSPF6_SPFTREE, spf_tree);
-}
-
-void
-ospf6_nexthop_show (struct vty *vty, struct ospf6_nexthop *nexthop)
-{
-  char buf[128], *ifname;
-  struct ospf6_interface *o6i;
-
-  ifname = NULL;
-
-  o6i = ospf6_interface_lookup_by_index (nexthop->ifindex);
-  if (! o6i)
-    {
-      zlog_err ("Spf: invalid ifindex %d in nexthop", nexthop->ifindex);
-    }
-  else
-    ifname = o6i->interface->name;
-
-  inet_ntop (AF_INET6, &nexthop->address, buf, sizeof (buf));
-  vty_out (vty, "    %s%%%s(%d)%s", buf, ifname,
-           nexthop->ifindex, VTY_NEWLINE);
-}
-
-void
-ospf6_vertex_show (struct vty *vty, struct ospf6_vertex *vertex)
-{
-  listnode node;
-  struct ospf6_vertex *v;
-  struct linklist_node lnode;
-
-  vty_out (vty, "SPF node %s%s", vertex->string, VTY_NEWLINE);
-  vty_out (vty, "  cost to this node: %d%s", vertex->distance, VTY_NEWLINE);
-  vty_out (vty, "  hops to this node: %d%s", vertex->depth, VTY_NEWLINE);
-
-  vty_out (vty, "  nexthops reachable to this node:%s", VTY_NEWLINE);
-  for (linklist_head (vertex->nexthop_list, &lnode);
-       ! linklist_end (&lnode);
-       linklist_next (&lnode))
-    ospf6_nexthop_show (vty, (struct ospf6_nexthop *) lnode.data);
-
-  vty_out (vty, "  parent nodes to this node:%s", VTY_NEWLINE);
-  if (! list_isempty (vertex->parent_list))
-    vty_out (vty, "    ");
-  for (node = listhead (vertex->parent_list); node; nextnode (node))
-    {
-      v = (struct ospf6_vertex *) getdata (node);
-      vty_out (vty, "%s ", v->string);
-    }
-  if (! list_isempty (vertex->parent_list))
-    vty_out (vty, "%s", VTY_NEWLINE);
-
-  vty_out (vty, "  child nodes to this node:%s", VTY_NEWLINE);
-  if (! list_isempty (vertex->path_list))
-    vty_out (vty, "    ");
-  for (node = listhead (vertex->path_list); node; nextnode (node))
-    {
-      v = (struct ospf6_vertex *) getdata (node);
-      vty_out (vty, "%s ", v->string);
-    }
-  if (! list_isempty (vertex->path_list))
-    vty_out (vty, "%s", VTY_NEWLINE);
-
-  vty_out (vty, "%s", VTY_NEWLINE);
-}
-
-void
-ospf6_spf_statistics_show (struct vty *vty, struct ospf6_spftree *spf_tree)
-{
-  listnode node;
-  struct ospf6_vertex *vertex;
-  u_int router_count, network_count, maxdepth;
-  struct timeval runtime_avg, interval_avg, last_updated, now;
-  char rmin[64], rmax[64], ravg[64];
-  char imin[64], imax[64], iavg[64];
-  char last_updated_string[64];
-
-  maxdepth = router_count = network_count = 0;
-  for (node = listhead (spf_tree->list); node; nextnode (node))
-    {
-      vertex = (struct ospf6_vertex *) getdata (node);
-      if (vertex->vertex_id.id.s_addr)
-        network_count++;
-      else
-        router_count++;
-      if (maxdepth < vertex->depth)
-        maxdepth = vertex->depth;
-    }
-
-  ospf6_timeval_div (&spf_tree->runtime_total, spf_tree->timerun,
-                     &runtime_avg);
-  ospf6_timeval_string (&spf_tree->runtime_min, rmin, sizeof (rmin));
-  ospf6_timeval_string (&spf_tree->runtime_max, rmax, sizeof (rmax));
-  ospf6_timeval_string (&runtime_avg, ravg, sizeof (ravg));
-
-  ospf6_timeval_div (&spf_tree->interval_total, spf_tree->timerun,
-                     &interval_avg);
-  ospf6_timeval_string (&spf_tree->interval_min, imin, sizeof (imin));
-  ospf6_timeval_string (&spf_tree->interval_max, imax, sizeof (imax));
-  ospf6_timeval_string (&interval_avg, iavg, sizeof (iavg));
-
-  gettimeofday (&now, (struct timezone *) NULL);
-  ospf6_timeval_sub (&now, &spf_tree->updated_time, &last_updated);
-  ospf6_timeval_string (&last_updated, last_updated_string,
-                        sizeof (last_updated_string));
-
-  vty_out (vty, "     SPF algorithm executed %d times%s", 
-           spf_tree->timerun, VTY_NEWLINE);
-  vty_out (vty, "     Average time to run SPF: %s%s",
-           ravg, VTY_NEWLINE);
-  vty_out (vty, "     Maximum time to run SPF: %s%s",
-           rmax, VTY_NEWLINE);
-  vty_out (vty, "     Average interval of SPF: %s%s",
-           iavg, VTY_NEWLINE);
-  vty_out (vty, "     SPF last updated: %s ago%s",
-           last_updated_string, VTY_NEWLINE);
-  vty_out (vty, "     Current SPF node count: %d%s",
-           listcount (spf_tree->list), VTY_NEWLINE);
-  vty_out (vty, "       Router: %d Network: %d%s",
-           router_count, network_count, VTY_NEWLINE);
-  vty_out (vty, "       Maximum of Hop count to nodes: %d%s",
-           maxdepth, VTY_NEWLINE);
-}
-
-DEFUN (show_ipv6_ospf6_area_spf_node,
-       show_ipv6_ospf6_area_spf_node_cmd,
-       "show ipv6 ospf6 area A.B.C.D spf node",
-       SHOW_STR
-       IP6_STR
-       OSPF6_STR
-       OSPF6_AREA_STR
-       OSPF6_AREA_ID_STR
-       "Shortest Path First caculation\n"
-       "vertex infomation\n"
-       )
-{
-  listnode i;
-  u_int32_t area_id;
-  struct ospf6_area *o6a;
-  struct ospf6_vertex *vertex;
-
-  OSPF6_CMD_CHECK_RUNNING ();
-
-  inet_pton (AF_INET, argv[0], &area_id);
-  o6a = ospf6_area_lookup (area_id, ospf6);
-  if (! o6a)
-    return CMD_SUCCESS;
-
-  for (i = listhead (o6a->spf_tree->list); i; nextnode (i))
-    {
-      vertex = (struct ospf6_vertex *) getdata (i);
-      ospf6_vertex_show (vty, vertex);
-    }
-
-  return CMD_SUCCESS;
-}
-
-static void
-ospf6_spftree_show (struct vty *vty, char *prefix, int current_rest,
-                    struct ospf6_vertex *v)
-{
-  char *p;
-  int psize;
+  struct ospf6_vertex *c;
+  char *next_prefix;
+  int len;
   int restnum;
-  listnode node;
 
-  vty_out (vty, "%s+-%s%s", prefix, v->string, VTY_NEWLINE);
+  /* "prefix" is the space prefix of the display line */
+  vty_out (vty, "%s+-%s [%d]%s", prefix, v->name, v->cost, VTY_NEWLINE);
 
-  if (listcount (v->path_list) == 0)
-    return;
-
-  psize = strlen (prefix) + 3;
-  p = malloc (psize);
-  if (!p)
+  len = strlen (prefix) + 4;
+  next_prefix = (char *) malloc (len);
+  if (next_prefix == NULL)
     {
-      vty_out (vty, "depth too long ...%s", VTY_NEWLINE);
+      vty_out (vty, "malloc failed%s", VTY_NEWLINE);
       return;
     }
+  snprintf (next_prefix, len, "%s%s", prefix, (rest ? "|  " : "   "));
 
-  restnum = listcount (v->path_list);
-  for (node = listhead (v->path_list); node; nextnode (node))
+  restnum = listcount (v->child_list);
+  LIST_LOOP (v->child_list, c, node)
     {
-      --restnum;
-      snprintf (p, psize, "%s%s", prefix, (current_rest ? "| " : "  "));
-      ospf6_spftree_show (vty, p, restnum,
-                          (struct ospf6_vertex *) getdata (node));
+      restnum--;
+      ospf6_spf_display_subtree (vty, next_prefix, restnum, c);
     }
 
-  free (p);
+  free (next_prefix);
 }
 
-DEFUN (show_ipv6_ospf6_area_spf_tree,
-       show_ipv6_ospf6_area_spf_tree_cmd,
-       "show ipv6 ospf6 area A.B.C.D spf tree",
-       SHOW_STR
-       IP6_STR
+DEFUN (debug_ospf6_spf_detail,
+       debug_ospf6_spf_detail_cmd,
+       "debug ospf6 spf detail",
+       DEBUG_STR
        OSPF6_STR
-       OSPF6_AREA_STR
-       OSPF6_AREA_ID_STR
-       "Shortest Path First caculation\n"
-       "Displays spf tree\n")
+       "Debug SPF Calculation\n"
+       "Debug Detailed SPF\n"
+      )
 {
-  u_int32_t area_id;
-  struct ospf6_area *o6a;
-
-  OSPF6_CMD_CHECK_RUNNING ();
-
-  inet_pton (AF_INET, argv[0], &area_id);
-  o6a = ospf6_area_lookup (area_id, ospf6);
-  if (! o6a)
-    return CMD_SUCCESS;
-
-  vty_out (vty, "%s        SPF tree for Area %s%s%s",
-           VTY_NEWLINE, o6a->str, VTY_NEWLINE, VTY_NEWLINE);
-
-  if (! o6a->spf_tree->root)
-    return CMD_SUCCESS;
-
-  ospf6_spftree_show (vty, "", 0, o6a->spf_tree->root);
+  unsigned char level = 0;
+  level = OSPF6_DEBUG_SPF_SUMMARY | OSPF6_DEBUG_SPF_DETAIL;
+  OSPF6_DEBUG_SPF_ON (level);
   return CMD_SUCCESS;
 }
 
-DEFUN (show_ipv6_ospf6_area_topology,
-       show_ipv6_ospf6_area_topology_cmd,
-       "show ipv6 ospf6 area A.B.C.D topology",
-       SHOW_STR
-       IP6_STR
+DEFUN (debug_ospf6_spf,
+       debug_ospf6_spf_cmd,
+       "debug ospf6 spf",
+       DEBUG_STR
        OSPF6_STR
-       OSPF6_AREA_STR
-       OSPF6_AREA_ID_STR
-       OSPF6_SPF_STR
-       "Displays SPF topology table\n")
+       "Debug SPF Calculation\n"
+      )
 {
-  struct ospf6_area *o6a;
-  u_int32_t area_id;
-
-  OSPF6_CMD_CHECK_RUNNING ();
-
-  inet_pton (AF_INET, argv[0], &area_id);
-  o6a = ospf6_area_lookup (area_id, ospf6);
-
-  if (! o6a)
-    return CMD_SUCCESS;
-
-  argc -= 1;
-  argv += 1;
-
-  return ospf6_route_table_show (vty, argc, argv, o6a->table_topology);
+  unsigned char level = 0;
+  level = OSPF6_DEBUG_SPF_SUMMARY;
+  OSPF6_DEBUG_SPF_ON (level);
+  return CMD_SUCCESS;
 }
 
-ALIAS (show_ipv6_ospf6_area_topology,
-       show_ipv6_ospf6_area_topology_router_cmd,
-       "show ipv6 ospf6 area A.B.C.D topology (A.B.C.D|<0-4294967295>|detail)",
-       SHOW_STR
-       IP6_STR
+DEFUN (no_debug_ospf6_spf_detail,
+       no_debug_ospf6_spf_detail_cmd,
+       "no debug ospf6 spf detail",
+       NO_STR
+       DEBUG_STR
        OSPF6_STR
-       OSPF6_AREA_STR
-       OSPF6_AREA_ID_STR
-       OSPF6_SPF_STR
-       "Displays SPF topology table\n"
-       OSPF6_ROUTER_ID_STR
-       OSPF6_ROUTER_ID_STR
-       )
+       "Quit Debugging SPF Calculation\n"
+       "Quit Debugging Detailed SPF (change to debug summary)\n"
+      )
+{
+  unsigned char level = 0;
+  level = OSPF6_DEBUG_SPF_DETAIL;
+  OSPF6_DEBUG_SPF_OFF (level);
+  return CMD_SUCCESS;
+}
 
-ALIAS (show_ipv6_ospf6_area_topology,
-       show_ipv6_ospf6_area_topology_router_lsid_cmd,
-       "show ipv6 ospf6 area A.B.C.D topology (A.B.C.D|<0-4294967295>) (A.B.C.D|<0-4294967295>)",
-       SHOW_STR
-       IP6_STR
+DEFUN (no_debug_ospf6_spf,
+       no_debug_ospf6_spf_cmd,
+       "no debug ospf6 spf",
+       NO_STR
+       DEBUG_STR
        OSPF6_STR
-       OSPF6_AREA_STR
-       OSPF6_AREA_ID_STR
-       OSPF6_SPF_STR
-       "Displays SPF topology table\n"
-       OSPF6_ROUTER_ID_STR
-       OSPF6_ROUTER_ID_STR
-       OSPF6_LS_ID_STR
-       OSPF6_LS_ID_STR
-       )
+       "Quit Debugging SPF Calculation\n"
+      )
+{
+  unsigned char level = 0;
+  level = OSPF6_DEBUG_SPF_SUMMARY | OSPF6_DEBUG_SPF_DETAIL;
+  OSPF6_DEBUG_SPF_OFF (level);
+  return CMD_SUCCESS;
+}
+
+int
+config_write_ospf6_debug_spf (struct vty *vty)
+{
+  if (IS_OSPF6_DEBUG_SPF (DETAIL))
+    vty_out (vty, "debug ospf6 spf detail%s", VTY_NEWLINE);
+  else if (IS_OSPF6_DEBUG_SPF (SUMMARY))
+    vty_out (vty, "debug ospf6 spf%s", VTY_NEWLINE);
+  return 0;
+}
+
+void
+install_element_ospf6_debug_spf ()
+{
+  install_element (ENABLE_NODE, &debug_ospf6_spf_cmd);
+  install_element (ENABLE_NODE, &debug_ospf6_spf_detail_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf6_spf_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf6_spf_detail_cmd);
+  install_element (CONFIG_NODE, &debug_ospf6_spf_cmd);
+  install_element (CONFIG_NODE, &debug_ospf6_spf_detail_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf6_spf_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf6_spf_detail_cmd);
+}
 
 void
 ospf6_spf_init ()
 {
-  nexthop_list = linklist_create ();
-  ospf6_spf_candidate_init ();
-  install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_node_cmd);
-  install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_tree_cmd);
-  install_element (VIEW_NODE, &show_ipv6_ospf6_area_topology_cmd);
-  install_element (VIEW_NODE, &show_ipv6_ospf6_area_topology_router_cmd);
-  install_element (VIEW_NODE, &show_ipv6_ospf6_area_topology_router_lsid_cmd);
-  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_node_cmd);
-  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_tree_cmd);
-  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_topology_cmd);
-  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_topology_router_cmd);
-  install_element (ENABLE_NODE, &show_ipv6_ospf6_area_topology_router_lsid_cmd);
 }
 
+
diff --git a/ospf6d/ospf6_spf.h b/ospf6d/ospf6_spf.h
index de50e94..1c04afb 100644
--- a/ospf6d/ospf6_spf.h
+++ b/ospf6d/ospf6_spf.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -22,7 +22,16 @@
 #ifndef OSPF6_SPF_H
 #define OSPF6_SPF_H
 
-#include "prefix.h"
+/* Debug option */
+extern unsigned char conf_debug_ospf6_spf;
+#define OSPF6_DEBUG_SPF_SUMMARY   0x01
+#define OSPF6_DEBUG_SPF_DETAIL    0x02
+#define OSPF6_DEBUG_SPF_ON(level) \
+  (conf_debug_ospf6_spf |= (level))
+#define OSPF6_DEBUG_SPF_OFF(level) \
+  (conf_debug_ospf6_spf &= ~(level))
+#define IS_OSPF6_DEBUG_SPF(level) \
+  (conf_debug_ospf6_spf & OSPF6_DEBUG_SPF_ ## level)
 
 /* Transit Vertex */
 struct ospf6_vertex
@@ -31,74 +40,53 @@
   u_int8_t type;
 
   /* Vertex Identifier */
-  struct prefix_ls vertex_id;
+  struct prefix vertex_id;
 
   /* Identifier String */
-  char string[128];
+  char name[128];
+
+  /* Associated Area */
+  struct ospf6_area *area;
 
   /* Associated LSA */
   struct ospf6_lsa *lsa;
 
-  /* Distance from Root (Cost) */
-  u_int16_t distance;
+  /* Distance from Root (i.e. Cost) */
+  u_int32_t cost;
 
-  /* Depth of this node */
-  u_char depth;
+  /* Router hops to this node */
+  u_char hops;
 
   /* nexthops to this node */
-  struct linklist *nexthop_list;
-
-  /* upper nodes in spf tree */
-  list parent_list;
-
-  /* lower nodes in spf tree */
-  list path_list;
+  struct ospf6_nexthop nexthop[OSPF6_MULTI_PATH_LIMIT];
 
   /* capability bits */
-  u_char capability_bits;
+  u_char capability;
 
   /* Optional capabilities */
-  u_char opt_capability[3];
+  u_char options[3];
+
+  /* For tree display */
+  struct ospf6_vertex *parent;
+  list child_list;
 };
 
 #define OSPF6_VERTEX_TYPE_ROUTER  0x01
 #define OSPF6_VERTEX_TYPE_NETWORK 0x02
+#define VERTEX_IS_TYPE(t, v) \
+  ((v)->type == OSPF6_VERTEX_TYPE_ ## t ? 1 : 0)
 
-struct ospf6_spftree
-{
-  /* calculation thread */
-  struct thread *t_spf_calculation;
+void ospf6_spf_table_finish (struct ospf6_route_table *result_table);
+void ospf6_spf_calculation (u_int32_t router_id,
+                            struct ospf6_route_table *result_table,
+                            struct ospf6_area *oa);
+void ospf6_spf_schedule (struct ospf6_area *oa);
 
-  /* root of this tree */
-  struct ospf6_vertex *root;
+void ospf6_spf_display_subtree (struct vty *vty, char *prefix,
+                                int rest, struct ospf6_vertex *v);
 
-  /* list for search */
-  list list;
-
-  /* statistics */
-  u_int32_t timerun;
-
-  struct timeval runtime_total;
-  struct timeval runtime_min;
-  struct timeval runtime_max;
-
-  struct timeval updated_time;
-  struct timeval interval_total;
-  struct timeval interval_min;
-  struct timeval interval_max;
-};
-
-int ospf6_spf_calculate_route (void *);
-
-void
-ospf6_spf_calculation_schedule (u_int32_t area_id);
-struct ospf6_spftree *ospf6_spftree_create ();
-void
-ospf6_spf_statistics_show (struct vty *vty, struct ospf6_spftree *spf_tree);
-void ospf6_spftree_delete (struct ospf6_spftree *spf_tree);
-
-void ospf6_spf_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new);
-
+int config_write_ospf6_debug_spf (struct vty *vty);
+void install_element_ospf6_debug_spf ();
 void ospf6_spf_init ();
 
 #endif /* OSPF6_SPF_H */
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index f9cc329..b1c1644 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -1,6 +1,5 @@
 /*
- * OSPFv3 Top Level Data Structure
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -31,299 +30,419 @@
 #include "thread.h"
 #include "command.h"
 
-#include "ospf6_hook.h"
+#include "ospf6d.h"
 #include "ospf6_proto.h"
-#include "ospf6_prefix.h"
+#include "ospf6_message.h"
 #include "ospf6_lsa.h"
 #include "ospf6_lsdb.h"
-
-#include "ospf6_message.h"
-#include "ospf6_neighbor.h"
-#include "ospf6_interface.h"
-#include "ospf6_area.h"
-#include "ospf6_top.h"
-
 #include "ospf6_route.h"
 #include "ospf6_zebra.h"
 
-#include "ospf6_nsm.h"
-#include "ospf6_asbr.h"
-#include "ospf6_abr.h"
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_interface.h"
+#include "ospf6_neighbor.h"
 
-#define HEADER_DEPENDENCY
-#include "ospf6d.h"
-#undef HEADER_DEPENDENCY
+#include "ospf6_asbr.h"
 
 /* global ospf6d variable */
 struct ospf6 *ospf6;
 
-static void
-ospf6_top_foreach_area (struct ospf6 *o6, void *arg, int val,
-                        void (*func) (void *, int, void *))
+void
+ospf6_top_lsdb_hook_add (struct ospf6_lsa *lsa)
 {
-  listnode node;
-  struct ospf6_area *o6a;
-
-  for (node = listhead (o6->area_list); node; nextnode (node))
+  switch (ntohs (lsa->header->type))
     {
-      o6a = (struct ospf6_area *) getdata (node);
-      (*func) (arg, val, o6a);
+      case OSPF6_LSTYPE_AS_EXTERNAL:
+        ospf6_asbr_lsa_add (lsa);
+        break;
+
+      default:
+        if (IS_OSPF6_DEBUG_LSA (RECV))
+          zlog_info ("Unknown LSA in AS-scoped lsdb");
+        break;
     }
 }
 
-static void
-ospf6_top_foreach_interface (struct ospf6 *o6, void *arg, int val,
-                             void (*func) (void *, int, void *))
+void
+ospf6_top_lsdb_hook_remove (struct ospf6_lsa *lsa)
 {
-  listnode node;
-  struct ospf6_area *o6a;
-
-  for (node = listhead (o6->area_list); node; nextnode (node))
+  switch (ntohs (lsa->header->type))
     {
-      o6a = (struct ospf6_area *) getdata (node);
-      (*o6a->foreach_if) (o6a, arg, val, func);
+      case OSPF6_LSTYPE_AS_EXTERNAL:
+        ospf6_asbr_lsa_remove (lsa);
+        break;
+
+      default:
+        if (IS_OSPF6_DEBUG_LSA (RECV))
+          zlog_info ("Unknown LSA in AS-scoped lsdb");
+        break;
     }
 }
 
-static void
-ospf6_top_foreach_neighbor (struct ospf6 *o6, void *arg, int val,
-                            void (*func) (void *, int, void *))
+struct ospf6 *
+ospf6_create ()
 {
-  listnode node;
-  struct ospf6_area *o6a;
+  struct ospf6 *o;
 
-  for (node = listhead (o6->area_list); node; nextnode (node))
+  o = XMALLOC (MTYPE_OSPF6_TOP, sizeof (struct ospf6));
+  memset (o, 0, sizeof (struct ospf6));
+
+  /* initialize */
+  gettimeofday (&o->starttime, (struct timezone *) NULL);
+  o->area_list = list_new ();
+  o->area_list->cmp = ospf6_area_cmp;
+  o->lsdb = ospf6_lsdb_create ();
+  o->lsdb->hook_add = ospf6_top_lsdb_hook_add;
+  o->lsdb->hook_remove = ospf6_top_lsdb_hook_remove;
+
+  o->route_table = ospf6_route_table_create ();
+  o->route_table->hook_add = ospf6_zebra_route_update_add;
+  o->route_table->hook_remove = ospf6_zebra_route_update_remove;
+
+  o->asbr_table = ospf6_route_table_create ();
+  o->asbr_table->hook_add = ospf6_asbr_lsentry_add;
+  o->asbr_table->hook_remove = ospf6_asbr_lsentry_remove;
+
+  o->external_table = ospf6_route_table_create ();
+  o->external_id_table = route_table_init ();
+
+  return o;
+}
+
+void
+ospf6_delete (struct ospf6 *o)
+{
+  listnode i;
+  struct ospf6_area *oa;
+
+  for (i = listhead (o->area_list); i; nextnode (i))
     {
-      o6a = (struct ospf6_area *) getdata (node);
-      (*o6a->foreach_nei) (o6a, arg, val, func);
+      oa = (struct ospf6_area *) getdata (i);
+      ospf6_area_delete (oa);
+    }
+
+  ospf6_lsdb_delete (o->lsdb);
+
+  ospf6_route_table_delete (o->route_table);
+  ospf6_route_table_delete (o->asbr_table);
+
+  ospf6_route_table_delete (o->external_table);
+  route_table_finish (o->external_id_table);
+
+  XFREE (MTYPE_OSPF6_TOP, o);
+}
+
+void
+ospf6_enable (struct ospf6 *o)
+{
+  listnode i;
+  struct ospf6_area *oa;
+
+  if (CHECK_FLAG (o->flag, OSPF6_DISABLED))
+    {
+      UNSET_FLAG (o->flag, OSPF6_DISABLED);
+      for (i = listhead (o->area_list); i; nextnode (i))
+        {
+          oa = (struct ospf6_area *) getdata (i);
+          ospf6_area_enable (oa);
+        }
     }
 }
 
-static int
-ospf6_top_maxage_remover (struct thread *t)
+void
+ospf6_disable (struct ospf6 *o)
 {
-  int count;
-  struct ospf6 *o6 = (struct ospf6 *) THREAD_ARG (t);
+  listnode i;
+  struct ospf6_area *oa;
 
-  o6->maxage_remover = (struct thread *) NULL;
+  if (! CHECK_FLAG (o->flag, OSPF6_DISABLED))
+    {
+      SET_FLAG (o->flag, OSPF6_DISABLED);
+      for (i = listhead (o->area_list); i; nextnode (i))
+        {
+          oa = (struct ospf6_area *) getdata (i);
+          ospf6_area_disable (oa);
+        }
 
-  count = 0;
-  o6->foreach_nei (o6, &count, NBS_EXCHANGE, ospf6_count_state);
-  o6->foreach_nei (o6, &count, NBS_LOADING, ospf6_count_state);
-  if (count != 0)
-    return 0;
+      ospf6_lsdb_remove_all (o->lsdb);
+      ospf6_route_remove_all (o->route_table);
+      ospf6_route_remove_all (o->asbr_table);
+    }
+}
 
-  ospf6_lsdb_remove_maxage (o6->lsdb);
+int
+ospf6_maxage_remover (struct thread *thread)
+{
+  struct ospf6 *o = (struct ospf6 *) THREAD_ARG (thread);
+  struct ospf6_area *oa;
+  struct ospf6_interface *oi;
+  struct ospf6_neighbor *on;
+  listnode i, j, k;
+
+  o->maxage_remover = (struct thread *) NULL;
+  if (IS_OSPF6_DEBUG_LSA (TIMER))
+    zlog_info ("Maxage Remover");
+
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      oa = (struct ospf6_area *) getdata (i);
+      for (j = listhead (oa->if_list); j; nextnode (j))
+        {
+          oi = (struct ospf6_interface *) getdata (j);
+          for (k = listhead (oi->neighbor_list); k; nextnode (k))
+            {
+              on = (struct ospf6_neighbor *) getdata (k);
+              if (on->state != OSPF6_NEIGHBOR_EXCHANGE &&
+                  on->state != OSPF6_NEIGHBOR_LOADING)
+                continue;
+
+              if (IS_OSPF6_DEBUG_LSA (TIMER))
+                zlog_info ("Maxage Remover End: %s exchange or loading",
+                           on->name);
+              return 0;
+            }
+        }
+    }
+
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      oa = (struct ospf6_area *) getdata (i);
+      for (j = listhead (oa->if_list); j; nextnode (j))
+        {
+          oi = (struct ospf6_interface *) getdata (j);
+          OSPF6_LSDB_MAXAGE_REMOVER (oi->lsdb);
+        }
+      OSPF6_LSDB_MAXAGE_REMOVER (oa->lsdb);
+    }
+  OSPF6_LSDB_MAXAGE_REMOVER (o->lsdb);
+
+  if (IS_OSPF6_DEBUG_LSA (TIMER))
+    zlog_info ("Maxage Remover End");
+
   return 0;
 }
 
 void
-ospf6_top_schedule_maxage_remover (void *arg, int val, struct ospf6 *o6)
+ospf6_maxage_remove (struct ospf6 *o)
 {
-  if (o6->maxage_remover != NULL)
-    return;
+  if (o && ! o->maxage_remover)
+    o->maxage_remover = thread_add_event (master, ospf6_maxage_remover, o, 0);
+}
 
-  o6->maxage_remover =
-    thread_add_event (master, ospf6_top_maxage_remover, o6, 0);
+/* start ospf6 */
+DEFUN (router_ospf6,
+       router_ospf6_cmd,
+       "router ospf6",
+       ROUTER_STR
+       OSPF6_STR)
+{
+  if (ospf6 == NULL)
+    ospf6 = ospf6_create ();
+  if (CHECK_FLAG (ospf6->flag, OSPF6_DISABLED))
+    ospf6_enable (ospf6);
+
+  /* set current ospf point. */
+  vty->node = OSPF6_NODE;
+  vty->index = ospf6;
+
+  return CMD_SUCCESS;
+}
+
+/* stop ospf6 */
+DEFUN (no_router_ospf6,
+       no_router_ospf6_cmd,
+       "no router ospf6",
+       NO_STR
+       OSPF6_ROUTER_STR)
+{
+  if (ospf6 == NULL || CHECK_FLAG (ospf6->flag, OSPF6_DISABLED))
+    vty_out (vty, "OSPFv3 is not running%s", VTY_NEWLINE);
+  else
+    ospf6_disable (ospf6);
+
+  /* return to config node . */
+  vty->node = CONFIG_NODE;
+  vty->index = NULL;
+
+  return CMD_SUCCESS;
+}
+
+/* change Router_ID commands. */
+DEFUN (ospf6_router_id,
+       ospf6_router_id_cmd,
+       "router-id A.B.C.D",
+       "Configure OSPF Router-ID\n"
+       V4NOTATION_STR)
+{
+  int ret;
+  u_int32_t router_id;
+  struct ospf6 *o;
+
+  o = (struct ospf6 *) vty->index;
+
+  ret = inet_pton (AF_INET, argv[0], &router_id);
+  if (ret == 0)
+    {
+      vty_out (vty, "malformed OSPF Router-ID: %s%s", argv[0], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  o->router_id = router_id;
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_interface_area,
+       ospf6_interface_area_cmd,
+       "interface IFNAME area A.B.C.D",
+       "Enable routing on an IPv6 interface\n"
+       IFNAME_STR
+       "Specify the OSPF6 area ID\n"
+       "OSPF6 area ID in IPv4 address notation\n"
+      )
+{
+  struct ospf6 *o;
+  struct ospf6_area *oa;
+  struct ospf6_interface *oi;
+  struct interface *ifp;
+  u_int32_t area_id;
+
+  o = (struct ospf6 *) vty->index;
+
+  /* find/create ospf6 interface */
+  ifp = if_get_by_name (argv[0]);
+  oi = (struct ospf6_interface *) ifp->info;
+  if (oi == NULL)
+    oi = ospf6_interface_create (ifp);
+  if (oi->area)
+    {
+      vty_out (vty, "%s already attached to Area %s%s",
+               oi->interface->name, oi->area->name, VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  /* parse Area-ID */
+  if (inet_pton (AF_INET, argv[1], &area_id) != 1)
+    {
+      vty_out (vty, "Invalid Area-ID: %s%s", argv[1], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  /* find/create ospf6 area */
+  oa = ospf6_area_lookup (area_id, o);
+  if (oa == NULL)
+    oa = ospf6_area_create (area_id, o);
+
+  /* attach interface to area */
+  listnode_add (oa->if_list, oi); /* sort ?? */
+  oi->area = oa;
+
+  /* start up */
+  thread_add_event (master, interface_up, oi, 0);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf6_interface_area,
+       no_ospf6_interface_area_cmd,
+       "no interface IFNAME area A.B.C.D",
+       NO_STR
+       "Disable routing on an IPv6 interface\n"
+       IFNAME_STR
+       "Specify the OSPF6 area ID\n"
+       "OSPF6 area ID in IPv4 address notation\n"
+       )
+{
+  struct ospf6 *o;
+  struct ospf6_interface *oi;
+  struct interface *ifp;
+  u_int32_t area_id;
+
+  o = (struct ospf6 *) vty->index;
+
+  ifp = if_lookup_by_name (argv[0]);
+  if (ifp == NULL)
+    {
+      vty_out (vty, "No such interface %s%s", argv[0], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  oi = (struct ospf6_interface *) ifp->info;
+  if (oi == NULL)
+    {
+      vty_out (vty, "Interface %s not enabled%s", ifp->name, VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  /* parse Area-ID */
+  if (inet_pton (AF_INET, argv[1], &area_id) != 1)
+    {
+      vty_out (vty, "Invalid Area-ID: %s%s", argv[1], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  if (oi->area->area_id != area_id)
+    {
+      vty_out (vty, "Wrong Area-ID: %s is attached to area %s%s",
+               oi->interface->name, oi->area->name, VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  thread_execute (master, interface_down, oi, 0);
+
+  listnode_delete (oi->area->if_list, oi);
+  oi->area = (struct ospf6_area *) NULL;
+
+  return CMD_SUCCESS;
 }
 
 void
-ospf6_show (struct vty *vty)
+ospf6_show (struct vty *vty, struct ospf6 *o)
 {
   listnode n;
-  struct ospf6_area *area;
-  char id_string[32];
-  unsigned long day, hour, min, sec;
+  struct ospf6_area *oa;
+  char router_id[16], duration[32];
   struct timeval now, running;
 
   /* process id, router id */
-  inet_ntop (AF_INET, &ospf6->router_id, id_string, sizeof (id_string));
-  vty_out (vty, " Routing Process (%lu) with ID %s%s",
-           ospf6->process_id, id_string, VTY_NEWLINE);
+  inet_ntop (AF_INET, &o->router_id, router_id, sizeof (router_id));
+  vty_out (vty, " OSPFv3 Routing Process (0) with Router-ID %s%s",
+           router_id, VTY_NEWLINE);
 
   /* running time */
   gettimeofday (&now, (struct timezone *)NULL);
-  ospf6_timeval_sub (&now, &ospf6->starttime, &running);
-  ospf6_timeval_decode (&running, &day, &hour, &min, &sec, NULL, NULL);
-  vty_out (vty, " Running %ld days %ld hours %ld minutes %ld seconds%s",
-           day, hour, min, sec, VTY_NEWLINE);
+  timersub (&now, &o->starttime, &running);
+  timerstring (&running, duration, sizeof (duration));
+  vty_out (vty, " Running %s%s", duration, VTY_NEWLINE);
 
-  vty_out (vty, " Supports only single TOS(TOS0) routes%s", VTY_NEWLINE);
-
-  /* Redistribute config */
-  ospf6_redistribute_show_config (vty);
+  /* Redistribute configuration */
+  /* XXX */
 
   /* LSAs */
   vty_out (vty, " Number of AS scoped LSAs is %u%s",
-           ospf6->lsdb->count, VTY_NEWLINE);
-  vty_out (vty, " Route calculation executed %d times%s",
-           ospf6->stat_route_calculation_execed, VTY_NEWLINE);
-
-  /* Route Statistics */
-#if 0
-  ospf6_route_statistics_show (vty, ospf6->route_table);
-#endif
+           o->lsdb->count, VTY_NEWLINE);
 
   /* Areas */
   vty_out (vty, " Number of areas in this router is %u%s",
-           listcount (ospf6->area_list), VTY_NEWLINE);
-  for (n = listhead (ospf6->area_list); n; nextnode (n))
+           listcount (o->area_list), VTY_NEWLINE);
+  for (n = listhead (o->area_list); n; nextnode (n))
     {
-      area = (struct ospf6_area *) getdata (n);
-      ospf6_area_show (vty, area);
+      oa = (struct ospf6_area *) getdata (n);
+      ospf6_area_show (vty, oa);
     }
 }
 
-void
-ospf6_statistics_show (struct vty *vty, struct ospf6 *o6)
+/* show top level structures */
+DEFUN (show_ipv6_ospf6,
+       show_ipv6_ospf6_cmd,
+       "show ipv6 ospf6",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR)
 {
-  listnode node;
-  struct ospf6_area *o6a;
-  char running_time[128];
-  struct timeval now, running;
+  OSPF6_CMD_CHECK_RUNNING ();
 
-  gettimeofday (&now, (struct timezone *) NULL);
-  ospf6_timeval_sub (&now, &o6->starttime, &running);
-  ospf6_timeval_string (&running, running_time, sizeof (running_time));
-
-  vty_out (vty, "Statistics of OSPF process %ld%s",
-           o6->process_id, VTY_NEWLINE);
-  vty_out (vty, "  Running: %s%s", running_time, VTY_NEWLINE);
-
-#if 0
-  ospf6_route_statistics_show (vty, o6->route_table);
-#endif
-
-  for (node = listhead (o6->area_list); node; nextnode (node))
-    {
-      o6a = (struct ospf6_area *) getdata (node);
-      ospf6_area_statistics_show (vty, o6a);
-    }
-}
-
-static struct ospf6 *
-ospf6_new ()
-{
-  struct ospf6 *new;
-  new = XMALLOC (MTYPE_OSPF6_TOP, sizeof (struct ospf6));
-  if (new)
-    memset (new, 0, sizeof (struct ospf6));
-  return new;
-}
-
-void
-ospf6_free (struct ospf6 *ospf6)
-{
-  XFREE (MTYPE_OSPF6_TOP, ospf6);
-}
-
-void
-ospf6_top_topology_add (struct ospf6_route_req *request)
-{
-  assert (request->route.type == OSPF6_DEST_TYPE_ROUTER);
-  if (CHECK_FLAG (request->path.router_bits, OSPF6_ROUTER_LSA_BIT_E))
-    ospf6_asbr_asbr_entry_add (request);
-}
-
-void
-ospf6_top_topology_remove (struct ospf6_route_req *request)
-{
-  assert (request->route.type == OSPF6_DEST_TYPE_ROUTER);
-  if (CHECK_FLAG (request->path.router_bits, OSPF6_ROUTER_LSA_BIT_E))
-    ospf6_asbr_asbr_entry_remove (request);
-}
-
-struct ospf6 *
-ospf6_create (unsigned long process_id)
-{
-  struct ospf6 *o6;
-  char namebuf[64];
-
-  o6 = ospf6_new ();
-
-  /* initialize */
-  gettimeofday (&o6->starttime, (struct timezone *)NULL);
-  o6->process_id = process_id;
-  o6->version = OSPF6_VERSION;
-  o6->area_list = list_new ();
-
-  o6->lsdb = ospf6_lsdb_create ();
-
-  o6->foreach_area = ospf6_top_foreach_area;
-  o6->foreach_if = ospf6_top_foreach_interface;
-  o6->foreach_nei = ospf6_top_foreach_neighbor;
-
-  snprintf (namebuf, sizeof (namebuf), "InterTopology table");
-  o6->topology_table = ospf6_route_table_create (namebuf);
-  ospf6_route_hook_register (ospf6_top_topology_add,
-                             ospf6_top_topology_add,
-                             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);
-  ospf6_route_hook_register (ospf6_zebra_route_update_add,
-                             ospf6_zebra_route_update_add,
-                             ospf6_zebra_route_update_remove,
-                             o6->route_table);
-  ospf6_route_hook_register (ospf6_abr_route_add,
-                             ospf6_abr_route_add,
-                             ospf6_abr_route_remove,
-                             o6->route_table);
-
-  return o6;
-}
-
-void
-ospf6_delete (struct ospf6 *ospf6)
-{
-  if (!ospf6)
-    return;
-
-  ospf6_route_remove_all (ospf6->route_table);
-  ospf6_free (ospf6);
-}
-
-struct ospf6 *
-ospf6_start ()
-{
-  if (ospf6)
-    return ospf6;
-
-  ospf6 = ospf6_create (0);
-  return ospf6;
-}
-
-void
-ospf6_stop ()
-{
-  if (!ospf6)
-    return;
-
-  ospf6_delete (ospf6);
-  ospf6 = NULL;
-}
-
-int
-ospf6_is_asbr (struct ospf6 *o6)
-{
-  int i = 0;
-  i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_SYSTEM);
-  i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_CONNECT);
-  i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_STATIC);
-  i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_KERNEL);
-  i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_RIPNG);
-  i |= ospf6_zebra_is_redistribute (ZEBRA_ROUTE_BGP);
-  return (i);
+  ospf6_show (vty, ospf6);
+  return CMD_SUCCESS;
 }
 
 DEFUN (show_ipv6_ospf6_route,
@@ -332,73 +451,146 @@
        SHOW_STR
        IP6_STR
        OSPF6_STR
-       "Routing table\n"
+       ROUTE_STR
        )
 {
-  OSPF6_CMD_CHECK_RUNNING ();
-  return ospf6_route_table_show (vty, argc, argv, ospf6->route_table);
+  ospf6_route_table_show (vty, argc, argv, ospf6->route_table);
+  return CMD_SUCCESS;
 }
 
 ALIAS (show_ipv6_ospf6_route,
-       show_ipv6_ospf6_route_prefix_cmd,
-       "show ipv6 ospf6 route (X::X|detail)",
+       show_ipv6_ospf6_route_detail_cmd,
+       "show ipv6 ospf6 route (X::X|X::X/M|detail|summary)",
        SHOW_STR
        IP6_STR
        OSPF6_STR
-       "Routing table\n"
-       "match IPv6 prefix\n"
-       )
+       ROUTE_STR
+       "Specify IPv6 address\n"
+       "Specify IPv6 prefix\n"
+       "Detailed information\n"
+       "Summary of route table\n"
+       );
 
-DEFUN (show_ipv6_ospf6_topology,
-       show_ipv6_ospf6_topology_cmd,
-       "show ipv6 ospf6 topology",
+DEFUN (show_ipv6_ospf6_route_match,
+       show_ipv6_ospf6_route_match_cmd,
+       "show ipv6 ospf6 route X::X/M match",
        SHOW_STR
        IP6_STR
        OSPF6_STR
-       "Inter Area topology information\n"
+       ROUTE_STR
+       "Specify IPv6 prefix\n"
+       "Display routes which match the specified route\n"
        )
 {
-  OSPF6_CMD_CHECK_RUNNING ();
-  return ospf6_route_table_show (vty, argc, argv, ospf6->topology_table);
+  char *sargv[CMD_ARGC_MAX];
+  int i, sargc;
+
+  /* copy argv to sargv and then append "match" */
+  for (i = 0; i < argc; i++)
+    sargv[i] = argv[i];
+  sargc = argc;
+  sargv[sargc++] = "match";
+  sargv[sargc] = NULL;
+
+  ospf6_route_table_show (vty, sargc, sargv, ospf6->route_table);
+  return CMD_SUCCESS;
 }
 
-ALIAS (show_ipv6_ospf6_topology,
-       show_ipv6_ospf6_topology_router_cmd,
-       "show ipv6 ospf6 topology (A.B.C.D|<0-4294967295>|detail)",
+DEFUN (show_ipv6_ospf6_route_match_detail,
+       show_ipv6_ospf6_route_match_detail_cmd,
+       "show ipv6 ospf6 route X::X/M match detail",
        SHOW_STR
        IP6_STR
        OSPF6_STR
-       "Inter Area topology information\n"
-       OSPF6_ROUTER_ID_STR
-       OSPF6_ROUTER_ID_STR
+       ROUTE_STR
+       "Specify IPv6 prefix\n"
+       "Display routes which match the specified route\n"
        "Detailed information\n"
        )
+{
+  char *sargv[CMD_ARGC_MAX];
+  int i, sargc;
 
-ALIAS (show_ipv6_ospf6_topology,
-       show_ipv6_ospf6_topology_router_lsid_cmd,
-       "show ipv6 ospf6 topology (A.B.C.D|<0-4294967295>) (A.B.C.D|<0-4294967295>)",
-       SHOW_STR
-       IP6_STR
-       OSPF6_STR
-       "Inter Area topology information\n"
-       OSPF6_ROUTER_ID_STR
-       OSPF6_ROUTER_ID_STR
-       OSPF6_LS_ID_STR
-       OSPF6_LS_ID_STR
-       )
+  /* copy argv to sargv and then append "match" and "detail" */
+  for (i = 0; i < argc; i++)
+    sargv[i] = argv[i];
+  sargc = argc;
+  sargv[sargc++] = "match";
+  sargv[sargc++] = "detail";
+  sargv[sargc] = NULL;
 
+  ospf6_route_table_show (vty, sargc, sargv, ospf6->route_table);
+  return CMD_SUCCESS;
+}
+
+
+/* OSPF configuration write function. */
+int
+config_write_ospf6 (struct vty *vty)
+{
+  char router_id[16];
+  listnode j, k;
+  struct ospf6_area *oa;
+  struct ospf6_interface *oi;
+
+  /* OSPFv6 configuration. */
+  if (ospf6 == NULL)
+    return CMD_SUCCESS;
+  if (CHECK_FLAG (ospf6->flag, OSPF6_DISABLED))
+    return CMD_SUCCESS;
+
+  inet_ntop (AF_INET, &ospf6->router_id, router_id, sizeof (router_id));
+  vty_out (vty, "router ospf6%s", VTY_NEWLINE);
+  vty_out (vty, " router-id %s%s", router_id, VTY_NEWLINE);
+
+  ospf6_redistribute_config_write (vty);
+
+  for (j = listhead (ospf6->area_list); j; nextnode (j))
+    {
+      oa = (struct ospf6_area *) getdata (j);
+      for (k = listhead (oa->if_list); k; nextnode (k))
+        {
+          oi = (struct ospf6_interface *) getdata (k);
+          vty_out (vty, " interface %s area %s%s",
+                   oi->interface->name, oa->name, VTY_NEWLINE);
+        }
+    }
+  vty_out (vty, "!%s", VTY_NEWLINE);
+  return 0;
+}
+
+/* OSPF6 node structure. */
+struct cmd_node ospf6_node =
+{
+  OSPF6_NODE,
+  "%s(config-ospf6)# ",
+};
+
+/* Install ospf related commands. */
 void
 ospf6_top_init ()
 {
+  /* Install ospf6 top node. */
+  install_node (&ospf6_node, config_write_ospf6);
+
+  install_element (VIEW_NODE, &show_ipv6_ospf6_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_cmd);
+  install_element (CONFIG_NODE, &router_ospf6_cmd);
+
   install_element (VIEW_NODE, &show_ipv6_ospf6_route_cmd);
-  install_element (VIEW_NODE, &show_ipv6_ospf6_route_prefix_cmd);
-  install_element (VIEW_NODE, &show_ipv6_ospf6_topology_cmd);
-  install_element (VIEW_NODE, &show_ipv6_ospf6_topology_router_cmd);
-  install_element (VIEW_NODE, &show_ipv6_ospf6_topology_router_lsid_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_route_detail_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_route_match_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_route_match_detail_cmd);
   install_element (ENABLE_NODE, &show_ipv6_ospf6_route_cmd);
-  install_element (ENABLE_NODE, &show_ipv6_ospf6_route_prefix_cmd);
-  install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_cmd);
-  install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_router_cmd);
-  install_element (ENABLE_NODE, &show_ipv6_ospf6_topology_router_lsid_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_route_detail_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_route_match_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_route_match_detail_cmd);
+
+  install_default (OSPF6_NODE);
+  install_element (OSPF6_NODE, &ospf6_router_id_cmd);
+  install_element (OSPF6_NODE, &ospf6_interface_area_cmd);
+  install_element (OSPF6_NODE, &no_ospf6_interface_area_cmd);
+  install_element (OSPF6_NODE, &no_router_ospf6_cmd);
 }
 
+
diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h
index 4c68756..bd1336f 100644
--- a/ospf6d/ospf6_top.h
+++ b/ospf6d/ospf6_top.h
@@ -1,6 +1,5 @@
 /*
- * OSPFv3 Top Level Data Structure
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -25,27 +24,28 @@
 
 #include "routemap.h"
 
-/* ospfv3 top level data structure */
+/* OSPFv3 top level data structure */
 struct ospf6
 {
-  /* process id */
-  u_long process_id;
+  /* my router id */
+  u_int32_t router_id;
 
   /* start time */
   struct timeval starttime;
 
-  /* ospf version must be 3 */
-  unsigned char version;
-
-  /* my router id */
-  u_int32_t router_id;
-
   /* list of areas */
   list area_list;
 
   /* AS scope link state database */
   struct ospf6_lsdb *lsdb;
 
+  struct ospf6_route_table *route_table;
+  struct ospf6_route_table *asbr_table;
+
+  struct ospf6_route_table *external_table;
+  struct route_table *external_id_table;
+  u_int32_t external_id;
+
   /* redistribute route-map */
   struct
   {
@@ -53,44 +53,21 @@
     struct route_map *map;
   } rmap[ZEBRA_ROUTE_MAX];
 
-  struct thread *t_route_calculation;
-  u_int stat_route_calculation_execed;
-
-  struct ospf6_route_table *route_table;
-  struct ospf6_route_table *topology_table;
-  struct ospf6_route_table *external_table;
-
-  void (*foreach_area) (struct ospf6 *, void *arg, int val,
-                        void (*func) (void *, int, void *));
-  void (*foreach_if)   (struct ospf6 *, void *arg, int val,
-                        void (*func) (void *, int, void *));
-  void (*foreach_nei)  (struct ospf6 *, void *arg, int val,
-                        void (*func) (void *, int, void *));
+  u_char flag;
 
   struct thread *maxage_remover;
-
-  list nexthop_list;
 };
- 
+
+#define OSPF6_DISABLED    0x01
+
+/* global pointer for OSPF top data structure */
 extern struct ospf6 *ospf6;
 
 /* prototypes */
-int
-ospf6_top_count_neighbor_in_state (u_char state, struct ospf6 *o6);
-
-void
-ospf6_top_schedule_maxage_remover (void *arg, int val, struct ospf6 *o6);
-
-void ospf6_show (struct vty *);
-void ospf6_statistics_show (struct vty *vty, struct ospf6 *o6);
-
-struct ospf6 *ospf6_start ();
-void ospf6_stop ();
-
-void ospf6_delete (struct ospf6 *);
-int ospf6_is_asbr (struct ospf6 *);
-
 void ospf6_top_init ();
 
+void ospf6_maxage_remove (struct ospf6 *o);
+
 #endif /* OSPF6_TOP_H */
 
+
diff --git a/ospf6d/ospf6_types.h b/ospf6d/ospf6_types.h
deleted file mode 100644
index 574e2f3..0000000
--- a/ospf6d/ospf6_types.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 1999 Yasuhiro Ohara
- *
- * 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.  
- */
-
-#ifndef OSPF6_TYPES_H
-#define OSPF6_TYPES_H
-
-typedef unsigned char  msgtype_t;
-typedef unsigned char  instance_id_t;
-typedef unsigned char  state_t;
-typedef unsigned char  vers_t;
-typedef unsigned char  opt_t;
-typedef unsigned char  rtr_pri_t;
-typedef unsigned char  prefixlen_t;
-typedef unsigned char  ddbits_t;
-typedef unsigned long  ddseqnum_t;
-typedef unsigned long  rtr_id_t;
-typedef unsigned long  ifid_t;
-typedef unsigned long  cost_t;
-typedef unsigned long  rxmt_int_t;
-typedef unsigned short hello_int_t;
-typedef unsigned short rtr_dead_int_t;
-typedef unsigned long  area_id_t;
-
-#endif /* OSPF6_TYPES_H */
-
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
index 4e8815f..b622086 100644
--- a/ospf6d/ospf6_zebra.c
+++ b/ospf6d/ospf6_zebra.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -19,12 +19,26 @@
  * Boston, MA 02111-1307, USA.  
  */
 
+#include <zebra.h>
+
+#include "log.h"
+#include "vty.h"
+#include "command.h"
+#include "prefix.h"
+#include "stream.h"
+#include "zclient.h"
+#include "memory.h"
+
 #include "ospf6d.h"
-
+#include "ospf6_proto.h"
+#include "ospf6_top.h"
 #include "ospf6_interface.h"
+#include "ospf6_route.h"
+#include "ospf6_lsa.h"
 #include "ospf6_asbr.h"
+#include "ospf6_zebra.h"
 
-#include "ospf6_linklist.h"
+unsigned char conf_debug_ospf6_zebra = 0;
 
 /* information about zebra. */
 struct zclient *zclient = NULL;
@@ -33,50 +47,23 @@
 void
 ospf6_zebra_redistribute (int type)
 {
-  int top_change = 0;
-
   if (zclient->redist[type])
     return;
-
-  if (! ospf6_is_asbr (ospf6))
-    top_change = 1;
-
   zclient->redist[type] = 1;
-
   if (zclient->sock > 0)
     zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, type);
-
-  if (top_change)
-    CALL_CHANGE_HOOK (&top_hook, ospf6);
 }
 
 void
 ospf6_zebra_no_redistribute (int type)
 {
-  int top_change = 0;
-
-  if (!zclient->redist[type])
+  if (! zclient->redist[type])
     return;
-
-  if (ospf6_is_asbr (ospf6))
-    top_change = 1;
-
   zclient->redist[type] = 0;
-
   if (zclient->sock > 0)
     zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type);
-
-  if (top_change)
-    CALL_CHANGE_HOOK (&top_hook, ospf6);
 }
 
-int
-ospf6_zebra_is_redistribute (int type)
-{
-  return zclient->redist[type];
-}
-
-
 /* Inteface addition message from zebra. */
 int
 ospf6_zebra_if_add (int command, struct zclient *zclient, zebra_size_t length)
@@ -84,14 +71,10 @@
   struct interface *ifp;
 
   ifp = zebra_interface_add_read (zclient->ibuf);
-
-  /* log */
-  if (IS_OSPF6_DUMP_ZEBRA)
-    zlog_info ("ZEBRA: I/F add: %s index %d mtu %d",
+  if (IS_OSPF6_DEBUG_ZEBRA (RECV))
+    zlog_info ("Zebra Interface add: %s index %d mtu %d",
                ifp->name, ifp->ifindex, ifp->mtu);
-
   ospf6_interface_if_add (ifp);
-
   return 0;
 }
 
@@ -99,18 +82,15 @@
 ospf6_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length)
 {
 #if 0
-  struct interface *ifp = NULL;
+  struct interface *ifp;
 
   ifp = zebra_interface_delete_read (zclient->ibuf);
-
-  /* log */
-  if (IS_OSPF6_DUMP_ZEBRA)
-    zlog_info ("ZEBRA: I/F delete: %s index %d mtu %d",
+  if (IS_OSPF6_DEBUG_ZEBRA (RECV))
+    zlog_info ("Zebra Interface delete: %s index %d mtu %d",
                ifp->name, ifp->ifindex, ifp->mtu);
 
   ospf6_interface_if_del (ifp);
-#endif
-
+#endif /*0*/
   return 0;
 }
 
@@ -121,10 +101,9 @@
   struct interface *ifp;
 
   ifp = zebra_interface_state_read (zclient->ibuf);
-
-  /* log */
-  if (IS_OSPF6_DUMP_ZEBRA)
-    zlog_info ("ZEBRA: I/F %s state change: index %d flags %ld metric %d mtu %d",
+  if (IS_OSPF6_DEBUG_ZEBRA (RECV))
+    zlog_info ("Zebra Interface state change: "
+                 "%s index %d flags %ld metric %d mtu %d",
                ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
 
   ospf6_interface_state_update (ifp);
@@ -133,7 +112,7 @@
 
 int
 ospf6_zebra_if_address_update_add (int command, struct zclient *zclient,
-                               zebra_size_t length)
+                                   zebra_size_t length)
 {
   struct connected *c;
   char buf[128];
@@ -142,14 +121,14 @@
   if (c == NULL)
     return 0;
 
-  if (IS_OSPF6_DUMP_ZEBRA)
-    zlog_info ("ZEBRA: I/F %s address add: %5s %s/%d",
+  if (IS_OSPF6_DEBUG_ZEBRA (RECV))
+    zlog_info ("Zebra Interface address add: %s %5s %s/%d",
                c->ifp->name, prefix_family_str (c->address),
                inet_ntop (c->address->family, &c->address->u.prefix,
                           buf, sizeof (buf)), c->address->prefixlen);
 
   if (c->address->family == AF_INET6)
-    ospf6_interface_address_update (c->ifp);
+    ospf6_interface_connected_route_update (c->ifp);
 
   return 0;
 }
@@ -165,14 +144,14 @@
   if (c == NULL)
     return 0;
 
-  if (IS_OSPF6_DUMP_ZEBRA)
-    zlog_info ("ZEBRA: I/F %s address del: %5s %s/%d",
+  if (IS_OSPF6_DEBUG_ZEBRA (RECV))
+    zlog_info ("Zebra Interface address delete: %s %5s %s/%d",
                c->ifp->name, prefix_family_str (c->address),
                inet_ntop (c->address->family, &c->address->u.prefix,
                           buf, sizeof (buf)), c->address->prefixlen);
 
   if (c->address->family == AF_INET6)
-    ospf6_interface_address_update (c->ifp);
+    ospf6_interface_connected_route_update (c->ifp);
 
   return 0;
 }
@@ -180,17 +159,8 @@
 
 
 const char *zebra_route_name[ZEBRA_ROUTE_MAX] =
-{
-  "System",
-  "Kernel",
-  "Connect",
-  "Static",
-  "RIP",
-  "RIPng",
-  "OSPF",
-  "OSPF6",
-  "BGP",
-};
+  { "System", "Kernel", "Connect", "Static", "RIP", "RIPng", "OSPF",
+    "OSPF6", "BGP" };
 
 const char *zebra_route_abname[ZEBRA_ROUTE_MAX] =
   { "X", "K", "C", "S", "r", "R", "o", "O", "B" };
@@ -204,7 +174,6 @@
   unsigned long ifindex;
   struct prefix_ipv6 p;
   struct in6_addr *nexthop;
-  char prefixstr[128], nexthopstr[128];
 
   s = zclient->ibuf;
   ifindex = 0;
@@ -244,27 +213,25 @@
   else
     api.metric = 0;
 
-  /* log */
-  if (IS_OSPF6_DUMP_ZEBRA)
+  if (IS_OSPF6_DEBUG_ZEBRA (RECV))
     {
+      char prefixstr[128], nexthopstr[128];
       prefix2str ((struct prefix *)&p, prefixstr, sizeof (prefixstr));
-      inet_ntop (AF_INET6, &nexthop, nexthopstr, sizeof (nexthopstr));
-
-      if (command == ZEBRA_IPV6_ROUTE_ADD)
-	zlog_info ("ZEBRA: Receive add %s route: %s nexthop:%s ifindex:%ld",
-		   zebra_route_name [api.type], prefixstr,
-		   nexthopstr, ifindex);
+      if (nexthop)
+        inet_ntop (AF_INET6, nexthop, nexthopstr, sizeof (nexthopstr));
       else
-	zlog_info ("ZEBRA: Receive remove %s route: %s nexthop:%s ifindex:%ld",
-		   zebra_route_name [api.type], prefixstr,
-		   nexthopstr, ifindex);
+        snprintf (nexthopstr, sizeof (nexthopstr), "::");
+
+      zlog_info ("Zebra Receive route %s: %s %s nexthop %s ifindex %ld",
+                 (command == ZEBRA_IPV6_ROUTE_ADD ? "add" : "delete"),
+                 zebra_route_name[api.type], prefixstr, nexthopstr, ifindex);
     }
  
   if (command == ZEBRA_IPV6_ROUTE_ADD)
-    ospf6_asbr_route_add (api.type, ifindex, (struct prefix *) &p,
-                          api.nexthop_num, nexthop);
+    ospf6_asbr_redistribute_add (api.type, ifindex, (struct prefix *) &p,
+                                 api.nexthop_num, nexthop);
   else
-    ospf6_asbr_route_remove (api.type, ifindex, (struct prefix *) &p);
+    ospf6_asbr_redistribute_remove (api.type, ifindex, (struct prefix *) &p);
 
   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
     free (nexthop);
@@ -272,6 +239,8 @@
   return 0;
 }
 
+
+
 
 DEFUN (show_zebra,
        show_zebra_cmd,
@@ -280,18 +249,24 @@
        "Zebra information\n")
 {
   int i;
-  if (!zclient)
-    vty_out (vty, "Not connected to zebra%s", VTY_NEWLINE);
+  if (zclient == NULL)
+    {
+      vty_out (vty, "Not connected to zebra%s", VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
 
   vty_out (vty, "Zebra Infomation%s", VTY_NEWLINE);
-  vty_out (vty, "  enable: %d%s", zclient->enable, VTY_NEWLINE);
-  vty_out (vty, "  fail: %d%s", zclient->fail, VTY_NEWLINE);
+  vty_out (vty, "  enable: %d fail: %d%s",
+           zclient->enable, zclient->fail, VTY_NEWLINE);
   vty_out (vty, "  redistribute default: %d%s", zclient->redist_default,
            VTY_NEWLINE);
+  vty_out (vty, "  redistribute:");
   for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
-    vty_out (vty, "    RouteType: %s - %s%s", zebra_route_name[i],
-             zclient->redist[i] ? "redistributed" : "not redistributed",
-             VTY_NEWLINE);
+    {
+      if (zclient->redist[i])
+        vty_out (vty, " %s", zebra_route_name[i]);
+    }
+  vty_out (vty, "%s", VTY_NEWLINE);
   return CMD_SUCCESS;
 }
 
@@ -301,9 +276,6 @@
        "Enable a routing process\n"
        "Make connection to zebra daemon\n")
 {
-  if (IS_OSPF6_DUMP_CONFIG)
-    zlog_info ("Config: router zebra");
-
   vty->node = ZEBRA_NODE;
   zclient->enable = 1;
   zclient_start (zclient);
@@ -317,9 +289,6 @@
        "Configure routing process\n"
        "Disable connection to zebra daemon\n")
 {
-  if (IS_OSPF6_DUMP_CONFIG)
-    zlog_info ("no router zebra");
-
   zclient->enable = 0;
   zclient_stop (zclient);
   return CMD_SUCCESS;
@@ -327,18 +296,18 @@
 
 /* Zebra configuration write function. */
 int
-ospf6_zebra_config_write (struct vty *vty)
+config_write_ospf6_zebra (struct vty *vty)
 {
   if (! zclient->enable)
     {
       vty_out (vty, "no router zebra%s", VTY_NEWLINE);
-      return 1;
+      vty_out (vty, "!%s", VTY_NEWLINE);
     }
   else if (! zclient->redist[ZEBRA_ROUTE_OSPF6])
     {
       vty_out (vty, "router zebra%s", VTY_NEWLINE);
       vty_out (vty, " no redistribute ospf6%s", VTY_NEWLINE);
-      return 1;
+      vty_out (vty, "!%s", VTY_NEWLINE);
     }
   return 0;
 }
@@ -348,41 +317,32 @@
 {
   ZEBRA_NODE,
   "%s(config-zebra)# ",
-  vtysh: 0
 };
 
 #define ADD    0
-#define CHANGE 1
-#define REMOVE 2
-
+#define REM    1
 static void
-ospf6_zebra_route_update (int type, struct ospf6_route_req *request)
+ospf6_zebra_route_update (int type, struct ospf6_route *request)
 {
-  char buf[96], ifname[IFNAMSIZ];
-
   struct zapi_ipv6 api;
-  struct ospf6_route_req route;
-  struct linklist *nexthop_list;
-  struct linklist_node node;
-  struct ospf6_nexthop *nexthop = NULL;
+  char buf[64], ifname[IFNAMSIZ];
+  int nhcount;
   struct in6_addr **nexthops;
   unsigned int *ifindexes;
-  struct prefix_ipv6 *p;
   int i, ret = 0;
+  struct prefix_ipv6 *dest;
 
-  if (IS_OSPF6_DUMP_ZEBRA)
+  if (IS_OSPF6_DEBUG_ZEBRA (SEND))
     {
-      prefix2str (&request->route.prefix, buf, sizeof (buf));
-      if (type == REMOVE)
-        zlog_info ("ZEBRA: Send remove route: %s", buf);
-      else
-        zlog_info ("ZEBRA: Send add route: %s", buf);
+      prefix2str (&request->prefix, buf, sizeof (buf));
+      zlog_info ("Send %s route: %s",
+                 (type == REM ? "remove" : "add"), buf);
     }
 
   if (zclient->sock < 0)
     {
-      if (IS_OSPF6_DUMP_ZEBRA)
-        zlog_info ("ZEBRA:   failed: not connected to zebra");
+      if (IS_OSPF6_DEBUG_ZEBRA (SEND))
+        zlog_info ("  Not connected to Zebra");
       return;
     }
 
@@ -390,195 +350,99 @@
       (request->path.type == OSPF6_PATH_TYPE_EXTERNAL1 ||
        request->path.type == OSPF6_PATH_TYPE_EXTERNAL2))
     {
-      if (IS_OSPF6_DUMP_ZEBRA)
-        zlog_info ("ZEBRA:   self originated external route, ignore");
+      if (IS_OSPF6_DEBUG_ZEBRA (SEND))
+        zlog_info ("  Ignore self-originated external route");
       return;
     }
 
-  /* Only the best path (i.e. the first path of the path-list
-     in 'struct ospf6_route') will be sent to zebra. */
-  ospf6_route_lookup (&route, &request->route.prefix, request->table);
-  if (memcmp (&route.path, &request->path, sizeof (route.path)))
+  /* If removing is the best path and if there's another path,
+     treat this request as add the secondary path */
+  if (type == REM && ospf6_route_is_best (request) &&
+      request->next && ospf6_route_is_same (request, request->next))
+    {
+      if (IS_OSPF6_DEBUG_ZEBRA (SEND))
+        zlog_info ("  Best-path removal resulted Sencondary addition");
+      type = ADD;
+      request = request->next;
+    }
+
+  /* Only the best path will be sent to zebra. */
+  if (! ospf6_route_is_best (request))
     {
       /* this is not preferred best route, ignore */
-      if (IS_OSPF6_DUMP_ZEBRA)
-        zlog_info ("ZEBRA:   not best path, ignore");
+      if (IS_OSPF6_DEBUG_ZEBRA (SEND))
+        zlog_info ("  Ignore non-best route");
       return;
     }
 
-  nexthop_list = linklist_create ();
+  nhcount = 0;
+  for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++)
+    if (ospf6_nexthop_is_set (&request->nexthop[i]))
+      nhcount++;
 
-  /* for each nexthop */
-  for (ospf6_route_lookup (&route, &request->route.prefix, request->table);
-       ! ospf6_route_end (&route); ospf6_route_next (&route))
+  if (nhcount == 0)
     {
-      if (memcmp (&route.path, &request->path, sizeof (route.path)))
-        break;
-
-      #define IN6_IS_ILLEGAL_NEXTHOP(a)\
-        ((*(u_int32_t *)(void *)(&(a)->s6_addr[0]) == 0xffffffff) &&\
-        (*(u_int32_t *)(void *)(&(a)->s6_addr[4]) == 0xffffffff) &&\
-        (*(u_int32_t *)(void *)(&(a)->s6_addr[8]) == 0xffffffff) &&\
-        (*(u_int32_t *)(void *)(&(a)->s6_addr[12]) == 0xffffffff))
-      if (IN6_IS_ILLEGAL_NEXTHOP (&route.nexthop.address))
-        {
-          zlog_warn ("ZEBRA: Illegal nexthop");
-          continue;
-        }
-
-      if (type == REMOVE && ! memcmp (&route.nexthop, &request->nexthop,
-                                      sizeof (struct ospf6_nexthop)))
-        continue;
-
-      nexthop = XCALLOC (MTYPE_OSPF6_OTHER, sizeof (struct ospf6_nexthop));
-      if (! nexthop)
-        {
-          zlog_warn ("ZEBRA: Can't update nexthop: malloc failed");
-          continue;
-        }
-
-      memcpy (nexthop, &route.nexthop, sizeof (struct ospf6_nexthop));
-      linklist_add (nexthop, nexthop_list);
-    }
-
-  if (type == REMOVE && nexthop_list->count != 0)
-    type = ADD;
-  else if (type == REMOVE && nexthop_list->count == 0)
-    {
-      if (IS_OSPF6_DUMP_ZEBRA)
-        zlog_info ("ZEBRA:   all nexthop with the selected path has gone");
-
-      if (! memcmp (&request->route, &route.route,
-                    sizeof (struct ospf6_route)))
-        {
-          /* send 'add' of alternative route */
-          struct ospf6_path seconde_path;
-
-          if (IS_OSPF6_DUMP_ZEBRA)
-            zlog_info ("ZEBRA:   found alternative path to add");
-
-          memcpy (&seconde_path, &route.path, sizeof (struct ospf6_path));
-          type = ADD;
-
-          while (! memcmp (&seconde_path, &route.path,
-                           sizeof (struct ospf6_path)))
-            {
-              nexthop = XCALLOC (MTYPE_OSPF6_OTHER,
-                                 sizeof (struct ospf6_nexthop));
-              if (! nexthop)
-                zlog_warn ("ZEBRA:   Can't update nexthop: malloc failed");
-              else
-                {
-                  memcpy (nexthop, &route.nexthop,
-                          sizeof (struct ospf6_nexthop));
-                  linklist_add (nexthop, nexthop_list);
-                }
-
-              ospf6_route_next (&route);
-            }
-        }
-      else
-        {
-          /* there is no alternative route. send 'remove' to zebra for
-             requested route */
-          if (IS_OSPF6_DUMP_ZEBRA)
-            zlog_info ("ZEBRA:   can't find alternative path, remove");
-
-          if (IS_OSPF6_DUMP_ZEBRA)
-            {
-              zlog_info ("ZEBRA:   Debug: walk over the route ?");
-              ospf6_route_log_request ("Debug route", "***", &route);
-              ospf6_route_log_request ("Debug request", "***", request);
-            }
-
-          nexthop = XCALLOC (MTYPE_OSPF6_OTHER,
-                             sizeof (struct ospf6_nexthop));
-          if (! nexthop)
-            zlog_warn ("ZEBRA:   Can't update nexthop: malloc failed");
-          else
-            {
-              memcpy (nexthop, &request->nexthop,
-                      sizeof (struct ospf6_nexthop));
-              linklist_add (nexthop, nexthop_list);
-            }
-        }
-    }
-
-  if (nexthop_list->count == 0)
-    {
-      if (IS_OSPF6_DUMP_ZEBRA)
-        zlog_info ("ZEBRA:   no nexthop, ignore");
-      linklist_delete (nexthop_list);
+      if (IS_OSPF6_DEBUG_ZEBRA (SEND))
+        zlog_info ("  No nexthop, ignore");
       return;
     }
 
   /* allocate memory for nexthop_list */
   nexthops = XCALLOC (MTYPE_OSPF6_OTHER,
-                      nexthop_list->count * sizeof (struct in6_addr *));
-  if (! nexthops)
+                      nhcount * sizeof (struct in6_addr *));
+  if (nexthops == NULL)
     {
-      zlog_warn ("ZEBRA:   Can't update zebra route: malloc failed");
-      for (linklist_head (nexthop_list, &node); !linklist_end (&node);
-           linklist_next (&node))
-        XFREE (MTYPE_OSPF6_OTHER, node.data);
-      linklist_delete (nexthop_list);
+      zlog_warn ("Can't send route to zebra: malloc failed");
       return;
     }
 
   /* allocate memory for ifindex_list */
   ifindexes = XCALLOC (MTYPE_OSPF6_OTHER,
-                       nexthop_list->count * sizeof (unsigned int));
-  if (! ifindexes)
+                       nhcount * sizeof (unsigned int));
+  if (ifindexes == NULL)
     {
-      zlog_warn ("ZEBRA: Can't update zebra route: malloc failed");
-      for (linklist_head (nexthop_list, &node); !linklist_end (&node);
-           linklist_next (&node))
-        XFREE (MTYPE_OSPF6_OTHER, node.data);
-      linklist_delete (nexthop_list);
+      zlog_warn ("Can't send route to zebra: malloc failed");
       XFREE (MTYPE_OSPF6_OTHER, nexthops);
       return;
     }
 
-  i = 0;
-  for (linklist_head (nexthop_list, &node); ! linklist_end (&node);
-       linklist_next (&node))
+  for (i = 0; i < nhcount; i++)
     {
-      nexthop = node.data;
-      if (IS_OSPF6_DUMP_ZEBRA)
+      if (IS_OSPF6_DEBUG_ZEBRA (SEND))
         {
-          inet_ntop (AF_INET6, &nexthop->address, buf, sizeof (buf));
-          if_indextoname (nexthop->ifindex, ifname);
-          zlog_info ("ZEBRA:   nexthop: %s%%%s(%d)",
-                     buf, ifname, nexthop->ifindex);
+          inet_ntop (AF_INET6, &request->nexthop[i].address,
+                     buf, sizeof (buf));
+          if_indextoname (request->nexthop[i].ifindex, ifname);
+          zlog_info ("  nexthop: %s%%%s(%d)", buf, ifname,
+                     request->nexthop[i].ifindex);
         }
-      nexthops[i] = &nexthop->address;
-      ifindexes[i] = nexthop->ifindex;
-      i++;
+      nexthops[i] = &request->nexthop[i].address;
+      ifindexes[i] = request->nexthop[i].ifindex;
     }
 
   api.type = ZEBRA_ROUTE_OSPF6;
   api.flags = 0;
   api.message = 0;
   SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
-  SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
-  api.nexthop_num = nexthop_list->count;
+  api.nexthop_num = nhcount;
   api.nexthop = nexthops;
-  api.ifindex_num = nexthop_list->count;
+  SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
+  api.ifindex_num = nhcount;
   api.ifindex = ifindexes;
+  SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
+  api.metric = (request->path.metric_type == 2 ?
+                request->path.cost_e2 : request->path.cost);
 
-  p = (struct prefix_ipv6 *) &request->route.prefix;
-  if (type == REMOVE && nexthop_list->count == 1)
-    ret = zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, p, &api);
+  dest = (struct prefix_ipv6 *) &request->prefix;
+  if (type == REM)
+    ret = zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, dest, &api);
   else
-    ret = zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, p, &api);
+    ret = zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, dest, &api);
 
   if (ret < 0)
-    zlog_err ("ZEBRA: zapi_ipv6_route () failed: %s", strerror (errno));
+    zlog_err ("zapi_ipv6_route() %s failed: %s",
+              (type == REM ? "delete" : "add"), strerror (errno));
 
-  for (linklist_head (nexthop_list, &node); !linklist_end (&node);
-       linklist_next (&node))
-    XFREE (MTYPE_OSPF6_OTHER, node.data);
-  linklist_delete (nexthop_list);
   XFREE (MTYPE_OSPF6_OTHER, nexthops);
   XFREE (MTYPE_OSPF6_OTHER, ifindexes);
 
@@ -586,64 +450,52 @@
 }
 
 void
-ospf6_zebra_route_update_add (struct ospf6_route_req *request)
+ospf6_zebra_route_update_add (struct ospf6_route *request)
 {
+  if (! zclient->redist[ZEBRA_ROUTE_OSPF6])
+    {
+      ospf6->route_table->hook_add = NULL;
+      ospf6->route_table->hook_remove = NULL;
+      return;
+    }
   ospf6_zebra_route_update (ADD, request);
 }
 
 void
-ospf6_zebra_route_update_remove (struct ospf6_route_req *request)
+ospf6_zebra_route_update_remove (struct ospf6_route *request)
 {
-  ospf6_zebra_route_update (REMOVE, request);
-}
-
-static void
-ospf6_zebra_redistribute_ospf6 ()
-{
-  struct route_node *node;
-
-  for (node = route_top (ospf6->route_table->table); node;
-       node = route_next (node))
+  if (! zclient->redist[ZEBRA_ROUTE_OSPF6])
     {
-      if (! node || ! node->info)
-        continue;
-      ospf6_zebra_route_update_add (node->info);
+      ospf6->route_table->hook_add = NULL;
+      ospf6->route_table->hook_remove = NULL;
+      return;
     }
+  ospf6_zebra_route_update (REM, request);
 }
 
-static void
-ospf6_zebra_no_redistribute_ospf6 ()
-{
-  struct route_node *node;
-
-  if (! ospf6)
-    return;
-
-  for (node = route_top (ospf6->route_table->table); node;
-       node = route_next (node))
-    {
-      if (! node || ! node->info)
-        continue;
-
-      ospf6_zebra_route_update_remove (node->info);
-    }
-}
-
-
 DEFUN (redistribute_ospf6,
        redistribute_ospf6_cmd,
        "redistribute ospf6",
        "Redistribute control\n"
        "OSPF6 route\n")
 {
-  /* log */
-  if (IS_OSPF6_DUMP_CONFIG)
-    zlog_info ("Config: redistribute ospf6");
+  struct ospf6_route *route;
+
+  if (zclient->redist[ZEBRA_ROUTE_OSPF6])
+    return CMD_SUCCESS;
 
   zclient->redist[ZEBRA_ROUTE_OSPF6] = 1;
 
-  /* set zebra route table */
-  ospf6_zebra_redistribute_ospf6 ();
+  if (ospf6 == NULL)
+    return CMD_SUCCESS;
+
+  /* send ospf6 route to zebra route table */
+  for (route = ospf6_route_head (ospf6->route_table); route;
+       route = ospf6_route_next (route))
+    ospf6_zebra_route_update_add (route);
+
+  ospf6->route_table->hook_add = ospf6_zebra_route_update_add;
+  ospf6->route_table->hook_remove = ospf6_zebra_route_update_remove;
 
   return CMD_SUCCESS;
 }
@@ -655,22 +507,23 @@
        "Redistribute control\n"
        "OSPF6 route\n")
 {
-  /* log */
-  if (IS_OSPF6_DUMP_CONFIG)
-    zlog_info ("Config: no redistribute ospf6");
+  struct ospf6_route *route;
+
+  if (! zclient->redist[ZEBRA_ROUTE_OSPF6])
+    return CMD_SUCCESS;
 
   zclient->redist[ZEBRA_ROUTE_OSPF6] = 0;
 
-  if (! ospf6)
+  if (ospf6 == NULL)
     return CMD_SUCCESS;
 
-  /* clean up zebra route table */
-  ospf6_zebra_no_redistribute_ospf6 ();
+  ospf6->route_table->hook_add = NULL;
+  ospf6->route_table->hook_remove = NULL;
 
-  ospf6_route_hook_unregister (ospf6_zebra_route_update_add,
-                               ospf6_zebra_route_update_add,
-                               ospf6_zebra_route_update_remove,
-                               ospf6->route_table);
+  /* withdraw ospf6 route from zebra route table */
+  for (route = ospf6_route_head (ospf6->route_table); route;
+       route = ospf6_route_next (route))
+    ospf6_zebra_route_update_remove (route);
 
   return CMD_SUCCESS;
 }
@@ -696,33 +549,120 @@
   /* ospf6_zebra_redistribute (ZEBRA_ROUTE_CONNECT); */
 
   /* Install zebra node. */
-  install_node (&zebra_node, ospf6_zebra_config_write);
+  install_node (&zebra_node, config_write_ospf6_zebra);
 
   /* Install command element for zebra node. */
   install_element (VIEW_NODE, &show_zebra_cmd);
   install_element (ENABLE_NODE, &show_zebra_cmd);
   install_element (CONFIG_NODE, &router_zebra_cmd);
   install_element (CONFIG_NODE, &no_router_zebra_cmd);
+
   install_default (ZEBRA_NODE);
   install_element (ZEBRA_NODE, &redistribute_ospf6_cmd);
   install_element (ZEBRA_NODE, &no_redistribute_ospf6_cmd);
 
-#if 0
-  hook.name = "ZebraRouteUpdate";
-  hook.hook_add = ospf6_zebra_route_update_add;
-  hook.hook_change = ospf6_zebra_route_update_add;
-  hook.hook_remove = ospf6_zebra_route_update_remove;
-  ospf6_hook_register (&hook, &route_hook);
-#endif
-
   return;
 }
 
-void
-ospf6_zebra_finish ()
+/* Debug */
+
+DEFUN (debug_ospf6_zebra_sendrecv,
+       debug_ospf6_zebra_sendrecv_cmd,
+       "debug ospf6 zebra (send|recv)",
+       DEBUG_STR
+       OSPF6_STR
+       "Debug connection between zebra\n"
+       "Debug Sending zebra\n"
+       "Debug Receiving zebra\n"
+      )
 {
-  zclient_stop (zclient);
-  zclient_free (zclient);
-  zclient = (struct zclient *) NULL;
+  unsigned char level = 0;
+
+  if (argc)
+    {
+      if (! strncmp (argv[0], "s", 1))
+        level = OSPF6_DEBUG_ZEBRA_SEND;
+      else if (! strncmp (argv[0], "r", 1))
+        level = OSPF6_DEBUG_ZEBRA_RECV;
+    }
+  else
+    level = OSPF6_DEBUG_ZEBRA_SEND | OSPF6_DEBUG_ZEBRA_RECV;
+
+  OSPF6_DEBUG_ZEBRA_ON (level);
+  return CMD_SUCCESS;
 }
 
+ALIAS (debug_ospf6_zebra_sendrecv,
+       debug_ospf6_zebra_cmd,
+       "debug ospf6 zebra",
+       DEBUG_STR
+       OSPF6_STR
+       "Debug connection between zebra\n"
+      );
+
+
+DEFUN (no_debug_ospf6_zebra_sendrecv,
+       no_debug_ospf6_zebra_sendrecv_cmd,
+       "no debug ospf6 zebra (send|recv)",
+       NO_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Debug connection between zebra\n"
+       "Debug Sending zebra\n"
+       "Debug Receiving zebra\n"
+      )
+{
+  unsigned char level = 0;
+
+  if (argc)
+    {
+      if (! strncmp (argv[0], "s", 1))
+        level = OSPF6_DEBUG_ZEBRA_SEND;
+      else if (! strncmp (argv[0], "r", 1))
+        level = OSPF6_DEBUG_ZEBRA_RECV;
+    }
+  else
+    level = OSPF6_DEBUG_ZEBRA_SEND | OSPF6_DEBUG_ZEBRA_RECV;
+
+  OSPF6_DEBUG_ZEBRA_OFF (level);
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_debug_ospf6_zebra_sendrecv,
+       no_debug_ospf6_zebra_cmd,
+       "no debug ospf6 zebra",
+       NO_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Debug connection between zebra\n"
+      );
+
+int
+config_write_ospf6_debug_zebra (struct vty *vty)
+{
+  if (IS_OSPF6_DEBUG_ZEBRA (SEND) && IS_OSPF6_DEBUG_ZEBRA (RECV))
+    vty_out (vty, "debug ospf6 zebra%s", VTY_NEWLINE);
+  else
+    {
+      if (IS_OSPF6_DEBUG_ZEBRA (SEND))
+        vty_out (vty, "debug ospf6 zebra send%s", VTY_NEWLINE);
+      if (IS_OSPF6_DEBUG_ZEBRA (RECV))
+        vty_out (vty, "debug ospf6 zebra recv%s", VTY_NEWLINE);
+    }
+  return 0;
+}
+
+void
+install_element_ospf6_debug_zebra ()
+{
+  install_element (ENABLE_NODE, &debug_ospf6_zebra_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf6_zebra_cmd);
+  install_element (ENABLE_NODE, &debug_ospf6_zebra_sendrecv_cmd);
+  install_element (ENABLE_NODE, &no_debug_ospf6_zebra_sendrecv_cmd);
+  install_element (CONFIG_NODE, &debug_ospf6_zebra_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf6_zebra_cmd);
+  install_element (CONFIG_NODE, &debug_ospf6_zebra_sendrecv_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf6_zebra_sendrecv_cmd);
+}
+
+
diff --git a/ospf6d/ospf6_zebra.h b/ospf6d/ospf6_zebra.h
index d86b2db..fb9877b 100644
--- a/ospf6d/ospf6_zebra.h
+++ b/ospf6d/ospf6_zebra.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -22,25 +22,32 @@
 #ifndef OSPF6_ZEBRA_H
 #define OSPF6_ZEBRA_H
 
+#include "zclient.h"
+
+/* Debug option */
+extern unsigned char conf_debug_ospf6_zebra;
+#define OSPF6_DEBUG_ZEBRA_SEND 0x01
+#define OSPF6_DEBUG_ZEBRA_RECV 0x02
+#define OSPF6_DEBUG_ZEBRA_ON(level) \
+  (conf_debug_ospf6_zebra |= level)
+#define OSPF6_DEBUG_ZEBRA_OFF(level) \
+  (conf_debug_ospf6_zebra &= ~(level))
+#define IS_OSPF6_DEBUG_ZEBRA(e) \
+  (conf_debug_ospf6_zebra & OSPF6_DEBUG_ZEBRA_ ## e)
+
 extern struct zclient *zclient;
 
+void ospf6_zebra_route_update_add (struct ospf6_route *request);
+void ospf6_zebra_route_update_remove (struct ospf6_route *request);
+
 void ospf6_zebra_redistribute (int);
 void ospf6_zebra_no_redistribute (int);
-int ospf6_zebra_is_redistribute (int);
-
-int ospf6_zebra_get_interface (int, struct zclient *, zebra_size_t);
-int ospf6_zebra_read (struct thread *); 
+#define ospf6_zebra_is_redistribute(type) \
+  (zclient->redist[type])
 void ospf6_zebra_init ();
-void ospf6_zebra_finish ();
-void ospf6_zebra_start ();
 
-int ospf6_zebra_read_ipv6 (int, struct zclient *, zebra_size_t);
-
-extern const char *zebra_route_name[ZEBRA_ROUTE_MAX];
-extern const char *zebra_route_abname[ZEBRA_ROUTE_MAX];
-
-void ospf6_zebra_route_update_add (struct ospf6_route_req *request);
-void ospf6_zebra_route_update_remove (struct ospf6_route_req *request);
+int config_write_ospf6_debug_zebra (struct vty *vty);
+void install_element_ospf6_debug_zebra ();
 
 #endif /*OSPF6_ZEBRA_H*/
 
diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c
index e83e1ea..362d679 100644
--- a/ospf6d/ospf6d.c
+++ b/ospf6d/ospf6d.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -19,173 +19,132 @@
  * Boston, MA 02111-1307, USA.  
  */
 
+#include <zebra.h>
+
+#include "thread.h"
+#include "linklist.h"
+#include "vty.h"
+#include "command.h"
+
 #include "ospf6d.h"
-
-#include "ospf6_damp.h"
-
-/* global ospf6d variable */
-int  ospf6_sock;
-list iflist;
-list nexthoplist = NULL;
-struct sockaddr_in6 allspfrouters6;
-struct sockaddr_in6 alldrouters6;
-char *recent_reason; /* set by ospf6_lsa_check_recent () */
-int proctitle_mode = 0;
+#include "ospf6_proto.h"
+#include "ospf6_network.h"
+#include "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+#include "ospf6_message.h"
+#include "ospf6_route.h"
+#include "ospf6_zebra.h"
+#include "ospf6_spf.h"
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_interface.h"
+#include "ospf6_neighbor.h"
+#include "ospf6_intra.h"
+#include "ospf6_asbr.h"
 
 char ospf6_daemon_version[] = OSPF6_DAEMON_VERSION;
 
-
-#define TIMER_SEC_MICRO 1000000
-
 void
-ospf6_timeval_sub (const struct timeval *t1, const struct timeval *t2,
-                   struct timeval *result)
+ospf6_debug ()
 {
-  long usec, movedown = 0;
+}
 
-  if (t1->tv_sec < t2->tv_sec ||
-      (t1->tv_sec == t2->tv_sec && t1->tv_usec < t2->tv_usec))
+static struct route_node *
+_route_next_until (struct route_node *node, struct route_node *limit)
+{
+  struct route_node *next;
+  struct route_node *start;
+
+  /* Node may be deleted from route_unlock_node so we have to preserve
+     next node's pointer. */
+
+  if (node->l_left)
     {
-      result->tv_sec = 0;
-      result->tv_usec = 0;
-      return;
+      next = node->l_left;
+      if (next == limit)
+        {
+          route_unlock_node (node);
+          return NULL;
+        }
+      route_lock_node (next);
+      route_unlock_node (node);
+      return next;
+    }
+  if (node->l_right)
+    {
+      next = node->l_right;
+      if (next == limit)
+        {
+          route_unlock_node (node);
+          return NULL;
+        }
+      route_lock_node (next);
+      route_unlock_node (node);
+      return next;
     }
 
-  if (t1->tv_usec < t2->tv_usec)
+  start = node;
+  while (node->parent)
     {
-      usec = t1->tv_usec + TIMER_SEC_MICRO;
-      movedown++;
-    }
-  else
-    usec = t1->tv_usec;
-  result->tv_usec = usec - t2->tv_usec;
-
-  result->tv_sec = t1->tv_sec - t2->tv_sec - movedown;
-}
-
-void
-ospf6_timeval_div (const struct timeval *t1, u_int by,
-                   struct timeval *result)
-{
-  long movedown;
-
-  if (by == 0)
-    {
-      result->tv_sec = 0;
-      result->tv_usec = 0;
-      return;
+      if (node->parent->l_left == node && node->parent->l_right)
+	{
+	  next = node->parent->l_right;
+          if (next == limit)
+            {
+              route_unlock_node (start);
+              return NULL;
+            }
+	  route_lock_node (next);
+	  route_unlock_node (start);
+	  return next;
+	}
+      node = node->parent;
     }
 
-  movedown = t1->tv_sec % by;
-  result->tv_sec = t1->tv_sec / by;
-  result->tv_usec = (t1->tv_usec + movedown * TIMER_SEC_MICRO) / by;
+  route_unlock_node (start);
+  return NULL;
 }
 
-void
-ospf6_timeval_decode (const struct timeval *t, long *dayp, long *hourp,
-                      long *minp, long *secp, long *msecp, long *usecp)
+struct route_node *
+route_prev (struct route_node *node)
 {
-  long day, hour, min, sec, msec, usec, left;
+  struct route_node *end;
+  struct route_node *prev = NULL;
 
-  left = t->tv_sec;
-  day = left / 86400; left -= day * 86400;
-  hour = left / 3600; left -= hour * 3600;
-  min = left / 60; left -= min * 60;
-  sec = left;
-  left = t->tv_usec;
-  msec = left / 1000; left -= msec * 1000;
-  usec = left;
+  if (node->parent == NULL)
+    {
+      route_unlock_node (node);
+      return NULL;
+    }
 
-  if (dayp) *dayp = day;
-  if (hourp) *hourp = hour;
-  if (minp) *minp = min;
-  if (secp) *secp = sec;
-  if (msecp) *msecp = msec;
-  if (usecp) *usecp = usec;
+  if (node->parent->l_left == node)
+    {
+      prev = node->parent;
+      route_lock_node (prev);
+      route_unlock_node (node);
+      return prev;
+    }
+
+  end = node;
+  node = node->parent;
+  route_lock_node (node);
+  while (node)
+    {
+      prev = node;
+      node = _route_next_until (node, end);
+    }
+  route_unlock_node (end);
+  route_lock_node (prev);
+
+  return prev;
 }
 
-void
-ospf6_timeval_string (struct timeval *tv, char *buf, int size)
-{
-  char days[16], hours[16], mins[16], secs[16], msecs[16], usecs[16];
-  long day, hour, min, sec, msec, usec;
-
-  ospf6_timeval_decode (tv, &day, &hour, &min, &sec, &msec, &usec);
-  snprintf (days, sizeof (days), "%ld days ", day);
-  snprintf (hours, sizeof (hours), "%ld hours ", hour);
-  snprintf (mins, sizeof (mins), "%ld mins ", min);
-  snprintf (secs, sizeof (secs), "%ld secs ", sec);
-  snprintf (msecs, sizeof (msecs), "%ld msecs ", msec);
-  snprintf (usecs, sizeof (usecs), "%ld usecs ", usec);
-
-  snprintf (buf, size, "%s%s%s%s%s%s",
-            (day ? days : ""), (hour ? hours : ""),
-            (min ? mins : ""), (sec ? secs : ""),
-            (msec ? msecs : ""), (usec ? usecs : ""));
-}
-
-void
-ospf6_timeval_string_summary (struct timeval *tv, char *buf, int size)
-{
-  char days[16], hours[16], mins[16], secs[16], msecs[16], usecs[16];
-  long day, hour, min, sec, msec, usec;
-
-  ospf6_timeval_decode (tv, &day, &hour, &min, &sec, &msec, &usec);
-  snprintf (days, sizeof (days), "%02ldd", day);
-  snprintf (hours, sizeof (hours), "%ldh", hour);
-  snprintf (mins, sizeof (mins), "%ldm", min);
-  snprintf (secs, sizeof (secs), "%lds", sec);
-  snprintf (msecs, sizeof (msecs), "%ldms", msec);
-  snprintf (usecs, sizeof (usecs), "%ldus", usec);
-
-  snprintf (buf, size, "%s%02ld:%02ld:%02ld",
-            (day ? days : ""), hour, min, sec);
-}
-
-/* foreach function */
-void
-ospf6_count_state (void *arg, int val, void *obj)
-{
-  int *count = (int *) arg;
-  u_char state = val;
-  struct ospf6_neighbor *nei = (struct ospf6_neighbor *) obj;
-
-  if (nei->state == state)
-    (*count)++;
-}
-
-/* VTY commands.  */
-DEFUN (reload,
-       reload_cmd,
-       "reload",
-       "Reloads\n")
-{
-  extern void _reload ();
-  _reload ();
-  return CMD_SUCCESS;
-}
-
-DEFUN (garbage_collection,
-       garbage_collection_cmd,
-       "ipv6 ospf6 garbage collect",
-       IPV6_STR
-       OSPF6_STR
-       "garbage collection by hand\n"
-       "Remove Maxages if possible and recalculate routes\n")
-{
-  ospf6_maxage_remover ();
-#if 0
-  ospf6_route_calculation_schedule ();
-#endif
-  return CMD_SUCCESS;
-}
-
-/* Show version. */
 DEFUN (show_version_ospf6,
        show_version_ospf6_cmd,
        "show version ospf6",
        SHOW_STR
-       "Displays ospf6d version\n")
+       "Displays ospf6d version\n"
+      )
 {
   vty_out (vty, "Zebra OSPF6d Version: %s%s",
            ospf6_daemon_version, VTY_NEWLINE);
@@ -193,582 +152,1103 @@
   return CMD_SUCCESS;
 }
 
-/* start ospf6 */
-DEFUN (router_ospf6,
-       router_ospf6_cmd,
-       "router ospf6",
-       OSPF6_ROUTER_STR
-       OSPF6_STR)
+struct cmd_node debug_node =
 {
-  if (ospf6 == NULL)
-    ospf6_start ();
-
-  /* set current ospf point. */
-  vty->node = OSPF6_NODE;
-  vty->index = ospf6;
-
-  return CMD_SUCCESS;
-}
-
-/* stop ospf6 */
-DEFUN (no_router_ospf6,
-       no_router_ospf6_cmd,
-       "no router ospf6",
-       NO_STR
-       OSPF6_ROUTER_STR)
-{
-  if (!ospf6)
-    vty_out (vty, "OSPFv3 is not running%s", VTY_NEWLINE);
-  else
-    ospf6_stop ();
-
-  /* return to config node . */
-  vty->node = CONFIG_NODE;
-  vty->index = NULL;
-
-  return CMD_SUCCESS;
-}
-
-/* show top level structures */
-DEFUN (show_ipv6_ospf6,
-       show_ipv6_ospf6_cmd,
-       "show ipv6 ospf6",
-       SHOW_STR
-       IP6_STR
-       OSPF6_STR)
-{
-  OSPF6_CMD_CHECK_RUNNING ();
-
-  ospf6_show (vty);
-  return CMD_SUCCESS;
-}
-
-DEFUN (show_ipv6_ospf6_nexthoplist,
-       show_ipv6_ospf6_nexthoplist_cmd,
-       "show ipv6 ospf6 nexthop-list",
-       SHOW_STR
-       IP6_STR
-       OSPF6_STR
-       "List of nexthop\n")
-{
-#if 0
-  listnode i;
-  struct ospf6_nexthop *nh;
-  char buf[128];
-  for (i = listhead (nexthoplist); i; nextnode (i))
-    {
-      nh = (struct ospf6_nexthop *) getdata (i);
-      nexthop_str (nh, buf, sizeof (buf));
-      vty_out (vty, "%s%s", buf,
-	       VTY_NEWLINE);
-    }
-#endif
-  return CMD_SUCCESS;
-}
-
-DEFUN (show_ipv6_ospf6_statistics,
-       show_ipv6_ospf6_statistics_cmd,
-       "show ipv6 ospf6 statistics",
-       SHOW_STR
-       IP6_STR
-       OSPF6_STR
-       "Statistics\n")
-{
-  OSPF6_CMD_CHECK_RUNNING ();
-
-  ospf6_statistics_show (vty, ospf6);
-  return CMD_SUCCESS;
-}
-
-/* change Router_ID commands. */
-DEFUN (ospf6_router_id,
-       ospf6_router_id_cmd,
-       "router-id ROUTER_ID",
-       "Configure ospf Router-ID.\n"
-       V4NOTATION_STR)
-{
-  int ret;
-  u_int32_t router_id;
-
-  ret = inet_pton (AF_INET, argv[0], &router_id);
-  if (!ret)
-    {
-      vty_out (vty, "malformed ospf router identifier%s", VTY_NEWLINE);
-      vty_out (vty, "%s", VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-
-  if (IS_OSPF6_DUMP_CONFIG)
-    zlog_info ("CONFIG: router-id %s", argv[0]);
-  ospf6->router_id = router_id;
-
-  return CMD_SUCCESS;
-}
+  DEBUG_NODE,
+  ""
+};
 
 int
-ospf6_interface_bind_area (struct vty *vty,
-                           char *if_name, char *area_name,
-                           char *plist_name, int passive)
+config_write_ospf6_debug (struct vty *vty)
 {
-  struct interface *ifp;
-  struct ospf6_interface *o6i;
-  struct ospf6_area *o6a;
-  u_int32_t area_id;
-
-  /* find/create ospf6 interface */
-  ifp = if_get_by_name (if_name);
-  o6i = (struct ospf6_interface *) ifp->info;
-  if (! o6i)
-    o6i = ospf6_interface_create (ifp);
-
-  /* parse Area-ID */
-  if (inet_pton (AF_INET, area_name, &area_id) != 1)
-    {
-      vty_out (vty, "Invalid Area-ID: %s%s", area_name, VTY_NEWLINE);
-      return CMD_ERR_AMBIGUOUS;
-    }
-
-  /* find/create ospf6 area */
-  o6a = ospf6_area_lookup (area_id, ospf6);
-  if (!o6a)
-    {
-      o6a = ospf6_area_create (area_id);
-      o6a->ospf6 = ospf6;
-      listnode_add (ospf6->area_list, o6a);
-    }
-
-  if (o6i->area)
-    {
-      if (o6i->area != o6a)
-        {
-          vty_out (vty, "Aready attached to area %s%s",
-                   o6i->area->str, VTY_NEWLINE);
-          return CMD_ERR_NOTHING_TODO;
-        }
-    }
-  else
-    {
-      listnode_add (o6a->if_list, o6i);
-      o6i->area = o6a;
-    }
-
-  /* prefix-list name */
-  if (plist_name)
-    {
-      if (o6i->plist_name)
-        XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name);
-      o6i->plist_name = XSTRDUP (MTYPE_PREFIX_LIST_STR, plist_name);
-    }
-  else
-    {
-      if (o6i->plist_name)
-        XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name);
-      o6i->plist_name = NULL;
-    }
-
-  if (passive)
-    {
-      listnode node;
-      struct ospf6_neighbor *o6n;
-
-      SET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
-      if (o6i->thread_send_hello)
-        {
-          thread_cancel (o6i->thread_send_hello);
-          o6i->thread_send_hello = (struct thread *) NULL;
-        }
-
-      for (node = listhead (o6i->neighbor_list); node; nextnode (node))
-        {
-          o6n = getdata (node);
-          if (o6n->inactivity_timer)
-            thread_cancel (o6n->inactivity_timer);
-          thread_execute (master, inactivity_timer, o6n, 0);
-        }
-    }
-  else
-    {
-      UNSET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
-      if (o6i->thread_send_hello == NULL)
-        thread_add_event (master, ospf6_send_hello, o6i, 0);
-    }
-
-  /* enable I/F if it's not enabled still */
-  if (! ospf6_interface_is_enabled (o6i->interface->ifindex))
-    thread_add_event (master, interface_up, o6i, 0);
-  else
-    CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
-
-  CALL_CHANGE_HOOK (&interface_hook, o6i);
-  return CMD_SUCCESS;
-}
-
-DEFUN (ospf6_interface_area_plist,
-       ospf6_interface_area_plist_cmd,
-       "interface IFNAME area A.B.C.D prefix-list WORD",
-       "Enable routing on an IPv6 interface\n"
-       IFNAME_STR
-       "Set the OSPF6 area ID\n"
-       "OSPF6 area ID in IPv4 address notation\n"
-       OSPF6_PREFIX_LIST_STR
-       "IPv6 prefix-list name\n"
-      )
-{
-  if (IS_OSPF6_DUMP_CONFIG)
-    zlog_info ("CONFIG: interface %s area %s prefix-list %s",
-               argv[0], argv[1], argv[2]);
-
-  return ospf6_interface_bind_area (vty, argv[0], argv[1], argv[2], 0);
-}
-
-DEFUN (ospf6_interface_area_plist_passive,
-       ospf6_interface_area_plist_passive_cmd,
-       "interface IFNAME area A.B.C.D prefix-list WORD passive",
-       "Enable routing on an IPv6 interface\n"
-       IFNAME_STR
-       "Set the OSPF6 area ID\n"
-       "OSPF6 area ID in IPv4 address notation\n"
-       OSPF6_PREFIX_LIST_STR
-       "IPv6 prefix-list name\n"
-       "IPv6 prefix-list name\n"
-       OSPF6_PASSIVE_STR
-      )
-{
-  if (IS_OSPF6_DUMP_CONFIG)
-    zlog_info ("CONFIG: interface %s area %s prefix-list %s passive",
-               argv[0], argv[1], argv[2]);
-
-  return ospf6_interface_bind_area (vty, argv[0], argv[1], argv[2], 1);
-}
-
-DEFUN (ospf6_interface_area,
-       ospf6_interface_area_cmd,
-       "interface IFNAME area A.B.C.D",
-       "Enable routing on an IPv6 interface\n"
-       IFNAME_STR
-       "Set the OSPF6 area ID\n"
-       "OSPF6 area ID in IPv4 address notation\n"
-      )
-{
-  struct interface *ifp;
-  struct ospf6_interface *o6i;
-  int passive;
-  char *plist_name;
-
-  if (IS_OSPF6_DUMP_CONFIG)
-    zlog_info ("CONFIG: interface %s area %s",
-               argv[0], argv[1]);
-
-  ifp = if_get_by_name (argv[0]);
-  o6i = (struct ospf6_interface *) ifp->info;
-  if (o6i)
-    {
-      passive = CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
-      plist_name = o6i->plist_name;
-    }
-  else
-    {
-      passive = 0;
-      plist_name = NULL;
-    }
-
-  return ospf6_interface_bind_area (vty, argv[0], argv[1],
-                                    plist_name, passive);
-}
-
-DEFUN (ospf6_interface_area_passive,
-       ospf6_interface_area_passive_cmd,
-       "interface IFNAME area A.B.C.D passive",
-       "Enable routing on an IPv6 interface\n"
-       IFNAME_STR
-       "Set the OSPF6 area ID\n"
-       "OSPF6 area ID in IPv4 address notation\n"
-       OSPF6_PASSIVE_STR
-      )
-{
-  if (IS_OSPF6_DUMP_CONFIG)
-    zlog_info ("CONFIG: interface %s area %s passive",
-               argv[0], argv[1]);
-
-  return ospf6_interface_bind_area (vty, argv[0], argv[1], NULL, 1);
-}
-
-DEFUN (no_ospf6_interface_area,
-       no_ospf6_interface_area_cmd,
-       "no interface IFNAME area A.B.C.D",
-       NO_STR
-       "Disable routing on an IPv6 interface\n"
-       IFNAME_STR)
-{
-  struct interface *ifp;
-  struct ospf6_interface *o6i;
-  struct ospf6 *o6;
-  u_int32_t area_id;
-
-  o6 = (struct ospf6 *) vty->index;
-
-  ifp = if_lookup_by_name (argv[0]);
-  if (!ifp)
-    return CMD_ERR_NO_MATCH;
-
-  o6i = (struct ospf6_interface *) ifp->info;
-  if (!o6i)
-    return CMD_SUCCESS;
-
-  /* parse Area-ID */
-  if (inet_pton (AF_INET, argv[1], &area_id) != 1)
-    {
-      vty_out (vty, "Invalid Area-ID: %s%s", argv[1], VTY_NEWLINE);
-      return CMD_ERR_AMBIGUOUS;
-    }
-
-  if (o6i->area->area_id != area_id)
-    {
-      vty_out (vty, "Wrong Area-ID: %s aready attached to area %s%s",
-               o6i->interface->name, o6i->area->str, VTY_NEWLINE);
-      return CMD_ERR_NOTHING_TODO;
-    }
-
-  if (o6i->area)
-    thread_execute (master, interface_down, o6i, 0);
-
-  listnode_delete (o6i->area->if_list, o6i);
-  o6i->area = (struct ospf6_area *) NULL;
-
-  return CMD_SUCCESS;
-}
-
-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"
-       "Summarize routes matching address/mask (border routers only)\n"
-       "IPv6 address range\n")
-{
-  struct ospf6 *o6;
-  struct ospf6_area *o6a;
-  u_int32_t area_id;
-  int ret;
-
-  o6 = (struct ospf6 *) vty->index;
-  inet_pton (AF_INET, argv[0], &area_id);
-  o6a = ospf6_area_lookup (area_id, o6);
-  if (! o6a)
-    {
-      vty_out (vty, "No such area%s", VTY_NEWLINE);
-      return CMD_ERR_NO_MATCH;
-    }
-
-  ret = str2prefix_ipv6 (argv[1], &o6a->area_range);
-  if (ret <= 0)
-    {
-      vty_out (vty, "Malformed IPv6 address%s", VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-
-  return CMD_SUCCESS;
-}
-
-DEFUN (ospf6_passive_interface,
-       ospf6_passive_interface_cmd,
-       "passive-interface IFNAME",
-       OSPF6_PASSIVE_STR
-       IFNAME_STR)
-{
-  struct interface *ifp;
-  struct ospf6_interface *o6i;
-
-  ifp = if_get_by_name (argv[0]);
-  if (ifp->info)
-    o6i = (struct ospf6_interface *) ifp->info;
-  else
-    o6i = ospf6_interface_create (ifp);
-
-  SET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
-
-  if (o6i->thread_send_hello)
-    {
-      thread_cancel (o6i->thread_send_hello);
-      o6i->thread_send_hello = (struct thread *) NULL;
-    }
-
-  return CMD_SUCCESS;
-}
-
-DEFUN (no_ospf6_passive_interface,
-       no_ospf6_passive_interface_cmd,
-       "no passive-interface IFNAME",
-       NO_STR
-       OSPF6_PASSIVE_STR
-       IFNAME_STR)
-{
-  struct interface *ifp;
-  struct ospf6_interface *o6i;
-
-  ifp = if_lookup_by_name (argv[0]);
-  if (! ifp)
-    return CMD_ERR_NO_MATCH;
-
-  o6i = (struct ospf6_interface *) ifp->info;
-  UNSET_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE);
-  if (o6i->thread_send_hello == NULL)
-    thread_add_event (master, ospf6_send_hello, o6i, 0);
-
-  return CMD_SUCCESS;
-}
-
-#ifdef HAVE_SETPROCTITLE
-extern int _argc;
-extern char **_argv;
-
-DEFUN (set_proctitle,
-       set_proctitle_cmd,
-       "set proctitle (version|normal|none)",
-       "Set command\n"
-       "Process title\n"
-       "Version information\n"
-       "Normal command-line options\n"
-       "Just program name\n")
-{
-  int i;
-  char buf[64], tmp[64];
-
-  if (strncmp (argv[0], "v", 1) == 0)
-    {
-      proctitle_mode = 1;
-      setproctitle ("%s Zebra: %s", OSPF6_DAEMON_VERSION, QUAGGA_VERSION);
-    }
-  else if (strncmp (argv[0], "nor", 3) == 0)
-    {
-      proctitle_mode = 0;
-      memset (tmp, 0, sizeof (tmp));
-      memset (buf, 0, sizeof (buf));
-      for (i = 0; i < _argc; i++)
-        {
-          snprintf (buf, sizeof (buf), "%s%s ", tmp, _argv[i]);
-          memcpy (&tmp, &buf, sizeof (tmp));
-        }
-      setproctitle (buf);
-    }
-  else if (strncmp (argv[0], "non", 3) == 0)
-    {
-      proctitle_mode = -1;
-      setproctitle (NULL);
-    }
-  else
-    return CMD_ERR_NO_MATCH;
-
-  return CMD_SUCCESS;
-}
-#endif /* HAVE_SETPROCTITLE */
-
-/* OSPF configuration write function. */
-int
-ospf6_config_write (struct vty *vty)
-{
-  listnode j, k;
-  char buf[64];
-  struct ospf6_area *area;
-  struct ospf6_interface *o6i;
-
-  if (proctitle_mode == 1)
-    vty_out (vty, "set proctitle version%s", VTY_NEWLINE);
-  else if (proctitle_mode == -1)
-    vty_out (vty, "set proctitle none%s", VTY_NEWLINE);
-
-  vty_out (vty, "!%s", VTY_NEWLINE);
-
-  if (! ospf6)
-    return 0;
-
-  /* OSPFv6 configuration. */
-  if (!ospf6)
-    return CMD_SUCCESS;
-
-  inet_ntop (AF_INET, &ospf6->router_id, buf, sizeof (buf));
-  vty_out (vty, "router ospf6%s", VTY_NEWLINE);
-  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))
-    {
-      area = (struct ospf6_area *)getdata (j);
-      for (k = listhead (area->if_list); k; nextnode (k))
-        {
-          o6i = (struct ospf6_interface *) getdata (k);
-          vty_out (vty, " interface %s area %s%s",
-                   o6i->interface->name, area->str, VTY_NEWLINE);
-        }
-    }
+  config_write_ospf6_debug_message (vty);
+  config_write_ospf6_debug_lsa (vty);
+  config_write_ospf6_debug_zebra (vty);
+  config_write_ospf6_debug_interface (vty);
+  config_write_ospf6_debug_neighbor (vty);
+  config_write_ospf6_debug_spf (vty);
+  config_write_ospf6_debug_route (vty);
+  config_write_ospf6_debug_asbr (vty);
   vty_out (vty, "!%s", VTY_NEWLINE);
   return 0;
 }
 
-/* OSPF6 node structure. */
-struct cmd_node ospf6_node =
+DEFUN (show_ipv6_ospf6_database,
+       show_ipv6_ospf6_database_cmd,
+       "show ipv6 ospf6 database",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+      )
 {
-  OSPF6_NODE,
-  "%s(config-ospf6)# ",
-  vtysh: 1
-};
+  listnode i, j;
+  struct ospf6 *o = ospf6;
+  void (*showfunc) (struct vty *, struct ospf6_lsa *) = NULL;
+
+  OSPF6_CMD_CHECK_RUNNING ();
+
+  if (argc)
+    {
+      if (! strncmp (argv[0], "de", 2))
+        showfunc = ospf6_lsa_show;
+      else if (! strncmp (argv[0], "du", 2))
+        showfunc = ospf6_lsa_show_dump;
+      else if (! strncmp (argv[0], "in", 2))
+        showfunc = ospf6_lsa_show_internal;
+    }
+  else
+    showfunc = ospf6_lsa_show_summary;
+
+  if (showfunc == ospf6_lsa_show_summary)
+    ospf6_lsa_show_summary_header (vty);
+
+  LSDB_FOREACH_LSA (vty, showfunc, o->lsdb);
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      LSDB_FOREACH_LSA (vty, showfunc, oa->lsdb);
+    }
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      for (j = listhead (oa->if_list); j; nextnode (j))
+        {
+          struct ospf6_interface *oi = (struct ospf6_interface *) getdata (j);
+          LSDB_FOREACH_LSA (vty, showfunc, oi->lsdb);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_database,
+       show_ipv6_ospf6_database_detail_cmd,
+       "show ipv6 ospf6 database (detail|dump|internal)",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Display details of LSAs\n"
+       "Dump LSAs\n"
+       "Display LSA's internal information\n"
+      );
+
+DEFUN (show_ipv6_ospf6_database_type,
+       show_ipv6_ospf6_database_type_cmd,
+       "show ipv6 ospf6 database "
+       "(router|network|inter-prefix|inter-router|as-external|"
+       "group-membership|type-7|link|intra-prefix)",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Display Router LSAs\n"
+       "Display Network LSAs\n"
+       "Display Inter-Area-Prefix LSAs\n"
+       "Display Inter-Area-Router LSAs\n"
+       "Display As-External LSAs\n"
+       "Display Group-Membership LSAs\n"
+       "Display Type-7 LSAs\n"
+       "Display Link LSAs\n"
+       "Display Intra-Area-Prefix LSAs\n"
+      )
+{
+  listnode i, j;
+  struct ospf6 *o = ospf6;
+  void (*showfunc) (struct vty *, struct ospf6_lsa *) = NULL;
+  u_int16_t type = 0;
+
+  OSPF6_CMD_CHECK_RUNNING ();
+
+  if (argc > 1)
+    {
+      if (! strncmp (argv[1], "de", 2))
+        showfunc = ospf6_lsa_show;
+      else if (! strncmp (argv[1], "du", 2))
+        showfunc = ospf6_lsa_show_dump;
+      else if (! strncmp (argv[1], "in", 2))
+        showfunc = ospf6_lsa_show_internal;
+    }
+  else
+    showfunc = ospf6_lsa_show_summary;
+
+  if (showfunc == ospf6_lsa_show_summary)
+    ospf6_lsa_show_summary_header (vty);
+
+  if (! strcmp (argv[0], "router"))
+    type = htons (OSPF6_LSTYPE_ROUTER);
+  else if (! strcmp (argv[0], "network"))
+    type = htons (OSPF6_LSTYPE_NETWORK);
+  else if (! strcmp (argv[0], "as-external"))
+    type = htons (OSPF6_LSTYPE_AS_EXTERNAL);
+  else if (! strcmp (argv[0], "intra-prefix"))
+    type = htons (OSPF6_LSTYPE_INTRA_PREFIX);
+  else if (! strcmp (argv[0], "inter-router"))
+    type = htons (OSPF6_LSTYPE_INTER_ROUTER);
+  else if (! strcmp (argv[0], "inter-prefix"))
+    type = htons (OSPF6_LSTYPE_INTER_PREFIX);
+  else if (! strcmp (argv[0], "link"))
+    type = htons (OSPF6_LSTYPE_LINK);
+
+  LSDB_FOREACH_LSA_T (vty, showfunc, o->lsdb, type);
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      LSDB_FOREACH_LSA_T (vty, showfunc, oa->lsdb, type);
+    }
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      for (j = listhead (oa->if_list); j; nextnode (j))
+        {
+          struct ospf6_interface *oi = (struct ospf6_interface *) getdata (j);
+          LSDB_FOREACH_LSA_T (vty, showfunc, oi->lsdb, type);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_database_type,
+       show_ipv6_ospf6_database_type_detail_cmd,
+       "show ipv6 ospf6 database "
+       "(router|network|inter-prefix|inter-router|as-external|"
+       "group-membership|type-7|link|intra-prefix) "
+       "(detail|dump|internal)",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Display Router LSAs\n"
+       "Display Network LSAs\n"
+       "Display Inter-Area-Prefix LSAs\n"
+       "Display Inter-Area-Router LSAs\n"
+       "Display As-External LSAs\n"
+       "Display Group-Membership LSAs\n"
+       "Display Type-7 LSAs\n"
+       "Display Link LSAs\n"
+       "Display Intra-Area-Prefix LSAs\n"
+       "Display details of LSAs\n"
+       "Dump LSAs\n"
+       "Display LSA's internal information\n"
+      );
+
+DEFUN (show_ipv6_ospf6_database_id,
+       show_ipv6_ospf6_database_id_cmd,
+       "show ipv6 ospf6 database * A.B.C.D",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Any Link state Type\n"
+       "Specify Link state ID as IPv4 address notation\n"
+      )
+{
+  listnode i, j;
+  struct ospf6 *o = ospf6;
+  void (*showfunc) (struct vty *, struct ospf6_lsa *) = NULL;
+  u_int32_t id = 0;
+
+  OSPF6_CMD_CHECK_RUNNING ();
+
+  if (argc > 1)
+    {
+      if (! strncmp (argv[1], "de", 2))
+        showfunc = ospf6_lsa_show;
+      else if (! strncmp (argv[1], "du", 2))
+        showfunc = ospf6_lsa_show_dump;
+      else if (! strncmp (argv[1], "in", 2))
+        showfunc = ospf6_lsa_show_internal;
+    }
+  else
+    showfunc = ospf6_lsa_show_summary;
+
+  if (showfunc == ospf6_lsa_show_summary)
+    ospf6_lsa_show_summary_header (vty);
+
+  if ((inet_pton (AF_INET, argv[0], &id)) != 1)
+    {
+      vty_out (vty, "Link State ID is not parsable: %s%s",
+               argv[0], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  LSDB_FOREACH_LSA_I (vty, showfunc, o->lsdb, id);
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      LSDB_FOREACH_LSA_I (vty, showfunc, oa->lsdb, id);
+    }
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      for (j = listhead (oa->if_list); j; nextnode (j))
+        {
+          struct ospf6_interface *oi = (struct ospf6_interface *) getdata (j);
+          LSDB_FOREACH_LSA_I (vty, showfunc, oi->lsdb, id);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_database_id,
+       show_ipv6_ospf6_database_id_detail_cmd,
+       "show ipv6 ospf6 database * A.B.C.D "
+       "(detail|dump|internal)",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Any Link state Type\n"
+       "Any Link state ID\n"
+       "Specify Link state ID as IPv4 address notation\n"
+       "Display details of LSAs\n"
+       "Dump LSAs\n"
+       "Display LSA's internal information\n"
+      );
+
+DEFUN (show_ipv6_ospf6_database_router,
+       show_ipv6_ospf6_database_router_cmd,
+       "show ipv6 ospf6 database * * A.B.C.D",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Any Link state Type\n"
+       "Any Link state ID\n"
+       "Specify Advertising Router as IPv4 address notation\n"
+      )
+{
+  listnode i, j;
+  struct ospf6 *o = ospf6;
+  void (*showfunc) (struct vty *, struct ospf6_lsa *) = NULL;
+  u_int32_t router = 0;
+
+  OSPF6_CMD_CHECK_RUNNING ();
+
+  if (argc > 1)
+    {
+      if (! strncmp (argv[1], "de", 2))
+        showfunc = ospf6_lsa_show;
+      else if (! strncmp (argv[1], "du", 2))
+        showfunc = ospf6_lsa_show_dump;
+      else if (! strncmp (argv[1], "in", 2))
+        showfunc = ospf6_lsa_show_internal;
+    }
+  else
+    showfunc = ospf6_lsa_show_summary;
+
+  if (showfunc == ospf6_lsa_show_summary)
+    ospf6_lsa_show_summary_header (vty);
+
+  if ((inet_pton (AF_INET, argv[0], &router)) != 1)
+    {
+      vty_out (vty, "Advertising Router is not parsable: %s%s",
+               argv[0], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  LSDB_FOREACH_LSA_R (vty, showfunc, o->lsdb, router);
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      LSDB_FOREACH_LSA_R (vty, showfunc, oa->lsdb, router);
+    }
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      for (j = listhead (oa->if_list); j; nextnode (j))
+        {
+          struct ospf6_interface *oi = (struct ospf6_interface *) getdata (j);
+          LSDB_FOREACH_LSA_R (vty, showfunc, oi->lsdb, router);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_database_router,
+       show_ipv6_ospf6_database_router_detail_cmd,
+       "show ipv6 ospf6 database * * A.B.C.D "
+       "(detail|dump|internal)",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Any Link state Type\n"
+       "Any Link state ID\n"
+       "Specify Advertising Router as IPv4 address notation\n"
+       "Display details of LSAs\n"
+       "Dump LSAs\n"
+       "Display LSA's internal information\n"
+      );
+
+DEFUN (show_ipv6_ospf6_database_type_id,
+       show_ipv6_ospf6_database_type_id_cmd,
+       "show ipv6 ospf6 database "
+       "(router|network|inter-prefix|inter-router|as-external|"
+       "group-membership|type-7|link|intra-prefix) A.B.C.D",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Display Router LSAs\n"
+       "Display Network LSAs\n"
+       "Display Inter-Area-Prefix LSAs\n"
+       "Display Inter-Area-Router LSAs\n"
+       "Display As-External LSAs\n"
+       "Display Group-Membership LSAs\n"
+       "Display Type-7 LSAs\n"
+       "Display Link LSAs\n"
+       "Display Intra-Area-Prefix LSAs\n"
+       "Specify Link state ID as IPv4 address notation\n"
+      )
+{
+  listnode i, j;
+  struct ospf6 *o = ospf6;
+  void (*showfunc) (struct vty *, struct ospf6_lsa *) = NULL;
+  u_int16_t type = 0;
+  u_int32_t id = 0;
+
+  OSPF6_CMD_CHECK_RUNNING ();
+
+  if (argc > 2)
+    {
+      if (! strncmp (argv[2], "de", 2))
+        showfunc = ospf6_lsa_show;
+      else if (! strncmp (argv[2], "du", 2))
+        showfunc = ospf6_lsa_show_dump;
+      else if (! strncmp (argv[2], "in", 2))
+        showfunc = ospf6_lsa_show_internal;
+    }
+  else
+    showfunc = ospf6_lsa_show_summary;
+
+  if (showfunc == ospf6_lsa_show_summary)
+    ospf6_lsa_show_summary_header (vty);
+
+  if (! strcmp (argv[0], "router"))
+    type = htons (OSPF6_LSTYPE_ROUTER);
+  else if (! strcmp (argv[0], "network"))
+    type = htons (OSPF6_LSTYPE_NETWORK);
+  else if (! strcmp (argv[0], "as-external"))
+    type = htons (OSPF6_LSTYPE_AS_EXTERNAL);
+  else if (! strcmp (argv[0], "intra-prefix"))
+    type = htons (OSPF6_LSTYPE_INTRA_PREFIX);
+  else if (! strcmp (argv[0], "inter-router"))
+    type = htons (OSPF6_LSTYPE_INTER_ROUTER);
+  else if (! strcmp (argv[0], "inter-prefix"))
+    type = htons (OSPF6_LSTYPE_INTER_PREFIX);
+  else if (! strcmp (argv[0], "link"))
+    type = htons (OSPF6_LSTYPE_LINK);
+
+  if ((inet_pton (AF_INET, argv[1], &id)) != 1)
+    {
+      vty_out (vty, "Link state ID is not parsable: %s%s",
+               argv[1], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  LSDB_FOREACH_LSA_TI (vty, showfunc, o->lsdb, type, id);
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      LSDB_FOREACH_LSA_TI (vty, showfunc, oa->lsdb, type, id);
+    }
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      for (j = listhead (oa->if_list); j; nextnode (j))
+        {
+          struct ospf6_interface *oi = (struct ospf6_interface *) getdata (j);
+          LSDB_FOREACH_LSA_TI (vty, showfunc, oi->lsdb, type, id);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_database_type_id,
+       show_ipv6_ospf6_database_type_id_detail_cmd,
+       "show ipv6 ospf6 database "
+       "(router|network|inter-prefix|inter-router|as-external|"
+       "group-membership|type-7|link|intra-prefix) A.B.C.D "
+       "(detail|dump|internal)",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Display Router LSAs\n"
+       "Display Network LSAs\n"
+       "Display Inter-Area-Prefix LSAs\n"
+       "Display Inter-Area-Router LSAs\n"
+       "Display As-External LSAs\n"
+       "Display Group-Membership LSAs\n"
+       "Display Type-7 LSAs\n"
+       "Display Link LSAs\n"
+       "Display Intra-Area-Prefix LSAs\n"
+       "Specify Link state ID as IPv4 address notation\n"
+       "Display details of LSAs\n"
+       "Dump LSAs\n"
+       "Display LSA's internal information\n"
+      );
+
+DEFUN (show_ipv6_ospf6_database_type_router,
+       show_ipv6_ospf6_database_type_router_cmd,
+       "show ipv6 ospf6 database "
+       "(router|network|inter-prefix|inter-router|as-external|"
+       "group-membership|type-7|link|intra-prefix) * A.B.C.D",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Display Router LSAs\n"
+       "Display Network LSAs\n"
+       "Display Inter-Area-Prefix LSAs\n"
+       "Display Inter-Area-Router LSAs\n"
+       "Display As-External LSAs\n"
+       "Display Group-Membership LSAs\n"
+       "Display Type-7 LSAs\n"
+       "Display Link LSAs\n"
+       "Display Intra-Area-Prefix LSAs\n"
+       "Any Link state ID\n"
+       "Specify Advertising Router as IPv4 address notation\n"
+      )
+{
+  listnode i, j;
+  struct ospf6 *o = ospf6;
+  void (*showfunc) (struct vty *, struct ospf6_lsa *) = NULL;
+  u_int16_t type = 0;
+  u_int32_t router = 0;
+
+  OSPF6_CMD_CHECK_RUNNING ();
+
+  if (argc > 2)
+    {
+      if (! strncmp (argv[2], "de", 2))
+        showfunc = ospf6_lsa_show;
+      else if (! strncmp (argv[2], "du", 2))
+        showfunc = ospf6_lsa_show_dump;
+      else if (! strncmp (argv[2], "in", 2))
+        showfunc = ospf6_lsa_show_internal;
+    }
+  else
+    showfunc = ospf6_lsa_show_summary;
+
+  if (showfunc == ospf6_lsa_show_summary)
+    ospf6_lsa_show_summary_header (vty);
+
+  if (! strcmp (argv[0], "router"))
+    type = htons (OSPF6_LSTYPE_ROUTER);
+  else if (! strcmp (argv[0], "network"))
+    type = htons (OSPF6_LSTYPE_NETWORK);
+  else if (! strcmp (argv[0], "as-external"))
+    type = htons (OSPF6_LSTYPE_AS_EXTERNAL);
+  else if (! strcmp (argv[0], "intra-prefix"))
+    type = htons (OSPF6_LSTYPE_INTRA_PREFIX);
+  else if (! strcmp (argv[0], "inter-router"))
+    type = htons (OSPF6_LSTYPE_INTER_ROUTER);
+  else if (! strcmp (argv[0], "inter-prefix"))
+    type = htons (OSPF6_LSTYPE_INTER_PREFIX);
+  else if (! strcmp (argv[0], "link"))
+    type = htons (OSPF6_LSTYPE_LINK);
+
+  if ((inet_pton (AF_INET, argv[1], &router)) != 1)
+    {
+      vty_out (vty, "Advertising Router is not parsable: %s%s",
+               argv[1], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  LSDB_FOREACH_LSA_TR (vty, showfunc, o->lsdb, type, router);
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      LSDB_FOREACH_LSA_TR (vty, showfunc, oa->lsdb, type, router);
+    }
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      for (j = listhead (oa->if_list); j; nextnode (j))
+        {
+          struct ospf6_interface *oi = (struct ospf6_interface *) getdata (j);
+          LSDB_FOREACH_LSA_TR (vty, showfunc, oi->lsdb, type, router);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_database_type_router,
+       show_ipv6_ospf6_database_type_router_detail_cmd,
+       "show ipv6 ospf6 database "
+       "(router|network|inter-prefix|inter-router|as-external|"
+       "group-membership|type-7|link|intra-prefix) * A.B.C.D "
+       "(detail|dump|internal)",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Display Router LSAs\n"
+       "Display Network LSAs\n"
+       "Display Inter-Area-Prefix LSAs\n"
+       "Display Inter-Area-Router LSAs\n"
+       "Display As-External LSAs\n"
+       "Display Group-Membership LSAs\n"
+       "Display Type-7 LSAs\n"
+       "Display Link LSAs\n"
+       "Display Intra-Area-Prefix LSAs\n"
+       "Any Link state ID\n"
+       "Specify Advertising Router as IPv4 address notation\n"
+       "Display details of LSAs\n"
+       "Dump LSAs\n"
+       "Display LSA's internal information\n"
+      );
+
+DEFUN (show_ipv6_ospf6_database_id_router,
+       show_ipv6_ospf6_database_id_router_cmd,
+       "show ipv6 ospf6 database * A.B.C.D A.B.C.D",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Any Link state Type\n"
+       "Specify Link state ID as IPv4 address notation\n"
+       "Specify Advertising Router as IPv4 address notation\n"
+      )
+{
+  listnode i, j;
+  struct ospf6 *o = ospf6;
+  void (*showfunc) (struct vty *, struct ospf6_lsa *) = NULL;
+  u_int32_t id = 0;
+  u_int32_t router = 0;
+
+  OSPF6_CMD_CHECK_RUNNING ();
+
+  if (argc > 2)
+    {
+      if (! strncmp (argv[2], "de", 2))
+        showfunc = ospf6_lsa_show;
+      else if (! strncmp (argv[2], "du", 2))
+        showfunc = ospf6_lsa_show_dump;
+      else if (! strncmp (argv[2], "in", 2))
+        showfunc = ospf6_lsa_show_internal;
+    }
+  else
+    showfunc = ospf6_lsa_show_summary;
+
+  if (showfunc == ospf6_lsa_show_summary)
+    ospf6_lsa_show_summary_header (vty);
+
+  if ((inet_pton (AF_INET, argv[0], &id)) != 1)
+    {
+      vty_out (vty, "Link state ID is not parsable: %s%s",
+               argv[1], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  if ((inet_pton (AF_INET, argv[1], &router)) != 1)
+    {
+      vty_out (vty, "Advertising Router is not parsable: %s%s",
+               argv[1], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  LSDB_FOREACH_LSA_IR (vty, showfunc, o->lsdb, id, router);
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      LSDB_FOREACH_LSA_IR (vty, showfunc, oa->lsdb, id, router);
+    }
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      for (j = listhead (oa->if_list); j; nextnode (j))
+        {
+          struct ospf6_interface *oi = (struct ospf6_interface *) getdata (j);
+          LSDB_FOREACH_LSA_IR (vty, showfunc, oi->lsdb, id, router);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_database_id_router,
+       show_ipv6_ospf6_database_id_router_detail_cmd,
+       "show ipv6 ospf6 database * A.B.C.D A.B.C.D "
+       "(detail|dump|internal)",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Any Link state Type\n"
+       "Specify Link state ID as IPv4 address notation\n"
+       "Specify Advertising Router as IPv4 address notation\n"
+       "Display details of LSAs\n"
+       "Dump LSAs\n"
+       "Display LSA's internal information\n"
+      );
+
+DEFUN (show_ipv6_ospf6_database_type_id_router,
+       show_ipv6_ospf6_database_type_id_router_cmd,
+       "show ipv6 ospf6 database "
+       "(router|network|inter-prefix|inter-router|as-external|"
+       "group-membership|type-7|link|intra-prefix) A.B.C.D A.B.C.D",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Display Router LSAs\n"
+       "Display Network LSAs\n"
+       "Display Inter-Area-Prefix LSAs\n"
+       "Display Inter-Area-Router LSAs\n"
+       "Display As-External LSAs\n"
+       "Display Group-Membership LSAs\n"
+       "Display Type-7 LSAs\n"
+       "Display Link LSAs\n"
+       "Display Intra-Area-Prefix LSAs\n"
+       "Specify Link state ID as IPv4 address notation\n"
+       "Specify Advertising Router as IPv4 address notation\n"
+      )
+{
+  listnode i, j;
+  struct ospf6 *o = ospf6;
+  void (*showfunc) (struct vty *, struct ospf6_lsa *) = NULL;
+  u_int16_t type = 0;
+  u_int32_t id = 0;
+  u_int32_t router = 0;
+
+  OSPF6_CMD_CHECK_RUNNING ();
+
+  if (argc > 3)
+    {
+      if (! strncmp (argv[3], "du", 2))
+        showfunc = ospf6_lsa_show_dump;
+      else if (! strncmp (argv[3], "in", 2))
+        showfunc = ospf6_lsa_show_internal;
+    }
+  else
+    showfunc = ospf6_lsa_show;
+
+  if (showfunc == ospf6_lsa_show_summary)
+    ospf6_lsa_show_summary_header (vty);
+
+  if (! strcmp (argv[0], "router"))
+    type = htons (OSPF6_LSTYPE_ROUTER);
+  else if (! strcmp (argv[0], "network"))
+    type = htons (OSPF6_LSTYPE_NETWORK);
+  else if (! strcmp (argv[0], "as-external"))
+    type = htons (OSPF6_LSTYPE_AS_EXTERNAL);
+  else if (! strcmp (argv[0], "intra-prefix"))
+    type = htons (OSPF6_LSTYPE_INTRA_PREFIX);
+  else if (! strcmp (argv[0], "inter-router"))
+    type = htons (OSPF6_LSTYPE_INTER_ROUTER);
+  else if (! strcmp (argv[0], "inter-prefix"))
+    type = htons (OSPF6_LSTYPE_INTER_PREFIX);
+  else if (! strcmp (argv[0], "link"))
+    type = htons (OSPF6_LSTYPE_LINK);
+
+  if ((inet_pton (AF_INET, argv[1], &id)) != 1)
+    {
+      vty_out (vty, "Link state ID is not parsable: %s%s",
+               argv[1], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  if ((inet_pton (AF_INET, argv[2], &router)) != 1)
+    {
+      vty_out (vty, "Advertising Router is not parsable: %s%s",
+               argv[2], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  LSDB_FOREACH_LSA_TIR (vty, showfunc, o->lsdb, type, id, router);
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      LSDB_FOREACH_LSA_TIR (vty, showfunc, oa->lsdb, type, id, router);
+    }
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      for (j = listhead (oa->if_list); j; nextnode (j))
+        {
+          struct ospf6_interface *oi = (struct ospf6_interface *) getdata (j);
+          LSDB_FOREACH_LSA_TIR (vty, showfunc, oi->lsdb, type, id, router);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_database_type_id_router,
+       show_ipv6_ospf6_database_type_id_router_detail_cmd,
+       "show ipv6 ospf6 database "
+       "(router|network|inter-prefix|inter-router|as-external|"
+       "group-membership|type-7|link|intra-prefix) A.B.C.D A.B.C.D "
+       "(dump|internal)",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Display Router LSAs\n"
+       "Display Network LSAs\n"
+       "Display Inter-Area-Prefix LSAs\n"
+       "Display Inter-Area-Router LSAs\n"
+       "Display As-External LSAs\n"
+       "Display Group-Membership LSAs\n"
+       "Display Type-7 LSAs\n"
+       "Display Link LSAs\n"
+       "Display Intra-Area-Prefix LSAs\n"
+       "Specify Link state ID as IPv4 address notation\n"
+       "Specify Advertising Router as IPv4 address notation\n"
+       "Display details of LSAs\n"
+       "Dump LSAs\n"
+       "Display LSA's internal information\n"
+      );
+
+DEFUN (show_ipv6_ospf6_database_self_originated,
+       show_ipv6_ospf6_database_self_originated_cmd,
+       "show ipv6 ospf6 database self-originated",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Display Self-originated LSAs\n"
+      )
+{
+  listnode i, j;
+  struct ospf6 *o = ospf6;
+  void (*showfunc) (struct vty *, struct ospf6_lsa *) = NULL;
+
+  OSPF6_CMD_CHECK_RUNNING ();
+
+  if (argc > 0)
+    {
+      if (! strncmp (argv[0], "de", 2))
+        showfunc = ospf6_lsa_show;
+      else if (! strncmp (argv[0], "du", 2))
+        showfunc = ospf6_lsa_show_dump;
+      else if (! strncmp (argv[0], "in", 2))
+        showfunc = ospf6_lsa_show_internal;
+    }
+  else
+    showfunc = ospf6_lsa_show_summary;
+
+  if (showfunc == ospf6_lsa_show_summary)
+    ospf6_lsa_show_summary_header (vty);
+
+  LSDB_FOREACH_LSA_R (vty, showfunc, o->lsdb, o->router_id);
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      LSDB_FOREACH_LSA_R (vty, showfunc, oa->lsdb, o->router_id);
+    }
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      for (j = listhead (oa->if_list); j; nextnode (j))
+        {
+          struct ospf6_interface *oi = (struct ospf6_interface *) getdata (j);
+          LSDB_FOREACH_LSA_R (vty, showfunc, oi->lsdb, o->router_id);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_database_self_originated,
+       show_ipv6_ospf6_database_self_originated_detail_cmd,
+       "show ipv6 ospf6 database self-originated "
+       "(detail|dump|internal)",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Display Self-originated LSAs\n"
+       "Display details of LSAs\n"
+       "Dump LSAs\n"
+       "Display LSA's internal information\n"
+      );
+
+DEFUN (show_ipv6_ospf6_database_type_self_originated,
+       show_ipv6_ospf6_database_type_self_originated_cmd,
+       "show ipv6 ospf6 database "
+       "(router|network|inter-prefix|inter-router|as-external|"
+       "group-membership|type-7|link|intra-prefix) self-originated",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Display Router LSAs\n"
+       "Display Network LSAs\n"
+       "Display Inter-Area-Prefix LSAs\n"
+       "Display Inter-Area-Router LSAs\n"
+       "Display As-External LSAs\n"
+       "Display Group-Membership LSAs\n"
+       "Display Type-7 LSAs\n"
+       "Display Link LSAs\n"
+       "Display Intra-Area-Prefix LSAs\n"
+       "Display Self-originated LSAs\n"
+      )
+{
+  listnode i, j;
+  struct ospf6 *o = ospf6;
+  void (*showfunc) (struct vty *, struct ospf6_lsa *) = NULL;
+  u_int16_t type = 0;
+
+  OSPF6_CMD_CHECK_RUNNING ();
+
+  if (argc > 1)
+    {
+      if (! strncmp (argv[1], "de", 2))
+        showfunc = ospf6_lsa_show;
+      else if (! strncmp (argv[1], "du", 2))
+        showfunc = ospf6_lsa_show_dump;
+      else if (! strncmp (argv[1], "in", 2))
+        showfunc = ospf6_lsa_show_internal;
+    }
+  else
+    showfunc = ospf6_lsa_show_summary;
+
+  if (showfunc == ospf6_lsa_show_summary)
+    ospf6_lsa_show_summary_header (vty);
+
+  if (! strcmp (argv[0], "router"))
+    type = htons (OSPF6_LSTYPE_ROUTER);
+  else if (! strcmp (argv[0], "network"))
+    type = htons (OSPF6_LSTYPE_NETWORK);
+  else if (! strcmp (argv[0], "as-external"))
+    type = htons (OSPF6_LSTYPE_AS_EXTERNAL);
+  else if (! strcmp (argv[0], "intra-prefix"))
+    type = htons (OSPF6_LSTYPE_INTRA_PREFIX);
+  else if (! strcmp (argv[0], "inter-router"))
+    type = htons (OSPF6_LSTYPE_INTER_ROUTER);
+  else if (! strcmp (argv[0], "inter-prefix"))
+    type = htons (OSPF6_LSTYPE_INTER_PREFIX);
+  else if (! strcmp (argv[0], "link"))
+    type = htons (OSPF6_LSTYPE_LINK);
+
+  LSDB_FOREACH_LSA_TR (vty, showfunc, o->lsdb, type, o->router_id);
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      LSDB_FOREACH_LSA_TR (vty, showfunc, oa->lsdb, type, o->router_id);
+    }
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      for (j = listhead (oa->if_list); j; nextnode (j))
+        {
+          struct ospf6_interface *oi = (struct ospf6_interface *) getdata (j);
+          LSDB_FOREACH_LSA_TR (vty, showfunc, oi->lsdb, type, o->router_id);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_database_type_self_originated,
+       show_ipv6_ospf6_database_type_self_originated_detail_cmd,
+       "show ipv6 ospf6 database "
+       "(router|network|inter-prefix|inter-router|as-external|"
+       "group-membership|type-7|link|intra-prefix) self-originated "
+       "(detail|dump|internal)",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Display Router LSAs\n"
+       "Display Network LSAs\n"
+       "Display Inter-Area-Prefix LSAs\n"
+       "Display Inter-Area-Router LSAs\n"
+       "Display As-External LSAs\n"
+       "Display Group-Membership LSAs\n"
+       "Display Type-7 LSAs\n"
+       "Display Link LSAs\n"
+       "Display Intra-Area-Prefix LSAs\n"
+       "Display Self-originated LSAs\n"
+       "Display details of LSAs\n"
+       "Dump LSAs\n"
+       "Display LSA's internal information\n"
+      );
+
+DEFUN (show_ipv6_ospf6_database_type_id_self_originated,
+       show_ipv6_ospf6_database_type_id_self_originated_cmd,
+       "show ipv6 ospf6 database "
+       "(router|network|inter-prefix|inter-router|as-external|"
+       "group-membership|type-7|link|intra-prefix) A.B.C.D self-originated",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Display Router LSAs\n"
+       "Display Network LSAs\n"
+       "Display Inter-Area-Prefix LSAs\n"
+       "Display Inter-Area-Router LSAs\n"
+       "Display As-External LSAs\n"
+       "Display Group-Membership LSAs\n"
+       "Display Type-7 LSAs\n"
+       "Display Link LSAs\n"
+       "Display Intra-Area-Prefix LSAs\n"
+       "Specify Link state ID as IPv4 address notation\n"
+       "Display Self-originated LSAs\n"
+      )
+{
+  listnode i, j;
+  struct ospf6 *o = ospf6;
+  void (*showfunc) (struct vty *, struct ospf6_lsa *) = NULL;
+  u_int16_t type = 0;
+  u_int32_t id = 0;
+
+  OSPF6_CMD_CHECK_RUNNING ();
+
+  if (argc > 2)
+    {
+      if (! strncmp (argv[2], "du", 2))
+        showfunc = ospf6_lsa_show_dump;
+      else if (! strncmp (argv[2], "in", 2))
+        showfunc = ospf6_lsa_show_internal;
+    }
+  else
+    showfunc = ospf6_lsa_show;
+
+  if (showfunc == ospf6_lsa_show_summary)
+    ospf6_lsa_show_summary_header (vty);
+
+  if (! strcmp (argv[0], "router"))
+    type = htons (OSPF6_LSTYPE_ROUTER);
+  else if (! strcmp (argv[0], "network"))
+    type = htons (OSPF6_LSTYPE_NETWORK);
+  else if (! strcmp (argv[0], "as-external"))
+    type = htons (OSPF6_LSTYPE_AS_EXTERNAL);
+  else if (! strcmp (argv[0], "intra-prefix"))
+    type = htons (OSPF6_LSTYPE_INTRA_PREFIX);
+  else if (! strcmp (argv[0], "inter-router"))
+    type = htons (OSPF6_LSTYPE_INTER_ROUTER);
+  else if (! strcmp (argv[0], "inter-prefix"))
+    type = htons (OSPF6_LSTYPE_INTER_PREFIX);
+  else if (! strcmp (argv[0], "link"))
+    type = htons (OSPF6_LSTYPE_LINK);
+
+  if ((inet_pton (AF_INET, argv[1], &id)) != 1)
+    {
+      vty_out (vty, "Link State ID is not parsable: %s%s",
+               argv[0], VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  LSDB_FOREACH_LSA_TIR (vty, showfunc, o->lsdb, type, id, o->router_id);
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      LSDB_FOREACH_LSA_TIR (vty, showfunc, oa->lsdb, type, id, o->router_id);
+    }
+  for (i = listhead (o->area_list); i; nextnode (i))
+    {
+      struct ospf6_area *oa = (struct ospf6_area *) getdata (i);
+      for (j = listhead (oa->if_list); j; nextnode (j))
+        {
+          struct ospf6_interface *oi = (struct ospf6_interface *) getdata (j);
+          LSDB_FOREACH_LSA_TIR (vty, showfunc, oi->lsdb, type, id, o->router_id);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_database_type_id_self_originated,
+       show_ipv6_ospf6_database_type_id_self_originated_detail_cmd,
+       "show ipv6 ospf6 database "
+       "(router|network|inter-prefix|inter-router|as-external|"
+       "group-membership|type-7|link|intra-prefix) A.B.C.D self-originated "
+       "(dump|internal)",
+       SHOW_STR
+       IPV6_STR
+       OSPF6_STR
+       "Display Link state database\n"
+       "Display Router LSAs\n"
+       "Display Network LSAs\n"
+       "Display Inter-Area-Prefix LSAs\n"
+       "Display Inter-Area-Router LSAs\n"
+       "Display As-External LSAs\n"
+       "Display Group-Membership LSAs\n"
+       "Display Type-7 LSAs\n"
+       "Display Link LSAs\n"
+       "Display Intra-Area-Prefix LSAs\n"
+       "Specify Link state ID as IPv4 address notation\n"
+       "Display Self-originated LSAs\n"
+       "Display details of LSAs\n"
+       "Dump LSAs\n"
+       "Display LSA's internal information\n"
+      );
+
+
 
 /* Install ospf related commands. */
 void
 ospf6_init ()
 {
-  /* Install ospf6 top node. */
-  install_node (&ospf6_node, ospf6_config_write);
+  install_node (&debug_node, config_write_ospf6_debug);
 
-  install_element (VIEW_NODE, &show_ipv6_ospf6_cmd);
+  install_element_ospf6_debug_message ();
+  install_element_ospf6_debug_lsa ();
+  install_element_ospf6_debug_interface ();
+  install_element_ospf6_debug_neighbor ();
+  install_element_ospf6_debug_zebra ();
+  install_element_ospf6_debug_spf ();
+  install_element_ospf6_debug_route ();
+  install_element_ospf6_debug_asbr ();
+
   install_element (VIEW_NODE, &show_version_ospf6_cmd);
-  install_element (ENABLE_NODE, &show_ipv6_ospf6_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_detail_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_detail_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_id_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_id_detail_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_router_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_router_detail_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_detail_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_router_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_router_detail_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_id_router_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_id_router_detail_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_router_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_router_detail_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_self_originated_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_self_originated_detail_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_self_originated_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_self_originated_detail_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_self_originated_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_self_originated_detail_cmd);
+
   install_element (ENABLE_NODE, &show_version_ospf6_cmd);
-  install_element (ENABLE_NODE, &reload_cmd);
-  install_element (CONFIG_NODE, &router_ospf6_cmd);
-  install_element (CONFIG_NODE, &interface_cmd);
-  install_element (CONFIG_NODE, &no_interface_cmd);
-#ifdef OSPF6_STATISTICS
-  install_element (VIEW_NODE, &show_ipv6_ospf6_statistics_cmd);
-  install_element (ENABLE_NODE, &show_ipv6_ospf6_statistics_cmd);
-#endif /* OSPF6_STATISTICS */
-#ifdef OSPF6_GARBAGE_COLLECT
-  install_element (ENABLE_NODE, &garbage_collection_cmd);
-#endif /* OSPF6_GARBAGE_COLLECT */
-#ifdef HAVE_SETPROCTITLE
-  install_element (CONFIG_NODE, &set_proctitle_cmd);
-#endif /* HAVE_SETPROCTITLE */
-
-  install_default (OSPF6_NODE);
-  install_element (OSPF6_NODE, &ospf6_router_id_cmd);
-  install_element (OSPF6_NODE, &ospf6_interface_area_cmd);
-  install_element (OSPF6_NODE, &ospf6_interface_area_passive_cmd);
-  install_element (OSPF6_NODE, &ospf6_interface_area_plist_cmd);
-  install_element (OSPF6_NODE, &ospf6_interface_area_plist_passive_cmd);
-  install_element (OSPF6_NODE, &no_ospf6_interface_area_cmd);
-  install_element (OSPF6_NODE, &ospf6_passive_interface_cmd);
-  install_element (OSPF6_NODE, &no_ospf6_passive_interface_cmd);
-  install_element (OSPF6_NODE, &ospf6_area_range_cmd);
-
-  /* Make empty list of top list. */
-  if_init ();
-
-  /* Install access list */
-  access_list_init ();
-
-  /* Install prefix list */
-  prefix_list_init ();
-
-  ospf6_dump_init ();
-
-#ifdef HAVE_OSPF6_DAMP
-  ospf6_damp_init ();
-#endif /*HAVE_OSPF6_DAMP*/
-
-  ospf6_hook_init ();
-  ospf6_lsa_init ();
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_detail_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_detail_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_id_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_id_detail_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_router_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_router_detail_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_detail_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_router_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_router_detail_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_id_router_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_id_router_detail_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_router_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_router_detail_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_self_originated_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_self_originated_detail_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_self_originated_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_self_originated_detail_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_self_originated_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_self_originated_detail_cmd);
 
   ospf6_top_init ();
   ospf6_area_init ();
@@ -776,53 +1256,14 @@
   ospf6_neighbor_init ();
   ospf6_zebra_init ();
 
-  ospf6_routemap_init ();
-  ospf6_lsdb_init ();
-
+  ospf6_lsa_init ();
   ospf6_spf_init ();
-
   ospf6_intra_init ();
-  ospf6_abr_init ();
   ospf6_asbr_init ();
+
+  /* Make ospf protocol socket. */
+  ospf6_serv_sock ();
+  thread_add_read (master, ospf6_receive, NULL, ospf6_sock);
 }
 
-void
-ospf6_terminate ()
-{
-  /* stop ospf6 */
-  ospf6_stop ();
-
-  /* log */
-  zlog (NULL, LOG_INFO, "OSPF6d terminated");
-}
-
-void
-ospf6_maxage_remover ()
-{
-#if 0
-  if (IS_OSPF6_DUMP_LSDB)
-    zlog_info ("MaxAge Remover");
-#endif
-
-  ospf6_top_schedule_maxage_remover (NULL, 0, ospf6);
-  (*ospf6->foreach_area) (ospf6, NULL, 0,
-                          ospf6_area_schedule_maxage_remover);
-  (*ospf6->foreach_if) (ospf6, NULL, 0,
-                        ospf6_interface_schedule_maxage_remover);
-}
-
-
-
-void *
-ospf6_lsa_get_scope (u_int16_t type, struct ospf6_interface *o6i)
-{
-  if (OSPF6_LSA_IS_SCOPE_LINKLOCAL (ntohs (type)))
-    return o6i;
-  else if (OSPF6_LSA_IS_SCOPE_AREA (ntohs (type)))
-    return o6i->area;
-  else if (OSPF6_LSA_IS_SCOPE_AS (ntohs (type)))
-    return o6i->area->ospf6;
-  else
-    return NULL;
-}
 
diff --git a/ospf6d/ospf6d.conf.sample b/ospf6d/ospf6d.conf.sample
index 71972f5..0a6ddb7 100644
--- a/ospf6d/ospf6d.conf.sample
+++ b/ospf6d/ospf6d.conf.sample
@@ -1,32 +1,20 @@
 !
 ! Zebra configuration saved from vty
-!   2000/05/11 02:09:37
+!   2003/11/28 00:49:49
 !
-hostname ospf6d@yasu3380
+hostname ospf6d@plant
 password zebra
-log file /var/log/zebra-ospf6d.log
 log stdout
+service advanced-vty
 !
-debug ospf6 message dbdesc
-debug ospf6 message lsreq
-debug ospf6 message lsupdate
-debug ospf6 message lsack
-debug ospf6 neighbor
-debug ospf6 spf
-debug ospf6 interface
-debug ospf6 area
-debug ospf6 lsa
-debug ospf6 zebra
-debug ospf6 config
-debug ospf6 dbex
-debug ospf6 route
+debug ospf6 neighbor state
 !
-interface ed0
+interface fxp0
  ipv6 ospf6 cost 1
  ipv6 ospf6 hello-interval 10
  ipv6 ospf6 dead-interval 40
  ipv6 ospf6 retransmit-interval 5
- ipv6 ospf6 priority 1
+ ipv6 ospf6 priority 0
  ipv6 ospf6 transmit-delay 1
  ipv6 ospf6 instance-id 0
 !
@@ -40,15 +28,25 @@
  ipv6 ospf6 instance-id 0
 !
 router ospf6
- router-id 0.0.0.1
+ router-id 255.1.1.1
  redistribute static route-map static-ospf6
- interface ed0 area 0.0.0.0
- interface lo0 area 0.0.0.0
+ interface fxp0 area 0.0.0.0
 !
-ipv6 prefix-list hostroute seq 10 permit 3ffe:501:100c:4380::/60 le 128 ge 128
+access-list access4 permit 127.0.0.1/32
 !
-route-map static-ospf6 permit 50
- match ipv6 address prefix-list hostroute
+ipv6 access-list access6 permit 3ffe:501::/32
+ipv6 access-list access6 permit 2001:200::/48
+ipv6 access-list access6 permit ::1/128
+!
+ipv6 prefix-list test-prefix seq 1000 deny any
+!
+route-map static-ospf6 permit 10
+ match ipv6 address prefix-list test-prefix
  set metric-type type-2
- set metric 30
+ set metric 2000
+!
+line vty
+ access-class access4
+ ipv6 access-class access6
+ exec-timeout 0 0
 !
diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h
index e867b1c..c08007f 100644
--- a/ospf6d/ospf6d.h
+++ b/ospf6d/ospf6d.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999 Yasuhiro Ohara
+ * Copyright (C) 2003 Yasuhiro Ohara
  *
  * This file is part of GNU Zebra.
  *
@@ -22,78 +22,11 @@
 #ifndef OSPF6D_H
 #define OSPF6D_H
 
-#include <zebra.h>
-#include "linklist.h"
-
-#ifndef HEADER_DEPENDENCY
-/* Include other stuffs */
-#include <lib/version.h>
-#include "log.h"
-#include "getopt.h"
-#include "thread.h"
-#include "command.h"
-#include "memory.h"
-#include "sockunion.h"
-#include "if.h"
-#include "prefix.h"
-#include "stream.h"
-#include "thread.h"
-#include "filter.h"
-#include "zclient.h"
-#include "table.h"
-#include "plist.h"
-
-/* OSPF stuffs */
-#include "ospf6_hook.h"
-#include "ospf6_types.h"
-#include "ospf6_prefix.h"
-#include "ospf6_lsa.h"
-#include "ospf6_lsdb.h"
-
-#include "ospf6_message.h"
-#include "ospf6_proto.h"
-#include "ospf6_spf.h"
-#include "ospf6_top.h"
-#include "ospf6_area.h"
-#include "ospf6_interface.h"
-#include "ospf6_neighbor.h"
-#include "ospf6_ism.h"
-#include "ospf6_nsm.h"
-#include "ospf6_route.h"
-#include "ospf6_dbex.h"
-#include "ospf6_network.h"
-#include "ospf6_zebra.h"
-#include "ospf6_dump.h"
-#include "ospf6_routemap.h"
-#include "ospf6_asbr.h"
-#include "ospf6_abr.h"
-#include "ospf6_intra.h"
-#endif /*HEADER_DEPENDENCY*/
-
-#define HASHVAL 64
-#define MAXIOVLIST 1024
-
-#define OSPF6_DAEMON_VERSION    "0.9.6p"
-
-#define AF_LINKSTATE  0xff
+#define OSPF6_DAEMON_VERSION    "0.9.7a"
 
 /* global variables */
-extern char *progname;
 extern int errno;
-extern int daemon_mode;
 extern struct thread_master *master;
-extern list iflist;
-extern list nexthoplist;
-extern struct sockaddr_in6 allspfrouters6;
-extern struct sockaddr_in6 alldrouters6;
-extern int ospf6_sock;
-extern char *recent_reason;
-
-/* Default configuration file name for ospfd. */
-#define OSPF6_DEFAULT_CONFIG       "ospf6d.conf"
-
-/* Default port values. */
-#define OSPF6_VTY_PORT             2606
 
 #ifdef INRIA_IPV6
 #ifndef IPV6_PKTINFO
@@ -101,7 +34,7 @@
 #endif /* IPV6_PKTINFO */
 #endif /* INRIA_IPV6 */
 
-/* Historycal for KAME.  */
+/* Historical for KAME.  */
 #ifndef IPV6_JOIN_GROUP
 #ifdef IPV6_ADD_MEMBERSHIP
 #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
@@ -117,6 +50,53 @@
 #endif /* IPV6_DROP_MEMBERSHIP */
 #endif /* ! IPV6_LEAVE_GROUP */
 
+/* operation on timeval structure */
+#ifndef timerclear
+#define timerclear(a) (a)->tv_sec = (tvp)->tv_usec = 0
+#endif /*timerclear*/
+#ifndef timersub
+#define timersub(a, b, res)                           \
+  do {                                                \
+    (res)->tv_sec = (a)->tv_sec - (b)->tv_sec;        \
+    (res)->tv_usec = (a)->tv_usec - (b)->tv_usec;     \
+    if ((res)->tv_usec < 0)                           \
+      {                                               \
+        (res)->tv_sec--;                              \
+        (res)->tv_usec += 1000000;                    \
+      }                                               \
+  } while (0)
+#endif /*timersub*/
+#define timerstring(tv, buf, size)                    \
+  do {                                                \
+    if ((tv)->tv_sec / 60 / 60 / 24)                  \
+      snprintf (buf, size, "%ldd%02ld:%02ld:%02ld",   \
+                (tv)->tv_sec / 60 / 60 / 24,          \
+                (tv)->tv_sec / 60 / 60 % 24,          \
+                (tv)->tv_sec / 60 % 60,               \
+                (tv)->tv_sec % 60);                   \
+    else                                              \
+      snprintf (buf, size, "%02ld:%02ld:%02ld",       \
+                (tv)->tv_sec / 60 / 60 % 24,          \
+                (tv)->tv_sec / 60 % 60,               \
+                (tv)->tv_sec % 60);                   \
+  } while (0)
+#define timerstring_local(tv, buf, size)                  \
+  do {                                                    \
+    int ret;                                              \
+    struct tm *tm;                                        \
+    tm = localtime (&(tv)->tv_sec);                       \
+    ret = strftime (buf, size, "%Y/%m/%d %H:%M:%S", tm);  \
+    if (ret == 0)                                         \
+      zlog_warn ("strftime error");                       \
+  } while (0)
+
+/* for commands */
+#define OSPF6_AREA_STR      "Area information\n"
+#define OSPF6_AREA_ID_STR   "Area ID (as an IPv4 notation)\n"
+#define OSPF6_SPF_STR       "Shortest Path First tree information\n"
+#define OSPF6_ROUTER_ID_STR "Specify Router-ID\n"
+#define OSPF6_LS_ID_STR     "Specify Link State ID\n"
+
 #define OSPF6_CMD_CHECK_RUNNING() \
   if (ospf6 == NULL) \
     { \
@@ -124,51 +104,13 @@
       return CMD_SUCCESS; \
     }
 
-#define OSPF6_LEVEL_NONE      0
-#define OSPF6_LEVEL_NEIGHBOR  1
-#define OSPF6_LEVEL_INTERFACE 2
-#define OSPF6_LEVEL_AREA      3
-#define OSPF6_LEVEL_TOP       4
-#define OSPF6_LEVEL_MAX       5
-
-#define OSPF6_PASSIVE_STR \
-  "Suppress routing updates on an interface\n"
-#define OSPF6_PREFIX_LIST_STR \
-  "Advertise I/F Address only match entries of prefix-list\n"
-
-#define OSPF6_AREA_STR      "Area information\n"
-#define OSPF6_AREA_ID_STR   "Area ID (as an IPv4 notation)\n"
-#define OSPF6_SPF_STR       "Shortest Path First tree information\n"
-#define OSPF6_ROUTER_ID_STR "Specify Router-ID\n"
-#define OSPF6_LS_ID_STR     "Specify Link State ID\n"
-
 
 /* Function Prototypes */
-void
-ospf6_timeval_sub (const struct timeval *t1, const struct timeval *t2,
-                   struct timeval *result);
-void
-ospf6_timeval_div (const struct timeval *t1, u_int by,
-                   struct timeval *result);
-void
-ospf6_timeval_sub_equal (const struct timeval *t, struct timeval *result);
-void
-ospf6_timeval_decode (const struct timeval *t, long *dayp, long *hourp,
-                      long *minp, long *secp, long *msecp, long *usecp);
-void
-ospf6_timeval_string (struct timeval *tv, char *buf, int size);
-void
-ospf6_timeval_string_summary (struct timeval *tv, char *buf, int size);
+struct route_node *route_prev (struct route_node *node);
 
-void
-ospf6_count_state (void *arg, int val, void *obj);
-
+void ospf6_debug ();
 void ospf6_init ();
-void ospf6_terminate ();
-
-void ospf6_maxage_remover ();
-
-void *ospf6_lsa_get_scope (u_int16_t type, struct ospf6_interface *o6i);
 
 #endif /* OSPF6D_H */
 
+