Initial revision
diff --git a/ospf6d/.cvsignore b/ospf6d/.cvsignore
new file mode 100644
index 0000000..cec4061
--- /dev/null
+++ b/ospf6d/.cvsignore
@@ -0,0 +1,8 @@
+Makefile
+*.o
+*.patch
+ospf6d
+ospf6d.conf
+tags
+TAGS
+.deps
diff --git a/ospf6d/ChangeLog b/ospf6d/ChangeLog
new file mode 100644
index 0000000..b7871c1
--- /dev/null
+++ b/ospf6d/ChangeLog
@@ -0,0 +1,809 @@
+2002-11-09  Vincent Jardin  <jardin@6wind.com>
+
+	* ospf6_interface.c: update link-local address on interface creation.
+
+2002-11-09  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_asbr.c: apply MinLSInterval to AS-External-LSA origination.
+	* ospf6_lsa.c: change not to issue flooding caused by expire event
+	when the received LSA is (already) MaxAge.
+	* ospf6_spf.c: fix a bug which is that ospf6d calculates
+	wrong nexthop when failed to find Link-LSA for the neighbor.
+	* ospf6_damp.c ospf6_dbex.c ospf6_neighbor.c ospf6_spf.c:
+	some clean up
+	* version: 0.9.6o
+
+2002-10-04  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_asbr.c: bug of failing ASE lsa refresh fixed.
+	* version: 0.9.6n
+
+2002-10-01  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_asbr.c: AS-External-LSA origination function
+	is re-written.
+	* ospf6_damp.[ch]: New feature that damps flaps is added.
+	* version: 0.9.6m
+
+2002-07-14  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_spf.c: unwanted assert() in ospf6_spf_nexthop_calculation()
+	is deleted.
+	* version: 0.9.6l
+
+2002-07-14  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_dbex.c: bug that ospf6d fails to refresh self-originated
+	LSA if he have not the LSA before has been fixed.
+	* ospf6_asbr.c: bug of failing removing ASE LSA when remove
+	message arrived from zebra has been fixed.
+	* version: 0.9.6k
+
+2002-07-13  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_zebra.c: bug reported [zebra 14642] fixed.
+	The bug was related to the synchronization between zebra
+	and ospf6d. Now synchronization will be correctly done.
+	* version: 0.9.6j
+
+2002-07-07  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_lsdb.c: bug fixed in ospf6_lsdb_type_router ().
+	* ospf6_dbex.c: because of retrans list structure changed
+	due to LSDB change, removal of old instance from retrans-list
+	is not necessary anymore. this caused crash but now fixed.
+	* version: 0.9.6i
+
+2002-07-07  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+	* zebra-0.93 released.
+
+2002-07-07  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_lsdb.c: entirely rewritten. now ospf6d uses
+	radix tree by using lib/table.[ch] for LSDB lookup.
+	* ospf6_abr.c, ospf6_asbr.c, ospf6_intra.c: hook changed
+	due to rewriting of lsdb module.
+	* ospf6_neighbor.c: lack of check existence and find correct
+	instance of the LSA which is going to be removed from neighbor's
+	retransmission was filled.
+	* version: 0.9.6h
+
+2002-07-07  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_intra.c: bug fix for Intra-route deletion.
+	* ospf6_route.c: bug fix for path comparison.
+	* version: 0.9.6g
+
+2002-06-28  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_route.c: some logs trying to find the situation
+	when assert occur are added. route duration statistics
+	added.
+	* ospf6_zebra.c: trying to fix the problem reported by
+	[zebra 14318] but not yet sure.
+	* version: 0.9.6f
+
+2002-06-25  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_intra.c: new file for management of intra-prefix LSA.
+	* ospf6_abr.c: inter area route calculation code added.
+	* version: 0.9.6e
+
+2002-06-22  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_asbr.c: All AS-External route was removed when
+	one of the ASBR path was gone, but the route from other ASBR
+	path should stay remained. this bug is fixed.
+	* version: 0.9.6d
+
+2002-06-22  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_route.c: route table calculation bug fixed. [zebra 14105]
+	* ospf6_spf.c, ospf6_route.c, etc.: log message cleaned up.
+	* version: 0.9.6c
+
+2002-04-27  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_route.c: [zebra 13514] bug fix.
+	thanks to Harald Koch.
+	* version: 0.9.6b
+
+2002-04-22  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_dump.c: fix bug of log function
+	* ospf6_area.c: fix bug of intra route deletion
+	* version: 0.9.6a
+
+2002-04-20  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* merged with "current" version.
+	* version: 0.9.6
+
+2001-03-11  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_lsdb.c ospf6_spf.c: log message changed for debug.
+
+2001-02-20  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* version: 0.9.5i
+
+	* ospf6_asbr.c: Added code that finds alternative
+	AS-External route when remove AS-External route.
+	This is temporary fix ...
+
+	* ospf6_redistribute.c: remove redistributed routes
+	immediately when 'no redistribute ...'
+
+2001-02-20  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* version: 0.9.5h
+
+	* ospf6_spf.c, ospf6_lsa.c: Change to originate Link-LSA on
+	point-to-point links.
+
+	* ospf6_message.c: Bug of log messages of self-originated
+	Hello packet fixed.
+
+2001-02-09  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* version: 0.9.5g
+	* ospf6_asbr.c: fix for the bug that AS-External route
+	is not get removed.
+
+2001-02-09  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_lsdb.c: crash bug while receiving wrong LSA scope bit
+	has been temporarily fixed
+
+2001-12-20  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_asbr.[ch]: The byte order bug in encoding/decoding
+	the bits/metric field in AS-External-LSA fixed.
+	Fixed to update E-bit in Router-LSA of itself.
+	Reported by Taisuke Sasaki ([zebra 11548]).
+
+	* README: updated.
+
+	* version: 0.9.5f
+
+2001-11-21  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_prefix.c: Intra-prefix-LSA bug fixed.
+	* ospf6_abr.[ch]: added (only just placeholder yet)
+
+2001-11-20  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_route.c: fix to overwrite a prefix when another
+	addition to the prefix is given. freeze function changed
+	not to remove routes by default.
+
+	* version: 0.9.5e
+
+2001-11-19  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* version: 0.9.5d
+
+	* ospf6_lsa.c ospf6_spf.c: SPF Calculations are now
+	scheduled by hook.
+
+	* ospf6_route.c: ospf6_route_add bug fix,
+	ospf6_route_remove_all corrected.
+
+2001-11-15  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_hook.[ch]: added.
+	* Almost half of the code has been rewritten.
+	especially, ospf6_route.[ch]. Hook call has been injected
+	much.
+	* ospf6_asbr.[ch]: added.
+
+2001-10-17  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_dbex.c: ospf6d was wrong to omit reoriginating
+	of LSA when the self-originated LSA was received from others.
+	fixed.
+	* ospf6d.h: version: 0.9.5c
+
+2001-10-16  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_lsa.c: 'force-prefix' was not executed. fixed.
+	* ospf6d.h: version: 0.9.5b
+
+2001-10-13  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_interface.c: 'passive-interface' is now moved to
+	'ipv6 ospf6 passive' in INTERFACE NODE. 'prefix-list' which
+	specifies the filter prefix for connected address prefix also
+	moved to INTERFACE NODE as 'ipv6 ospf6 advertise prefix-list WORD'.
+	The old obsoleted commands are still acceptable though. New command
+	'ipv6 ospf6 advertise force-prefix' added, which which tells ospf6d
+	to advertise rather prefix than stub local-address even on loopback
+	or pointopoint interfaces.
+
+	* ospf6_dump.c: 'ospf6 debug hello' -> 'ospf6 debug message hello'.
+	same for other message type. The older is still acceptable.
+
+	* ospf6_lsa.c: Changed AS-External generation to new one which uses
+	LSA hooks. Delete old garbage.
+
+2001-10-02  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6d.c: turn off and turn on sequence with
+	'no interface' 'interface' cmds was not work. fixed.
+
+	* ospf6_lsa.c: generating Intra-Area-Prefix-LSA for stub
+	did not care duplicate prefixes. fixed.
+
+2001-09-07  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_message.c: There was a bug that prevent LSDB
+	to syncronize. It was a DbDesc packet bug that Slave
+	sends two different DbDesc packet on the same sequence
+	number. This cause many LSAs are dropped when Exchanging
+	LSDB, because the latter DbDesc packet that have the same
+	sequence number will be ignored as duplicate packet.
+	This seems to be exist at least before 0.9.4 version.
+	Now this is the most stable candidate.
+
+	* ospf6d.h: version 0.9.5a
+
+2001-09-06  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_zebra.c ospf6_spf.c ospf6_lsa.c :
+	delete nexthop check to certify the nexthop is Link-local address.
+	Suppress Link-LSA origination on links other than Broadcast.
+	SPF's nexthop calculation first checks linklocal address
+	in Link-LSA, then checks source address of neighbor's packets.
+
+	* ospf6_interface.c ospf6_ism.c ospf6_lsa.c ospf6_nsm.c:
+	intra-area-prefix-lsa origination func moved to new one.
+
+	* ospf6_interface.h ospf6d.[ch] ospf6_lsa.c: 
+	interface_area_cmd now changed to have 'passive'
+	and 'prefix-list' option.
+
+	* ospf6_prefix.c:
+	clean up.
+
+2001-09-04  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_dbex.c ospf6_interface.c ospf6_ism.c ospf6_lsa.[ch]:
+	clean up and new LSA origination functions added.
+
+	* ospf6_route.c ospf6_lsdb.c: make vty function more
+	clean/understandable.
+
+	* ospf6d.h: version 0.9.5
+
+2001-08-24  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+	* ospf6_lsdb.c: Use IS_LSA_MAXAGE macro instead of
+	ospf6_lsa_is_maxage.
+
+	* ospf6_lsa.h (IS_LSA_MAXAGE): Add new macro to check MaxAge.
+
+2001-08-21  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_lsdb.c: if There's no previous prefix
+	ospf6d was wrongly not calculate the prefix.
+	this reported by (v6 16029) is fixed.
+
+	* ospf6_neighbor.c: Instance of LSA Summary included
+	in DbDesc packet was wrongly freed. The bug cause
+	malformed DbDesc, ExChange <-> ExStart flapping,
+	and then crash.
+
+	* ospf6d.h: version 0.9.4
+
+2001-08-21  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_route.[ch]: Showing format is changed.
+	'show ipv6 route ospf6' -> 'show ipv6 ospf6 route'
+	'show ipv6 route ospf6 external' ->
+	'show ipv6 ospf6 route redistribute'
+
+	* ospf6_lsdb.c ospf6_lsa.c ospf6_neighbor.c ospf6_interface.c:
+	memory leak in LS list fixed.
+
+	* all: clean up
+
+	* ospf6d.h: version 0.9.3
+
+2001-08-20  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+	* ospf6d.c (ospf6_timeval_sub_equal): Remove function.
+
+	* ospf6_spf.c (ospf6_timeval_cmp): Rewrite ospf6_timeval_cmp().
+	(ospf6_timeval_add_equal): Function moved from ospf6d.c
+	
+2001-08-19  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+	* zebra-0.92a released.
+
+2001-08-15  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+	* zebra-0.92 released.
+
+2001-08-09  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_lsdb.c ospf6_neighbor.c:
+	LSDB function/structure and LS list function has been rewritten.
+	memory leak has been decreased.
+
+	* ospf6_lsa.[ch] ospf6_dbex.c: garbage code has been deleted.
+
+	* ospf6d.h: version 0.9.2
+
+2001-08-07  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_dbex.c ospf6_lsdb.c:
+	Retransmition list had a critical bug that breaks LSDB
+	synchronization. When new LSA be added to retrans-list,
+	old must be removed, but it was not. So new LSA dropped,
+	and LSA Acknowledgement did not work. The bug was fixed.
+
+	* ospf6d.h: version 0.9.1
+
+2001-06-20  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_spf.c: crash bug fix in temporary treat code for
+	Router-LSA whose LS-ID != 0
+
+	* ospf6_dbex.c: RFC2328 13.(4) was wrongly coded.
+	    (4) Else if the LSA's LS age is equal to MaxAge, and there is
+            currently *NO* instance of the LSA in the router's link state
+	    ...
+
+	* ospf6_lsa.c: RFC2328 13.1 checksum tie breaker
+	had been neglected, and has just added now.
+
+	* ospf6d.h: version 0.9.0
+	ospf6d expected to work with hitachi gr2000 from these fixes.
+
+2001-06-12  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_lsa.c: Fix bug in creating Intra-Area-Prefix-LSA.
+	DR was mis-include others prefixes advertised by their Link-LSA.
+
+	* ospf6_route.c: Fix bug in calculating intra area routes.
+	Not all prefixes in Intra-Area-Prefix-LSA was calculated.
+
+	* ospf6_spf.c:
+	Changed to quit when a error occured in calculating SPF tree.
+	Very messy hack for the bug reported by [zebra 8807]. This
+	is not tested yet.
+	Changed to quit SPF calculation when a nexthop calculation
+	errors.
+
+	* ospf6_zebra.c:
+	Support for interface address deletion.
+
+	* ospf6d.h:
+	version: 0.8.y
+
+2001-04-18  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6d.h
+	Due to previous change (DR Election algorithm changed),
+	backward compatibility will be lost from this version.
+	version: 0.8.x
+
+2001-04-18  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_message.c ospf6_ism.c:
+	Bug of router_id comparison
+
+2001-04-17  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_dbex.c: ospf6_dbex_is_maxage_to_be_dropped() had
+	some bug causing Loading state lasts long.
+	version: 0.8.v
+
+2001-04-08  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_route.c: BUG in AS-External route calculation fixed.
+	It was using OLD LSDB...
+	Version: 0.8.u-
+
+2001-04-08  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_area.c, ospf6_dbex.c, ospf6_interface.c,
+	ospf6_lsa.c, ospf6_lsdb.c, ospf6_lsdb.h, ospf6_message.c,
+	ospf6_neighbor.c, ospf6_neighbor.h, ospf6_nsm.c,
+	ospf6_redistribute.c, ospf6_route.c, ospf6_spf.c:
+	Delete old LSDB function.
+
+	* ospf6d.h:
+	Version: 0.8.u
+
+2001-04-05  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_area.c, ospf6_area.h, ospf6_dbex.c, ospf6_interface.c,
+	ospf6_interface.h, ospf6_lsa.c, ospf6_lsdb.c, ospf6_lsdb.h,
+	ospf6_message.c, ospf6_nsm.c, ospf6_redistribute.c, ospf6_route.c,
+	ospf6_spf.c, ospf6_top.c, ospf6_top.h, ospf6d.h:
+	Changed to use New LSDB.
+	Version: 0.8.t
+
+2001-04-02  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_lsa.c:
+	Interface stub check in Intra-Area-Prefix-LSA origination 
+	was wrong. - fixed.
+
+	* ospf6_area.h, ospf6_dbex.c, ospf6_interface.c,
+	ospf6_interface.h, ospf6_lsa.c, ospf6_lsa.h, ospf6_lsdb.c,
+	ospf6_message.c, ospf6_neighbor.c, ospf6_nsm.c,
+	ospf6_redistribute.c, ospf6_top.c, ospf6_top.h, ospf6d.c:
+	New LSDB functions, but not changed to be used.
+
+	* ospf6d.h:
+	Version: 0.8.s
+
+2001-03-28  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_area.c ospf6_area.h ospf6_dbex.c ospf6_dump.c
+	ospf6_interface.c ospf6_interface.h ospf6_lsa.c
+	ospf6_message.c ospf6_redistribute.c ospf6_spf.c ospf6_top.c
+	ospf6_top.h ospf6_zebra.c ospf6d.c ospf6d.h: cleaning.
+
+2001-03-24  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6d.h:
+	version: 0.8.r
+
+	* ospf6_neighbor.[ch], ospf6_lsa.[ch]:
+	just clean up and log clearify.
+
+	* ospf6_message.[ch]:
+	Packet receiving function and dumping OSPFv3 packet has been
+	changed simple and clean.
+
+	* ospf6_dbex.[ch], ospf6_interface.[ch], ospf6_lsdb.[ch],
+	  ospf6_neighbor.[ch], ospf6_nsm.[ch]:
+	LSList(i.e. summary list, request list, retrans list, etc) have
+	been rewritten based on new LSDB module. The main LSDB have not
+	yet shifted to this new module, but will shift eventually.
+	This change expected to resolve the problem that the ospf6d keeps
+	on sending redundant LSUpdate/LSAck.
+
+	* ospf6_interface.c: changed default MTU from 1500 to 1280.
+	It was possible that the ospf6d could not send packet (e.g.
+	LSUpdate in response to LSReq in my case) when the packet
+	size accidentally reached near 1500 (I was forget about IP
+	header :p). It is a bit illegal to set MTU 1280 constantly,
+	but I failed once with I/F MTU from kernel (through zebra),
+	and thinks that 1280 is more stable than kernel variable.
+	Comments will be appriciated.
+
+2001-03-15  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_dbex.c, ospf6_interface.c, ospf6_ism.c, ospf6_lsdb.[ch],
+	  ospf6_neighbor.c, ospf6_spf.c, ospf6d.c:
+	Fix for crash. ospf6d has ever been crashing when
+	'no interface' command executed, and when starting up with
+	the configuration which does not include 'router ospf6'.
+	these has been fixed.
+
+2001-02-24  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_lsa.c, ospf6_message.c:
+	LSA summary (exchanged while Adjacency bring up) may expire
+	(may reach MaxAge). Handling this has been added but
+	it's a little bit quick hack.
+
+	* ospf6_message.c:
+	Thread chain bug fixed. Read network thread chain has been cut
+	when receive packets on not-enabled interface. this was wrong
+	and fixed.
+
+2001-02-24  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_message.c:
+	I/F MTU check part on sending packet had some bug, and it's fixed.
+	Ospf6d has believed a value from zebra as I/F MTU, but from now
+	I/F MTU is set to constant 1500. This is workaround for ATM.
+
+2001-02-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra-0.91 is released.
+
+2001-01-04  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* just code clean up of almost all module.
+	* ospf6_dump.c, ospf6_lsa.c: file dependency.
+	* ospf6_mesg.[ch]: changed filename to ospf6_message.[ch]
+
+2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra-0.90 is released.
+
+2001-01-04  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_mesg.c,ospf6_lsa.c: doubly cancel thread bug fixed.
+	version 0.8.k CRASHed for this.
+	* ospf6_lsa.c: bug of logging fixed.
+	version: 0.8.l
+
+2001-01-04  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_neighbor.c: fix typo when trying to delete
+	MaxAge AS-External LSA. MaxAge LSA remaining bug is expected
+	to be fixed.
+	version: 0.8.k
+
+2001-01-04  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_mesg.c: add I/F Mtu check for sending LS Update.
+
+	* ospf6_dbex.c, ospf6_mesg.c, ospf6_neighbor.c, ospf6_neighbor.h,
+	ospf6_spf.c: Changed type of hisaddr field in ospf6_neighbor
+	structure, from sockaddr_in6 to in6_addr. No protocol/processing
+	changed.
+
+2001-01-04  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_mesg.c, ospf6_neighbor.[ch]: Speed up of
+	Database Exchange.
+	version: 0.8.j
+
+	Because the LS Request list was checked only when attempt
+	to send (retransmit) LS Request packet, Loading state lasted
+	long (for RxmtInterval) unexpectedly. This was fixed; LS Request
+	packet will be send as soon as one received a LS Update packet.
+
+2001-01-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ospf6d.h (OSPF6_VTYSH_PATH): Change "/tmp/ospf6d" to
+	/tmp/.ospf6d".
+
+2000-12-29  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_dump.[ch]: simplified.
+
+2000-12-19  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_route.c: Fix bug of using unavailable route.
+	version: 0.8.d
+
+2000-11-30  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_spf.c: calculate statistics. version: 0.8.d
+
+2000-11-26  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_mesg.c, ospf6_nsm.c: LSDB sync bug fixed.
+	version: 0.8.c
+
+2000-11-26  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_dbex.c: Start debugging and cleaning.
+
+	* ospf6_area.c, ospf6_dbex.c, ospf6_interface.c, ospf6_lsa.c,
+	ospf6_proto.c, ospf6_top.c: add some function to clarify codes.
+
+2000-11-26  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_spf.c: Delete old garbage (which was enclosed by #if 0)
+
+	* ospf6_redistribute.c: "redistribute ospf6" was generated in
+	"router ospf6" in config file. It is a bug, and fixed.
+	wrong warning message was deleted.
+
+	* ospf6_main.c: If daemon mode, ospf6d was silent even if
+	the config file was wrong. It is a bug, and fixed.
+
+	* ospf6_route.c, ospf6_zebra.c: Zebra syncronization method
+	has been changed. delete garbages. allow nexthop of :: in case
+	of connected route.
+
+	* ospf6_dbex.c: Delete annoying log messages.
+
+	* ospf6_lsa.c: Changed string for LSA log.
+
+2000-11-21  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_spf.c: some careless bug fixed.
+
+	* ospf6_route.c: changed not to send garbage route
+          whose nexthop is not linklocal address.
+
+2000-11-09  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+        * ospf6_rtable.c: renamed to ospf6_route.c
+        whole functionality has been rewritten as new code.
+        new functions not yet installs routes; the old
+        functions still remains. cleaning log messages.
+
+	* ospf6_spf.c: whole functionality has been rewritten
+	as new code. new command "show ipv6 ospf6 spf node",
+	"show ipv6 ospf6 spf tree", "show ipv6 ospf6 spf table"
+	has been added. Memory leak was fixed. cleaning log messages.
+
+	* ospf6d version: 0.7.c
+
+2000-10-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra-0.89 is released.
+
+2000-09-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ospf6_lsdb.c (ospf6_lsdb_remove_maxage_lsa): Fix compile
+	warnings.
+
+2000-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra-0.88 is released.
+
+2000-08-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ospf6_rtable.h (struct ospf6_nexthop): Change ifindex type from
+	unsigned long to unsigned int.
+
+2000-04-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ospf6d.h: Include some headers for avoid warning.
+
+	* ospf6_routemap.h: Add newfile.
+
+1999-11-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ospf6_network.c: Respect IPV6_JOIN_GROUP and IPV6_LEAVE_GROUP
+	rather than RFC2133.
+
+1999-10-21  Jun-ichiro itojun Hagino <itojun@itojun.org>
+
+	* ospf6_network.c (ospf6_ipv6_decode_ipv4): Fix bug of conversion
+	from IPv4 Mapped Address to IPv4 address.
+
+1999-08-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ospf6_lsa.c (construct_link_lsa): Enclose KAME specific part by
+	#ifdef/#endif.
+
+1999-07-29  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* ospf6_mesg.c: add new message process function.
+
+1999-07-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ospf6_main.c (sighup): Call of log_rotate() removed.
+
+1999-07-24  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	ospf6_dbex.{c,h}: variable "acknowledge" has been deleted.
+
+1999-07-22  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* *.{c,h}: lsa data structure has been drastically
+	changed.
+
+1999-07-16  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* *.{c,h}: bug of updating LSA's which is self
+	originated has been fixed.
+
+1999-07-14  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* *.{c,h} : log clean up.
+
+1999-07-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ospf6d.c (ospf6_init): Change to use install_default.
+
+1999-07-03  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+	* ospf6_rtable.c (nexthop_*): added some function that handles
+	new nexthop structure.
+
+1999-07-01  Rick Payne <rickp@rossfell.co.uk>
+
+	* ospf6_zebra.c (ospf6_zebra_init): Install standard commands to
+	ZEBRA_NODE.
+
+1999-06-09  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+	* ospf6_rtable.h: added for new routing table of ospf6d
+
+1999-05-14  Stephen R. van den Berg <srb@cuci.nl>
+
+	* ospf6_main.c (signal_init): SIGTERM call sigint.
+	(sigint): Loggging more better message.
+
+1999-05-13  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+	*ospf6_spf.c (get_prefix_lsa_of_vertex): bug fix about network vertex.
+
+1999-05-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ospf6_network.c (send_linkstate_ack): Check HAVE_SIN6_SCOPE_ID
+	is defined.
+	* ospf6_mesg.c (make_hello): Likewise.
+	* ospf6_lsa.c (lsa_flood): Likewise.
+
+1999-05-07  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+	* ospf6_spf.c, etc: Many bug fix.
+        intra-area-prefix-LSA treatment changed.
+        network byte order of neighbor ifid changed.
+
+1999-05-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ospf6_zebra.h (struct zebra): Add hitory entry to structure.
+
+1999-05-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ospf6_main.c (main): Add KAME check for binding vty socket.
+	(main): Delete old interface get routine garbage.
+
+	* ospf6d.c: Change all `show ip6' statement to `show ipv6'.
+	(show_ipv6_ospf6_requestlist): Add description.
+
+1999-05-04  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+	* ospf6_lsa.c, etc: Many bug fix, now two routers
+	on the same segment can become FULL neighbor state
+	each other.
+
+1999-05-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* Makefile.am: Add file dependency.
+	(depend): Add target.
+
+1999-05-02  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+	* Clean up and fix have been almost done. This code
+	now testing stage of Intra area routing.
+
+	* Configuration Vty become more similar to Cisco.
+
+1999-04-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* Trim training newline from zlog format arguemnt.
+	
+	* ospf6_dump.c (ospf6_err): Commented out ospf6_err and
+	ospf6_warn.  Same kind of function should be implemented as
+	zlog_err or zlog_warn or someting.
+
+	* ospf6d.c: Change OSPF_NODE to OSPF6_NODE.
+	Change OSPF_DEFAULT_CONFIG to OSPF6_DEFAULT_CONFIG.
+	
+
+1999-04-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ospf6_mesg.c (make_hello): Add check of SIN6_LEN
+
+1999-04-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ospf6_neighbor.c: Change list_clear_all to list_delete_all_node.
+	Remove list_delete_all fuction and use lib/linklist.c's one.
+	
+1999-04-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* mcast_join(),mcast_leave()'s argument socket length is removed.
+
+1999-04-08    <kunihiro@zebra.org>
+
+	* ospf6_zebra.h (ospf_zebra_read): Fix typo.
+
+	* ospf6_interface.h: Tempolary add struct rt_addrinfo.
+
+1999-03-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* Merge from ospfd-zebra-990303 codes.
+
+1999-02-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* Makefile.in: add new file.
+
+	* Makefile.am: @INCLUDES@ is added for OS/library specific IPv6
+	directory search.
+
+	* Import files from Yasuhiro Ohara <yasu@sfc.wide.ad.jp>'s ospfd.
+	Impterted files are:
+	Makefile.am, ospf_area.h, ospf_dump.c, ospf_interface.c,
+	ospf_interface.h, ospf_lsa.c, ospf_lsa.h, ospf_main.c,
+	ospf_mesg.c, ospf_mesg.h, ospf_neighbor.c,
+	ospf_neighbor.h,ospf_network.c, ospf_network.h, ospf_proto.h,
+	ospf_spf.c, ospf_spf.h, ospf_types.h, ospfd.c, ospfd.h
diff --git a/ospf6d/Makefile.am b/ospf6d/Makefile.am
new file mode 100644
index 0000000..e1b78cb
--- /dev/null
+++ b/ospf6d/Makefile.am
@@ -0,0 +1,48 @@
+## Process this file with automake to produce Makefile.in.
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+INSTALL_SDATA=@INSTALL@ -m 600
+
+noinst_LIBRARIES = libospf6.a
+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
+
+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
+
+ospf6d_SOURCES = \
+	ospf6_main.c $(libospf6_a_SOURCES)
+
+ospf6d_LDADD = ../lib/libzebra.a
+
+sysconf_DATA = ospf6d.conf.sample
+
+EXTRA_DIST = $(sysconf_DATA)
+
+install-sysconfDATA: $(sysconf_DATA)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+	@list='$(sysconf_DATA)'; for p in $$list; do \
+	  if test -f $(srcdir)/$$p; then \
+	    echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+	    $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+	  else if test -f $$p; then \
+	    echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+	    $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+	  fi; fi; \
+	done
diff --git a/ospf6d/Makefile.in b/ospf6d/Makefile.in
new file mode 100644
index 0000000..fed57d9
--- /dev/null
+++ b/ospf6d/Makefile.in
@@ -0,0 +1,549 @@
+# Makefile.in generated by automake 1.7 from Makefile.am.
+# @configure_input@
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_triplet = @host@
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BGPD = @BGPD@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURSES = @CURSES@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+IF_METHOD = @IF_METHOD@
+IF_PROC = @IF_PROC@
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPFORWARD = @IPFORWARD@
+KERNEL_METHOD = @KERNEL_METHOD@
+LDFLAGS = @LDFLAGS@
+LIBPAM = @LIBPAM@
+LIBS = @LIBS@
+LIB_IPV6 = @LIB_IPV6@
+LIB_REGEX = @LIB_REGEX@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MULTIPATH_NUM = @MULTIPATH_NUM@
+OBJEXT = @OBJEXT@
+OSPF6D = @OSPF6D@
+OSPFD = @OSPFD@
+OTHER_METHOD = @OTHER_METHOD@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RIPD = @RIPD@
+RIPNGD = @RIPNGD@
+RTREAD_METHOD = @RTREAD_METHOD@
+RT_METHOD = @RT_METHOD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VTYSH = @VTYSH@
+ZEBRA = @ZEBRA@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__quote = @am__quote@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+INSTALL_SDATA = @INSTALL@ -m 600
+
+noinst_LIBRARIES = libospf6.a
+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
+
+
+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
+
+
+ospf6d_SOURCES = \
+	ospf6_main.c $(libospf6_a_SOURCES)
+
+
+ospf6d_LDADD = ../lib/libzebra.a
+
+sysconf_DATA = ospf6d.conf.sample
+
+EXTRA_DIST = $(sysconf_DATA)
+subdir = ospf6d
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+
+libospf6_a_AR = $(AR) cru
+libospf6_a_LIBADD =
+am_libospf6_a_OBJECTS = ospf6_dump.$(OBJEXT) ospf6d.$(OBJEXT) \
+	ospf6_interface.$(OBJEXT) ospf6_network.$(OBJEXT) \
+	ospf6_neighbor.$(OBJEXT) ospf6_message.$(OBJEXT) \
+	ospf6_lsa.$(OBJEXT) ospf6_spf.$(OBJEXT) ospf6_route.$(OBJEXT) \
+	ospf6_zebra.$(OBJEXT) ospf6_ism.$(OBJEXT) ospf6_dbex.$(OBJEXT) \
+	ospf6_lsdb.$(OBJEXT) ospf6_prefix.$(OBJEXT) ospf6_top.$(OBJEXT) \
+	ospf6_area.$(OBJEXT) ospf6_nsm.$(OBJEXT) \
+	ospf6_routemap.$(OBJEXT) ospf6_proto.$(OBJEXT) \
+	ospf6_hook.$(OBJEXT) ospf6_asbr.$(OBJEXT) \
+	ospf6_bintree.$(OBJEXT) ospf6_linklist.$(OBJEXT) \
+	ospf6_abr.$(OBJEXT) ospf6_intra.$(OBJEXT) ospf6_damp.$(OBJEXT)
+libospf6_a_OBJECTS = $(am_libospf6_a_OBJECTS)
+sbin_PROGRAMS = ospf6d$(EXEEXT)
+PROGRAMS = $(sbin_PROGRAMS)
+
+am__objects_1 = ospf6_dump.$(OBJEXT) ospf6d.$(OBJEXT) \
+	ospf6_interface.$(OBJEXT) ospf6_network.$(OBJEXT) \
+	ospf6_neighbor.$(OBJEXT) ospf6_message.$(OBJEXT) \
+	ospf6_lsa.$(OBJEXT) ospf6_spf.$(OBJEXT) ospf6_route.$(OBJEXT) \
+	ospf6_zebra.$(OBJEXT) ospf6_ism.$(OBJEXT) ospf6_dbex.$(OBJEXT) \
+	ospf6_lsdb.$(OBJEXT) ospf6_prefix.$(OBJEXT) ospf6_top.$(OBJEXT) \
+	ospf6_area.$(OBJEXT) ospf6_nsm.$(OBJEXT) \
+	ospf6_routemap.$(OBJEXT) ospf6_proto.$(OBJEXT) \
+	ospf6_hook.$(OBJEXT) ospf6_asbr.$(OBJEXT) \
+	ospf6_bintree.$(OBJEXT) ospf6_linklist.$(OBJEXT) \
+	ospf6_abr.$(OBJEXT) ospf6_intra.$(OBJEXT) ospf6_damp.$(OBJEXT)
+am_ospf6d_OBJECTS = ospf6_main.$(OBJEXT) $(am__objects_1)
+ospf6d_OBJECTS = $(am_ospf6d_OBJECTS)
+ospf6d_DEPENDENCIES = ../lib/libzebra.a
+ospf6d_LDFLAGS =
+
+DEFAULT_INCLUDES =  -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/ospf6_abr.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_area.Po ./$(DEPDIR)/ospf6_asbr.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_bintree.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_damp.Po ./$(DEPDIR)/ospf6_dbex.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_dump.Po ./$(DEPDIR)/ospf6_hook.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_interface.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_intra.Po ./$(DEPDIR)/ospf6_ism.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_linklist.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_lsa.Po ./$(DEPDIR)/ospf6_lsdb.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_main.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_message.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_neighbor.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_network.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_nsm.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_prefix.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_proto.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_route.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_routemap.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_spf.Po ./$(DEPDIR)/ospf6_top.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ospf6_zebra.Po ./$(DEPDIR)/ospf6d.Po
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES = $(libospf6_a_SOURCES) $(ospf6d_SOURCES)
+DATA = $(sysconf_DATA)
+
+HEADERS = $(noinst_HEADERS)
+
+DIST_COMMON = README $(noinst_HEADERS) ChangeLog Makefile.am \
+	Makefile.in
+SOURCES = $(libospf6_a_SOURCES) $(ospf6d_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in:  Makefile.am  $(top_srcdir)/configure.in $(ACLOCAL_M4)
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign  ospf6d/Makefile
+Makefile:  $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+
+clean-noinstLIBRARIES:
+	-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libospf6.a: $(libospf6_a_OBJECTS) $(libospf6_a_DEPENDENCIES) 
+	-rm -f libospf6.a
+	$(libospf6_a_AR) libospf6.a $(libospf6_a_OBJECTS) $(libospf6_a_LIBADD)
+	$(RANLIB) libospf6.a
+sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(sbindir)
+	@list='$(sbin_PROGRAMS)'; for p in $$list; do \
+	  p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  if test -f $$p \
+	  ; then \
+	    f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+	   echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \
+	   $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f || exit 1; \
+	  else :; fi; \
+	done
+
+uninstall-sbinPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(sbin_PROGRAMS)'; for p in $$list; do \
+	  f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+	  echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \
+	  rm -f $(DESTDIR)$(sbindir)/$$f; \
+	done
+
+clean-sbinPROGRAMS:
+	-test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
+ospf6d$(EXEEXT): $(ospf6d_OBJECTS) $(ospf6d_DEPENDENCIES) 
+	@rm -f ospf6d$(EXEEXT)
+	$(LINK) $(ospf6d_LDFLAGS) $(ospf6d_OBJECTS) $(ospf6d_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_abr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_area.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_asbr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_bintree.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_damp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_dbex.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_dump.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_hook.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_interface.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_intra.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_ism.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_linklist.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_lsa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_lsdb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_message.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_neighbor.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_network.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_nsm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_prefix.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_proto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_route.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_routemap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_spf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_top.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_zebra.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6d.Po@am__quote@
+
+distclean-depend:
+	-rm -rf ./$(DEPDIR)
+
+.c.o:
+@am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@	  -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \
+@am__fastdepCC_TRUE@	then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@	else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@	fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
+
+.c.obj:
+@am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@	  -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`; \
+@am__fastdepCC_TRUE@	then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@	else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@	fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`
+uninstall-info-am:
+sysconfDATA_INSTALL = $(INSTALL_DATA)
+
+uninstall-sysconfDATA:
+	@$(NORMAL_UNINSTALL)
+	@list='$(sysconf_DATA)'; for p in $$list; do \
+	  f="`echo $$p | sed -e 's|^.*/||'`"; \
+	  echo " rm -f $(DESTDIR)$(sysconfdir)/$$f"; \
+	  rm -f $(DESTDIR)$(sysconfdir)/$$f; \
+	done
+
+ETAGS = etags
+ETAGSFLAGS =
+
+CTAGS = ctags
+CTAGSFLAGS =
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$tags$$unique" \
+	  || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	     $$tags $$unique
+
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkinstalldirs) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS)
+
+installdirs:
+	$(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(sysconfdir)
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-noinstLIBRARIES clean-sbinPROGRAMS \
+	mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+	distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-sbinPROGRAMS install-sysconfDATA
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \
+	uninstall-sysconfDATA
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-noinstLIBRARIES clean-sbinPROGRAMS ctags distclean \
+	distclean-compile distclean-depend distclean-generic \
+	distclean-tags distdir dvi dvi-am info info-am install \
+	install-am install-data install-data-am install-exec \
+	install-exec-am install-info install-info-am install-man \
+	install-sbinPROGRAMS install-strip install-sysconfDATA \
+	installcheck installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
+	uninstall-am uninstall-info-am uninstall-sbinPROGRAMS \
+	uninstall-sysconfDATA
+
+
+install-sysconfDATA: $(sysconf_DATA)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+	@list='$(sysconf_DATA)'; for p in $$list; do \
+	  if test -f $(srcdir)/$$p; then \
+	    echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+	    $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+	  else if test -f $$p; then \
+	    echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+	    $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+	  fi; fi; \
+	done
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ospf6d/README b/ospf6d/README
new file mode 100644
index 0000000..b3b4d16
--- /dev/null
+++ b/ospf6d/README
@@ -0,0 +1,85 @@
+
+		  Zebra OSPF daemon for IPv6 network
+
+			     2001/12/20
+
+Zebra OSPF6d is OSPF version 3 daemon which is specified by
+"OSPF for IPv6" (RFC 2740).
+
+*** NOTE ***
+  Zebra ospf6d is in development yet. It may lack some functionalities,
+  and may have some bugs. Use the latest version from the anoncvs
+  repository (http://www.zebra.org/cvs.html) !
+
+This file README is like memo yet, so please feel free to ask
+<yasu@sfc.wide.ad.jp> by E-mail. Patches will be appriciated.
+
+ospf6d's vty port was default to 2606/tcp.
+Use commands below.
+
+VIEW NODE:
+  show ipv6 ospf6
+    To see Router-ID, uptime of ospf6d, some statistics.
+
+  show ipv6 ospf6 database ...
+    This command shows LSA database. You can specify
+    LS-type/LS-ID/Advertising-Router of LSAs. '*' is recognized.
+
+  show ipv6 ospf6 interface ...
+    To see the status of the OSPF interface, and the configuration
+    like interface costs.
+
+  show ipv6 ospf6 neighbor ...
+    Shows state of neighbors and choosed (Backup) DR on the I/F.
+
+  show ipv6 ospf6 route (X::X)
+    This command shows internal routing table of the ospf6d.
+    Routes not calculated by OSPFv3 (like connected routes)
+    are not shown. If Address is specified (X::X), shows the route
+    that the address matches.
+
+  show ipv6 ospf6 route redistribute (X::X)
+    Shows the routes advertised as AS-External routes by the router
+    itself. If Address is specified (X::X), shows the route
+    that the address matches.
+
+CONFIG NODE:
+  interface NAME
+    To enter INTERFACE NODE
+
+  router ospf6 ...
+    To enter OSPF6 NODE
+
+INTERFACE NODE:
+  ipv6 ospf6 cost COST
+    Sets the interface's output cost. default 1
+
+  ipv6 ospf6 hello-interval HELLOINTERVAL
+    Sets the interface's Hello Interval. default 10
+
+  ipv6 ospf6 dead-interval DEADINTERVAL
+    Sets the interface's Router Dead Interval. default 40
+
+  ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL
+    Sets the interface's Rxmt Interval. default 5
+
+  ipv6 ospf6 priority PRIORITY
+    Sets the interface's Router Priority. default 1
+
+  ipv6 ospf6 transmit-delay TRANSMITDELAY
+    Sets the interface's Inf-Trans-Delay. default 1
+
+OSPF6 NODE:
+  router-id A.B.C.D
+    Sets the router's Router-ID
+
+  interface NAME area AREA
+    Binds interface to specified Area, and start
+    sending OSPFv3 packets.
+
+Sample configuration is in ospf6d.conf.sample.
+
+--
+Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+Kunihiro Ishiguro <kunihiro@zebra.org>
+
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
new file mode 100644
index 0000000..864e0c2
--- /dev/null
+++ b/ospf6d/ospf6_abr.c
@@ -0,0 +1,655 @@
+/*
+ * 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
new file mode 100644
index 0000000..510532e
--- /dev/null
+++ b/ospf6d/ospf6_abr.h
@@ -0,0 +1,56 @@
+/*
+ * 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
new file mode 100644
index 0000000..51af508
--- /dev/null
+++ b/ospf6d/ospf6_area.c
@@ -0,0 +1,332 @@
+/*
+ * OSPF6 Area Data Structure
+ * 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 "ospf6d.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 *))
+{
+  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);
+}
+
+int
+ospf6_area_is_stub (struct ospf6_area *o6a)
+{
+  if (OSPF6_OPT_ISSET (o6a->options, OSPF6_OPT_E))
+    return 0;
+  return 1;
+}
+
+int
+ospf6_area_is_transit (struct ospf6_area *o6a)
+{
+  return 0;
+}
+
+
+
+void
+ospf6_area_route_add (void *data)
+{
+  struct ospf6_route_req *route = data;
+  struct in6_addr local;
+
+  inet_pton (AF_INET6, "::1", &local);
+  if (! memcmp (&route->nexthop.address, &local, sizeof (struct in6_addr)))
+    {
+      if (IS_OSPF6_DUMP_AREA)
+        zlog_info ("AREA: Self-originated route add, ignore");
+      return;
+    }
+
+  ospf6_route_add (route, ospf6->route_table);
+}
+
+void
+ospf6_area_route_remove (void *data)
+{
+  struct ospf6_route_req *route = data;
+  struct in6_addr local;
+
+  inet_pton (AF_INET6, "::1", &local);
+  if (! memcmp (&route->nexthop.address, &local, sizeof (struct in6_addr)))
+    {
+      if (IS_OSPF6_DUMP_AREA)
+        zlog_info ("AREA: Self-originated route remove, ignore");
+      return;
+    }
+
+  ospf6_route_remove (route, ospf6->route_table);
+}
+
+/* Make new area structure */
+struct ospf6_area *
+ospf6_area_create (u_int32_t area_id)
+{
+  struct ospf6_area *o6a;
+  char namebuf[64];
+
+  /* allocate memory */
+  o6a = 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 ();
+
+  o6a->lsdb = ospf6_lsdb_create ();
+  o6a->spf_tree = ospf6_spftree_create ();
+
+  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;
+
+  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;
+
+  /* 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);
+
+  o6a->foreach_if = ospf6_area_foreach_interface;
+  o6a->foreach_nei = ospf6_area_foreach_neighbor;
+
+  return o6a;
+}
+
+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)
+{
+  listnode n;
+  struct ospf6_interface *o6i;
+
+  CALL_REMOVE_HOOK (&area_hook, o6a);
+
+  /* ospf6 interface list */
+  for (n = listhead (o6a->if_list); n; nextnode (n))
+    {
+      o6i = (struct ospf6_interface *) getdata (n);
+      /* ospf6_interface_delete (o6i); */
+    }
+  list_delete (o6a->if_list);
+
+  /* terminate LSDB */
+  ospf6_lsdb_remove_all (o6a->lsdb);
+
+  /* spf tree terminate */
+  /* xxx */
+
+  /* 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;
+
+  /* new */
+  ospf6_route_table_delete (o6a->route_table);
+
+  ospf6_spftree_delete (o6a->spf_tree);
+  ospf6_route_table_delete (o6a->table_topology);
+
+  /* free area */
+  XFREE (MTYPE_OSPF6_AREA, o6a);
+}
+
+struct ospf6_area *
+ospf6_area_lookup (u_int32_t area_id, struct ospf6 *o6)
+{
+  struct ospf6_area *o6a;
+  listnode n;
+
+  for (n = listhead (o6->area_list); n; nextnode (n))
+    {
+      o6a = (struct ospf6_area *) getdata (n);
+      if (o6a->area_id == area_id)
+        return o6a;
+    }
+
+  return (struct ospf6_area *) NULL;
+}
+
+void
+ospf6_area_show (struct vty *vty, struct ospf6_area *o6a)
+{
+  listnode i;
+  struct ospf6_interface *o6i;
+
+  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);
+
+  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))
+    {
+      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);
+    }
+}
+
+void
+ospf6_area_statistics_show (struct vty *vty, struct ospf6_area *o6a)
+{
+#if 0
+  listnode node;
+  struct ospf6_interface *o6i;
+
+  vty_out (vty, "  Statistics of Area %s%s", o6a->str, VTY_NEWLINE);
+#endif
+}
+
+DEFUN (show_ipv6_ospf6_area_route,
+       show_ipv6_ospf6_area_route_cmd,
+       "show ipv6 ospf6 area A.B.C.D route",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       OSPF6_AREA_STR
+       OSPF6_AREA_ID_STR
+       ROUTE_STR
+       )
+{
+  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);
+}
+
+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)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       OSPF6_AREA_STR
+       OSPF6_AREA_ID_STR
+       ROUTE_STR
+       "Specify IPv6 address\n"
+       "Detailed information\n"
+       )
+
+void
+ospf6_area_init ()
+{
+  area_index = ospf6_dump_install ("area", "Area information\n");
+
+  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);
+}
+
+
diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h
new file mode 100644
index 0000000..0684464
--- /dev/null
+++ b/ospf6d/ospf6_area.h
@@ -0,0 +1,90 @@
+/*
+ * OSPF6 Area Data Structure
+ * 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 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];
+
+  struct ospf6   *ospf6;      /* back pointer */
+  u_int32_t       area_id;
+  u_char          options[3]; /* OSPF Option including ExternalCapability */
+
+  list            if_list; /* OSPF interface to this area */
+
+  struct ospf6_lsdb *lsdb;
+
+  struct thread  *spf_calc;
+  struct thread  *route_calc;
+  int             stat_spf_execed;
+  int             stat_route_execed;
+
+  struct route_table *table; /* new route table */
+
+  struct prefix_ipv6 area_range;
+  struct ospf6_spftree *spf_tree;
+
+  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_router_lsa;
+};
+
+
+/* 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_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);
+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);
+
+void ospf6_area_init ();
+
+#endif /* OSPF_AREA_H */
+
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
new file mode 100644
index 0000000..00a2b66
--- /dev/null
+++ b/ospf6d/ospf6_asbr.c
@@ -0,0 +1,1040 @@
+/*
+ * Copyright (C) 2001-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 "log.h"
+#include "memory.h"
+#include "prefix.h"
+#include "command.h"
+#include "vty.h"
+#include "routemap.h"
+#include "table.h"
+#include "plist.h"
+#include "thread.h"
+
+#include "ospf6_prefix.h"  /* xxx for ospf6_asbr.h */
+#include "ospf6_lsa.h"     /* xxx for ospf6_asbr.h */
+#include "ospf6_route.h"   /* xxx for ospf6_asbr.h, ospf6_zebra.h */
+#include "ospf6_zebra.h"
+#include "ospf6_asbr.h"
+#include "ospf6_damp.h"
+#include "ospf6_top.h"
+#include "ospf6_lsdb.h"
+#include "ospf6_proto.h"
+
+extern struct thread_master *master;
+
+struct route_table *external_table;
+struct
+{
+  char *name;
+  struct route_map *map;
+} rmap [ZEBRA_ROUTE_MAX];
+
+static u_int32_t link_state_id = 0;
+
+char *
+zroute_name[] =
+{ 
+  "system", "kernel", "connected", "static",
+  "rip", "ripng", "ospf", "ospf6", "bgp", "unknown"
+};
+char *
+zroute_abname[] =
+{
+  "X", "K", "C", "S", "R", "R", "O", "O", "B", "?"
+};
+
+#define ZROUTE_NAME(x) \
+  (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \
+   zroute_name[(x)] : zroute_name[ZEBRA_ROUTE_MAX])
+
+#define ZROUTE_ABNAME(x) \
+  (0 < (x) && (x) < ZEBRA_ROUTE_MAX ? \
+   zroute_abname[(x)] : zroute_abname[ZEBRA_ROUTE_MAX])
+
+/* redistribute function */
+void
+ospf6_asbr_routemap_set (int type, char *mapname)
+{
+  if (rmap[type].name)
+    free (rmap[type].name);
+
+  rmap[type].name = strdup (mapname);
+  rmap[type].map = route_map_lookup_by_name (mapname);
+}
+
+void
+ospf6_asbr_routemap_unset (int type)
+{
+  if (rmap[type].name)
+    free (rmap[type].name);
+  rmap[type].name = NULL;
+  rmap[type].map = NULL;
+}
+
+void
+ospf6_asbr_routemap_update ()
+{
+  int i;
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    {
+      if (rmap[i].name)
+        rmap[i].map = route_map_lookup_by_name (rmap[i].name);
+      else
+        rmap[i].map = NULL;
+    }
+}
+
+DEFUN (ospf6_redistribute,
+       ospf6_redistribute_cmd,
+       "redistribute (static|kernel|connected|ripng|bgp)",
+       "Redistribute\n"
+       "Static route\n"
+       "Kernel route\n"
+       "Connected route\n"
+       "RIPng route\n"
+       "BGP route\n"
+      )
+{
+  int type = 0;
+
+  if (strncmp (argv[0], "sta", 3) == 0)
+    type = ZEBRA_ROUTE_STATIC;
+  else if (strncmp (argv[0], "ker", 3) == 0)
+    type = ZEBRA_ROUTE_KERNEL;
+  else if (strncmp (argv[0], "con", 3) == 0)
+    type = ZEBRA_ROUTE_CONNECT;
+  else if (strncmp (argv[0], "rip", 3) == 0)
+    type = ZEBRA_ROUTE_RIPNG;
+  else if (strncmp (argv[0], "bgp", 3) == 0)
+    type = ZEBRA_ROUTE_BGP;
+
+  ospf6_zebra_no_redistribute (type);
+  ospf6_asbr_routemap_unset (type);
+  ospf6_zebra_redistribute (type);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ospf6_redistribute_routemap,
+       ospf6_redistribute_routemap_cmd,
+       "redistribute (static|kernel|connected|ripng|bgp) route-map WORD",
+       "Redistribute\n"
+       "Static routes\n"
+       "Kernel route\n"
+       "Connected route\n"
+       "RIPng route\n"
+       "BGP route\n"
+       "Route map reference\n"
+       "Route map name\n"
+      )
+{
+  int type = 0;
+
+  if (strncmp (argv[0], "sta", 3) == 0)
+    type = ZEBRA_ROUTE_STATIC;
+  else if (strncmp (argv[0], "ker", 3) == 0)
+    type = ZEBRA_ROUTE_KERNEL;
+  else if (strncmp (argv[0], "con", 3) == 0)
+    type = ZEBRA_ROUTE_CONNECT;
+  else if (strncmp (argv[0], "rip", 3) == 0)
+    type = ZEBRA_ROUTE_RIPNG;
+  else if (strncmp (argv[0], "bgp", 3) == 0)
+    type = ZEBRA_ROUTE_BGP;
+
+  ospf6_zebra_no_redistribute (type);
+  ospf6_asbr_routemap_set (type, argv[1]);
+  ospf6_zebra_redistribute (type);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf6_redistribute,
+       no_ospf6_redistribute_cmd,
+       "no redistribute (static|kernel|connected|ripng|bgp)",
+       NO_STR
+       "Redistribute\n"
+       "Static route\n"
+       "Kernel route\n"
+       "Connected route\n"
+       "RIPng route\n"
+       "BGP route\n"
+      )
+{
+  int type = 0;
+  struct route_node *node;
+  struct ospf6_external_route *route;
+  struct ospf6_external_info *info, *info_next = NULL;
+
+  if (strncmp (argv[0], "sta", 3) == 0)
+    type = ZEBRA_ROUTE_STATIC;
+  else if (strncmp (argv[0], "ker", 3) == 0)
+    type = ZEBRA_ROUTE_KERNEL;
+  else if (strncmp (argv[0], "con", 3) == 0)
+    type = ZEBRA_ROUTE_CONNECT;
+  else if (strncmp (argv[0], "rip", 3) == 0)
+    type = ZEBRA_ROUTE_RIPNG;
+  else if (strncmp (argv[0], "bgp", 3) == 0)
+    type = ZEBRA_ROUTE_BGP;
+
+  ospf6_zebra_no_redistribute (type);
+  ospf6_asbr_routemap_unset (type);
+
+  /* remove redistributed route */
+  for (node = route_top (external_table); node; node = route_next (node))
+    {
+      route = node->info;
+      if (! route)
+        continue;
+      for (info = route->info_head; info; info = info_next)
+        {
+          info_next = info->next;
+          if (info->type != type)
+            continue;
+          ospf6_asbr_route_remove (info->type, info->ifindex,
+                                   &route->prefix);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+
+int
+ospf6_redistribute_config_write (struct vty *vty)
+{
+  int i;
+
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    {
+      if (i == ZEBRA_ROUTE_OSPF6)
+        continue;
+
+      if (! ospf6_zebra_is_redistribute (i))
+        continue;
+
+      if (rmap[i].map)
+        vty_out (vty, " redistribute %s route-map %s%s",
+                 ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE);
+      else
+        vty_out (vty, " redistribute %s%s",
+                 ZROUTE_NAME(i), VTY_NEWLINE);
+    }
+
+  return 0;
+}
+
+void
+ospf6_redistribute_show_config (struct vty *vty)
+{
+  int i;
+
+  if (! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_SYSTEM) &&
+      ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_KERNEL) &&
+      ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_STATIC) &&
+      ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_RIPNG) &&
+      ! ospf6_zebra_is_redistribute(ZEBRA_ROUTE_BGP))
+    return;
+
+  vty_out (vty, " Redistributing External Routes from,%s", VTY_NEWLINE);
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    {
+      if (i == ZEBRA_ROUTE_OSPF6)
+        continue;
+      if (! ospf6_zebra_is_redistribute (i))
+        continue;
+
+      if (rmap[i].map)
+        vty_out (vty, "    %s with route-map %s%s",
+                 ZROUTE_NAME(i), rmap[i].name, VTY_NEWLINE);
+      else
+        vty_out (vty, "    %s%s", ZROUTE_NAME(i), VTY_NEWLINE);
+    }
+}
+
+/* AS External LSA origination */
+int
+ospf6_asbr_external_lsa_originate (struct thread *thread)
+{
+  struct ospf6_external_info *info;
+  char buffer [MAXLSASIZE];
+  struct ospf6_lsa_as_external *e;
+  char *p;
+
+  info = THREAD_ARG (thread);
+
+  /* clear thread */
+  info->thread_originate = NULL;
+
+  if (info->is_removed)
+    {
+      if (IS_OSPF6_DUMP_ASBR)
+        {
+          char pbuf[64];
+          prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+          zlog_info ("ASBR: quit redistribution %s: state is down",
+                     pbuf);
+        }
+      return 0;
+    }
+
+  /* prepare buffer */
+  memset (buffer, 0, sizeof (buffer));
+  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))
+    {
+      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;
+  struct ospf6_external_info *info;
+
+  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);
+
+  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;
+}
+
+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 (! ospf6_zebra_is_redistribute (type))
+    return;
+
+  /* apply route-map */
+  memset (&tinfo, 0, sizeof (struct ospf6_external_info));
+  if (rmap[type].map)
+    {
+      ret = route_map_apply (rmap[type].map, prefix, RMAP_OSPF6, &tinfo);
+      if (ret == RMAP_DENYMATCH)
+        {
+          if (IS_OSPF6_DUMP_ASBR)
+            zlog_info ("ASBR: denied by route-map %s", rmap[type].name);
+          return;
+        }
+    }
+
+  node = route_node_get (external_table, prefix);
+  route = node->info;
+
+  if (! route)
+    {
+      route = XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
+                       sizeof (struct ospf6_external_route));
+      memset (route, 0, sizeof (struct ospf6_external_route));
+
+      memcpy (&route->prefix, prefix, sizeof (struct prefix));
+
+      node->info = route;
+      route->node = node;
+    }
+
+  for (info = route->info_head; info; info = info->next)
+    {
+      if (info->type == type && info->ifindex == ifindex)
+        break;
+    }
+
+  if (! info)
+    {
+      info = XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
+                      sizeof (struct ospf6_external_info));
+      memset (info, 0, sizeof (struct ospf6_external_info));
+
+      info->route = route;
+      /* add tail */
+      info->prev = route->info_tail;
+      if (route->info_tail)
+        route->info_tail->next = info;
+      else
+        route->info_head = info;
+      route->info_tail = info;
+
+      info->id = link_state_id++;
+    }
+
+  /* copy result of route-map */
+  info->metric_type = tinfo.metric_type;
+  info->metric = tinfo.metric;
+  memcpy (&info->forwarding, &tinfo.forwarding,
+          sizeof (struct in6_addr));
+
+  info->type = type;
+  info->ifindex = ifindex;
+
+  if (nexthop_num && nexthop)
+    {
+      info->nexthop_num = nexthop_num;
+
+      if (info->nexthop)
+        XFREE (MTYPE_OSPF6_EXTERNAL_INFO, info->nexthop);
+
+      info->nexthop = (struct in6_addr *)
+        XMALLOC (MTYPE_OSPF6_EXTERNAL_INFO,
+                 nexthop_num * sizeof (struct in6_addr));
+      memcpy (info->nexthop, nexthop,
+              nexthop_num * sizeof (struct in6_addr));
+    }
+
+  info->is_removed = 0;
+
+  //if (IS_OSPF6_DUMP_ASBR)
+    {
+      char pbuf[64];
+      struct timeval now;
+      prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+      gettimeofday (&now, NULL);
+      zlog_info ("ASBR: start redistributing %s as LS-ID %ld: %ld.%06ld",
+                 pbuf, (u_long) info->id, now.tv_sec, now.tv_usec);
+    }
+
+#ifdef HAVE_OSPF6_DAMP
+  ospf6_damp_event_up (OSPF6_DAMP_TYPE_ROUTE, prefix,
+                       ospf6_asbr_schedule_external, info);
+#else /*HAVE_OSPF6_DAMP*/
+  ospf6_asbr_schedule_external (info);
+#endif /*HAVE_OSPF6_DAMP*/
+}
+
+void
+ospf6_asbr_route_remove (int type, int ifindex, struct prefix *prefix)
+{
+  struct route_node *node;
+  struct ospf6_external_route *route;
+  struct ospf6_external_info *info;
+  struct ospf6_lsa *lsa;
+
+  node = route_node_get (external_table, prefix);
+  route = node->info;
+
+  if (! route)
+    return;
+
+  for (info = route->info_head; info; info = info->next)
+    {
+      if (info->type == type && info->ifindex == ifindex)
+        break;
+    }
+
+  if (! info)
+    return;
+
+  //if (IS_OSPF6_DUMP_ASBR)
+    {
+      char pbuf[64];
+      struct timeval now;
+      prefix2str (&info->route->prefix, pbuf, sizeof (pbuf));
+      gettimeofday (&now, NULL);
+      zlog_info ("ASBR: quit redistributing %s as LS-ID %ld: %ld.%06ld",
+                 pbuf, (u_long) info->id, now.tv_sec, now.tv_usec);
+    }
+
+  if (info->thread_originate)
+    thread_cancel (info->thread_originate);
+  info->thread_originate = NULL;
+
+  lsa = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_AS_EXTERNAL),
+                           htonl (info->id), ospf6->router_id, ospf6);
+#ifdef HAVE_OSPF6_DAMP
+  ospf6_damp_event_down (OSPF6_DAMP_TYPE_ROUTE, &info->route->prefix,
+                         ospf6_asbr_external_lsa_flush, lsa);
+#else /*HAVE_OSPF6_DAMP*/
+  ospf6_asbr_external_lsa_flush (lsa);
+#endif /*HAVE_OSPF6_DAMP*/
+
+#if 1
+  info->is_removed = 1;
+#else
+  /* remove from route */
+  if (info->prev)
+    info->prev->next = info->next;
+  else
+    info->route->info_head = info->next;
+  if (info->next)
+    info->next->prev = info->prev;
+  else
+    info->route->info_tail = info->prev;
+
+  /* if no info, free route */
+  if (! info->route->info_head && ! info->route->info_tail)
+    {
+      info->route->node->info = NULL;
+      free (info->route);
+    }
+
+  if (info->nexthop)
+    free (info->nexthop);
+  free (info);
+#endif /*0*/
+}
+
+void
+ospf6_asbr_external_lsa_add (struct ospf6_lsa *lsa)
+{
+  struct ospf6_lsa_as_external *external;
+  struct prefix_ls asbr_id;
+  struct ospf6_route_req asbr_entry;
+  struct ospf6_route_req request;
+
+  external = OSPF6_LSA_HEADER_END (lsa->header);
+
+  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;
+    }
+
+  if (IS_OSPF6_DUMP_ASBR)
+    zlog_info ("ASBR: new external lsa: %s seq: %lx",
+               lsa->str, (u_long)ntohl (lsa->header->seqnum));
+
+  if (lsa->header->adv_router == ospf6->router_id)
+    {
+      if (IS_OSPF6_DUMP_ASBR)
+        zlog_info ("ASBR: my external LSA, ignore");
+      return;
+    }
+
+  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_asbr_external_lsa_remove (struct ospf6_lsa *lsa)
+{
+  struct ospf6_lsa_as_external *external;
+  struct prefix dest;
+  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;
+
+  assert (lsa->header);
+  external = (struct ospf6_lsa_as_external *)(lsa->header + 1);
+  
+  /* 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" : "-"));
+
+  vty_out (vty, "     Bits: %s%s", buf, VTY_NEWLINE);
+  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);
+
+  vty_out (vty, "     Referenced LSType: %d%s",
+           ntohs (external->prefix.prefix_refer_lstype), VTY_NEWLINE);
+
+  ospf6_prefix_in6_addr (&external->prefix, &in6);
+  inet_ntop (AF_INET6, &in6, buf, sizeof (buf));
+  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));
+      vty_out (vty, "     Forwarding-Address: %s%s", buf, VTY_NEWLINE);
+    }
+
+  return 0;
+}
+
+void
+ospf6_asbr_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new)
+{
+  if (old)
+    ospf6_asbr_external_lsa_remove (old);
+  if (new && ! IS_LSA_MAXAGE (new))
+    ospf6_asbr_external_lsa_add (new);
+}
+
+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",
+       SHOW_STR
+       IP6_STR
+       ROUTE_STR
+       OSPF6_STR
+       "redistributing External information\n"
+       )
+{
+  struct route_node *node;
+  struct ospf6_external_route *route;
+
+  vty_out (vty, "%s %-32s %3s %-15s %3s %s%s",
+           " ", "Prefix", "I/F", "LS-Id", "#NH", "Metric",
+           VTY_NEWLINE);
+  for (node = route_top (external_table); node; node = route_next (node))
+    {
+      route = node->info;
+      if (route)
+        ospf6_asbr_external_route_show (vty, route);
+    }
+  return CMD_SUCCESS;
+}
+
+void
+ospf6_asbr_init ()
+{
+  external_table = route_table_init ();
+  link_state_id = 0;
+
+  ospf6_asbr_register_as_external ();
+
+  install_element (VIEW_NODE, &show_ipv6_route_ospf6_external_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_route_ospf6_external_cmd);
+  install_element (OSPF6_NODE, &ospf6_redistribute_cmd);
+  install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd);
+  install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd);
+}
+
+
diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h
new file mode 100644
index 0000000..153ed21
--- /dev/null
+++ b/ospf6d/ospf6_asbr.h
@@ -0,0 +1,112 @@
+/*
+ * 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_ASBR_H
+#define OSPF6_ASBR_H
+
+#include "thread.h"
+
+struct ospf6_external_info
+{
+  int is_removed;
+  struct thread *thread_originate;
+
+  struct ospf6_external_route *route;
+
+  struct ospf6_external_info *prev;
+  struct ospf6_external_info *next;
+
+  /* external route type */
+  int type;
+
+  /* external route ifindex */
+  int ifindex;
+
+  /* LS-ID */
+  u_int32_t id;
+
+  /* nexthops */
+  u_int nexthop_num;
+  struct in6_addr *nexthop;
+
+  u_int8_t  prefix_options;
+
+  u_int8_t  metric_type;
+  u_int32_t metric;
+  struct in6_addr forwarding;
+  /* u_int32_t tag; */
+};
+
+struct ospf6_external_route
+{
+  struct route_node *node;
+
+  /* prefix */
+  struct prefix prefix;
+
+  /* external information */
+  struct ospf6_external_info *info_head;
+  struct ospf6_external_info *info_tail;
+};
+
+/* AS-External-LSA */
+struct ospf6_lsa_as_external
+{
+  u_int32_t bits_metric;
+
+  struct ospf6_prefix prefix;
+  /* followed by none or one forwarding address */
+  /* followed by none or one external route tag */
+  /* followed by none or one referenced LS-ID */
+};
+
+#define OSPF6_ASBR_BIT_T  ntohl (0x01000000)
+#define OSPF6_ASBR_BIT_F  ntohl (0x02000000)
+#define OSPF6_ASBR_BIT_E  ntohl (0x04000000)
+
+#define OSPF6_ASBR_METRIC(E) (ntohl ((E)->bits_metric & htonl (0x00ffffff)))
+#define OSPF6_ASBR_METRIC_SET(E,C) \
+  { (E)->bits_metric &= htonl (0xff000000); \
+    (E)->bits_metric |= htonl (0x00ffffff) & htonl (C); }
+
+void ospf6_asbr_routemap_update ();
+
+int ospf6_redistribute_config_write (struct vty *vty);
+void ospf6_redistribute_show_config (struct vty *vty);
+
+void
+ospf6_asbr_route_add (int type, int ifindex, struct prefix *prefix,
+                      u_int nexthop_num, struct in6_addr *nexthop);
+void
+ospf6_asbr_route_remove (int type, int ifindex, struct prefix *prefix);
+
+void ospf6_asbr_external_lsa_add (struct ospf6_lsa *lsa);
+void ospf6_asbr_external_lsa_remove (struct ospf6_lsa *lsa);
+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 ();
+
+#endif /* OSPF6_ASBR_H */
+
diff --git a/ospf6d/ospf6_bintree.c b/ospf6d/ospf6_bintree.c
new file mode 100644
index 0000000..c1e9e55
--- /dev/null
+++ b/ospf6d/ospf6_bintree.c
@@ -0,0 +1,436 @@
+
+#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
new file mode 100644
index 0000000..fad8bbd
--- /dev/null
+++ b/ospf6d/ospf6_bintree.h
@@ -0,0 +1,47 @@
+
+#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
new file mode 100644
index 0000000..4e807a7
--- /dev/null
+++ b/ospf6d/ospf6_damp.c
@@ -0,0 +1,748 @@
+/*
+ * OSPF flap dampening by Manav Bhatia
+ * Copyright (C) 2002 
+ * 
+ * This file is part of GNU Zebra.
+ * 
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ * 
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include <zebra.h>
+#include <math.h>
+
+#include "log.h"
+#include "prefix.h"
+#include "thread.h"
+#include "table.h"
+#include "command.h"
+#include "vty.h"
+
+extern struct thread_master *master;
+
+#include "ospf6_damp.h"
+
+#ifdef HAVE_OSPF6_DAMP
+
+#define DELTA_REUSE         10 /* Time granularity for reuse lists */
+#define DELTA_T              5 /* Time granularity for decay arrays */
+#define DEFAULT_HALF_LIFE   60 /* (sec)     1 min */
+
+#define DEFAULT_PENALTY   1000
+#define DEFAULT_REUSE      750
+#define DEFAULT_SUPPRESS  2000
+
+#define REUSE_LIST_SIZE    256
+#define REUSE_ARRAY_SIZE  1024
+
+/* Global variable to access damping configuration */
+struct ospf6_damp_config damp_config;
+struct ospf6_damp_config *dc = &damp_config;
+u_int reuse_array_offset = 0;
+struct route_table *damp_info_table[OSPF6_DAMP_TYPE_MAX];
+struct thread *ospf6_reuse_thread = NULL;
+
+int ospf6_damp_debug = 0;
+#define IS_OSPF6_DEBUG_DAMP (ospf6_damp_debug)
+
+static struct ospf6_damp_info *
+ospf6_damp_lookup (u_short type, struct prefix *name)
+{
+  struct route_node *node;
+
+  node = route_node_lookup (damp_info_table[type], name);
+  if (node && node->info)
+    return (struct ospf6_damp_info *) node->info;
+  return NULL;
+}
+
+static struct ospf6_damp_info *
+ospf6_damp_create (u_short type, struct prefix *name)
+{
+  struct route_node *node;
+  struct ospf6_damp_info *di;
+  char namebuf[64];
+
+  di = ospf6_damp_lookup (type, name);
+  if (di)
+    return di;
+
+  if (IS_OSPF6_DEBUG_DAMP)
+    {
+      prefix2str (name, namebuf, sizeof (namebuf));
+      zlog_info ("DAMP: create: type: %d, name: %s", type, namebuf);
+    }
+
+  di = (struct ospf6_damp_info *)
+    malloc (sizeof (struct ospf6_damp_info));
+  memset (di, 0, sizeof (struct ospf6_damp_info));
+  di->type = type;
+  prefix_copy (&di->name, name);
+
+  node = route_node_get (damp_info_table[type], name);
+  node->info = di;
+
+  return di;
+}
+
+static void
+ospf6_damp_delete (u_short type, struct prefix *name)
+{
+  struct route_node *node;
+  struct ospf6_damp_info *di;
+  char namebuf[64];
+
+  node = route_node_lookup (damp_info_table[type], name);
+  if (! node || ! node->info)
+    return;
+
+  di = node->info;
+
+  if (IS_OSPF6_DEBUG_DAMP)
+    {
+      prefix2str (&di->name, namebuf, sizeof (namebuf));
+      zlog_info ("DAMP: delete: type: %d, name: %s",
+                 di->type, namebuf);
+    }
+
+  node->info = NULL;
+  free (di);
+}
+
+/* compute and fill the configuration parameter */
+void
+ospf6_damp_init_config (u_int half_life, u_int reuse,
+                        u_int suppress, u_int t_hold)
+{
+  int i;
+  double max_ratio, max_ratio1, max_ratio2;
+
+  dc->half_life = half_life ? half_life : DEFAULT_HALF_LIFE;
+  dc->reuse     = reuse     ? reuse     : DEFAULT_REUSE;
+  dc->suppress  = suppress  ? suppress  : DEFAULT_SUPPRESS;
+  dc->t_hold    = t_hold    ? t_hold    : 4 * dc->half_life;
+
+  /* Initialize system-wide params */
+  dc->delta_t = DELTA_T;
+  dc->delta_reuse = DELTA_REUSE;
+  dc->default_penalty = DEFAULT_PENALTY;
+  dc->reuse_index_array_size = REUSE_ARRAY_SIZE;
+
+  /* ceiling is the maximum penalty a route may attain */
+  /* ceiling = reuse * 2^(T-hold/half-life) */
+  dc->ceiling = (int)
+    (dc->reuse * (pow (2, (double) dc->t_hold / dc->half_life)));
+
+  /* Decay-array computations */
+  /* decay_array_size = decay memory/time granularity */
+  dc->decay_array_size = ceil ((double) dc->t_hold / dc->delta_t);
+  dc->decay_array = malloc (sizeof (double) * (dc->decay_array_size));
+
+  /* Each i-th element is per tick delay raised to the i-th power */
+  dc->decay_array[0] = 1.0;
+  dc->decay_array[1] = exp ((1.0 / (dc->half_life / dc->delta_t)) * log (0.5));
+  for (i = 2; i < dc->decay_array_size; i++)
+    dc->decay_array[i] = dc->decay_array[i - 1] * dc->decay_array[1];
+
+  /* Reuse-list computations (reuse queue head array ?) */
+  dc->reuse_list_size = ceil ((double) dc->t_hold / dc->delta_reuse) + 1;
+  if (dc->reuse_list_size == 0 || dc->reuse_list_size > REUSE_LIST_SIZE)
+    dc->reuse_list_size = REUSE_LIST_SIZE;
+  dc->reuse_list_array = (struct ospf6_damp_info **)
+    malloc (dc->reuse_list_size * sizeof (struct ospf6_reuse_list *));
+  memset (dc->reuse_list_array, 0x00,
+          dc->reuse_list_size * sizeof (struct ospf6_reuse_list *));
+
+  /* Reuse-array computations */
+  dc->reuse_index_array = malloc (sizeof (int) * dc->reuse_index_array_size);
+
+  /*
+   * This is the maximum ratio between the current value of the penalty and
+   * the reuse value which can be indexed by the reuse array. It will be 
+   * limited by the ceiling or by the amount of time that the reuse list 
+   * covers 
+   */
+  max_ratio1 = (double) dc->ceiling / dc->reuse;
+  max_ratio2 = exp ((double) dc->t_hold / dc->half_life) * log10 (2.0);
+  max_ratio = (max_ratio2 != 0 && max_ratio2 < max_ratio1 ?
+               max_ratio2 : max_ratio1);
+
+  /*
+   * reuse array is just an estimator and we need something
+   * to use the full array 
+   */
+  dc->scale_factor = (double) dc->reuse_index_array_size / (max_ratio - 1);
+
+  for (i = 0; i < dc->reuse_index_array_size; i++)
+    {
+      dc->reuse_index_array[i] = (int)
+        (((double) dc->half_life / dc->delta_reuse) *
+         log10 (1.0 / (dc->reuse * (1.0 + ((double) i / dc->scale_factor))))
+         / log10 (0.5));
+    }
+
+  dc->enabled = ON;
+}
+
+static double
+ospf6_damp_decay (time_t tdiff)
+{
+  int index = tdiff / dc->delta_t;
+
+  if (index >= dc->decay_array_size)
+    return 0;
+
+  return dc->decay_array[index];
+}
+
+static int
+ospf6_damp_reuse_index (int penalty)
+{
+  int index;
+
+  index = (int) (((double) penalty / dc->reuse - 1.0) * dc->scale_factor);
+
+  if (index >= dc->reuse_index_array_size)
+    index = dc->reuse_index_array_size - 1;
+
+  return (dc->reuse_index_array[index] - dc->reuse_index_array[0]);
+}
+
+static int
+ospf6_reuse_list_lookup (struct ospf6_damp_info *di)
+{
+  struct ospf6_damp_info *info;
+
+  for (info = dc->reuse_list_array[di->index]; info; info = info->next)
+    {
+      if (info == di)
+        return 1;
+    }
+  return 0;
+}
+
+static void
+ospf6_reuse_list_remove (struct ospf6_damp_info *di)
+{
+  if (di->prev)
+    di->prev->next = di->next;
+  else
+    dc->reuse_list_array[di->index] = di->next;
+  if (di->next)
+    di->next->prev = di->prev;
+
+  di->index = -1;
+  di->prev = NULL;
+  di->next = NULL;
+}
+
+static void
+ospf6_reuse_list_add (struct ospf6_damp_info *di)
+{
+  /* set the index of reuse-array */
+  di->index = (reuse_array_offset + (ospf6_damp_reuse_index (di->penalty)))
+              % dc->reuse_list_size;
+
+  /* insert to the head of the reuse list */
+  di->next = dc->reuse_list_array[di->index];
+  if (di->next)
+    di->next->prev = di;
+  di->prev = NULL;
+  dc->reuse_list_array[di->index] = di;
+}
+
+/* When we quit damping for a target, we should execute proper event
+   which have been postponed during damping */
+static void
+ospf6_damp_stop (struct ospf6_damp_info *di)
+{
+  time_t t_now;
+  char namebuf[64];
+  struct timeval now;
+
+  if (IS_OSPF6_DEBUG_DAMP)
+    {
+      t_now = time (NULL);
+      prefix2str (&di->name, namebuf, sizeof (namebuf));
+      gettimeofday (&now, NULL);
+      zlog_info ("DAMP: %lu.%06lu stop damping: %ld: type: %d, name: %s",
+                 now.tv_sec, now.tv_usec,
+                 t_now, di->type, namebuf);
+    }
+
+  /* set flag indicates that we're damping this target */
+  di->damping = OFF;
+
+  /* if the target's current status differ from that it should be,
+     execute the proper event to repair his status */
+  if (di->target_status != di->event_type)
+    {
+      (*(di->event)) (di->target);
+      di->target_status = di->event_type;
+
+      di->event = NULL;
+      di->event_type = event_none;
+    }
+}
+
+/* ospf6_reuse_timer is called every DELTA_REUSE seconds.
+   Each route in the current reuse-list is evaluated
+   and is used or requeued */
+int
+ospf6_damp_reuse_timer (struct thread *t)
+{
+  struct ospf6_damp_info *di, *next;
+  time_t t_now, t_diff;
+  char namebuf[64];
+  struct timeval now;
+
+  /* Restart the reuse timer */
+  ospf6_reuse_thread =
+    thread_add_timer (master, ospf6_damp_reuse_timer, NULL, dc->delta_reuse);
+
+  t_now = time (NULL);
+
+  /* get the damp info list head */
+  di = dc->reuse_list_array[reuse_array_offset];
+  dc->reuse_list_array[reuse_array_offset] = NULL;
+
+  /* rotate the circular reuse list head array */
+  reuse_array_offset = (reuse_array_offset + 1) % dc->reuse_list_size;
+
+  /* for each damp info */
+  while (di)
+    {
+      next = di->next;
+      di->next = NULL;
+
+      /* Update penalty */
+      t_diff = t_now - di->t_updated;
+      di->t_updated = t_now;
+      di->penalty = (int)
+        ((double) di->penalty * ospf6_damp_decay (t_diff));
+      /* configration of ceiling may be just changed */
+      if (di->penalty > dc->ceiling)
+        di->penalty = dc->ceiling;
+
+      if (IS_OSPF6_DEBUG_DAMP)
+        {
+          prefix2str (&di->name, namebuf, sizeof (namebuf));
+          gettimeofday (&now, NULL);
+          zlog_info ("DAMP: %lu.%06lu update penalty: type: %d, name: %s, penalty: %d",
+                     now.tv_sec, now.tv_usec,
+                     di->type, namebuf, di->penalty);
+        }
+
+      /* If the penalty becomes under reuse,
+         call real event that we have been postponed. */
+      if (di->penalty < dc->reuse && di->damping == ON)
+        ospf6_damp_stop (di);
+
+      /* If the penalty becomes less than the half of the
+         reuse value, this damp info will be freed from reuse-list,
+         by assuming that it is considered to be stable enough already,
+         and there's no need to maintain flapping history for this. */
+      if (di->penalty <= dc->reuse / 2)
+        {
+          ospf6_damp_delete (di->type, &di->name);
+          di = next;
+          continue;
+        }
+
+      /* re-insert to the reuse-list */
+      ospf6_reuse_list_add (di);
+
+      di = next;
+    }
+
+  return 0;
+}
+
+static void
+ospf6_damp_event (damp_event_t event_type,
+                  u_short type, struct prefix *name,
+                  int (*event) (void *), void *target)
+{
+  time_t t_now, t_diff;
+  struct ospf6_damp_info *di;
+  char namebuf[64];
+  struct timeval now;
+
+  if (dc->enabled == OFF)
+    {
+      (*event) (target);
+      return;
+    }
+
+  di = ospf6_damp_lookup (type, name);
+  if (! di)
+    di = ospf6_damp_create (type, name);
+
+  t_now = time (NULL);
+
+  di->event = event;
+  di->target = target;
+  di->event_type = event_type;
+
+  if (! ospf6_reuse_list_lookup (di))
+    di->t_start = t_now;
+  else
+    {
+      ospf6_reuse_list_remove (di);
+
+      t_diff = t_now - di->t_updated;
+      di->penalty = (int) (di->penalty * ospf6_damp_decay (t_diff));
+    }
+
+  /* penalty only on down event */
+  if (event_type == event_down)
+    {
+      di->flap++;
+      di->penalty += dc->default_penalty;
+    }
+
+  /* limit penalty up to ceiling */
+  if (di->penalty > dc->ceiling)
+    di->penalty = dc->ceiling;
+
+  if (IS_OSPF6_DEBUG_DAMP)
+    {
+      prefix2str (&di->name, namebuf, sizeof (namebuf));
+      gettimeofday (&now, NULL);
+      zlog_info ("DAMP: %lu.%06lu update penalty: type: %d, name: %s, penalty: %d",
+                 now.tv_sec, now.tv_usec,
+                 di->type, namebuf, di->penalty);
+    }
+
+  /* if penalty < reuse, stop damping here */
+  if (di->penalty < dc->reuse && di->damping == ON)
+    {
+      if (IS_OSPF6_DEBUG_DAMP)
+        {
+          prefix2str (&di->name, namebuf, sizeof (namebuf));
+          gettimeofday (&now, NULL);
+          zlog_info ("DAMP: %lu.%06lu stop damping: %ld: type: %d, name: %s",
+                     now.tv_sec, now.tv_usec,
+                     t_now, di->type, namebuf);
+        }
+      di->damping = OFF;
+    }
+
+  /* if event == up and if penalty >= suppress , start damping here */
+  if (di->event_type == event_up && di->penalty >= dc->suppress &&
+      di->damping == OFF)
+    {
+      if (IS_OSPF6_DEBUG_DAMP)
+        {
+          prefix2str (&di->name, namebuf, sizeof (namebuf));
+          gettimeofday (&now, NULL);
+          zlog_info ("DAMP: %lu.%06lu start damping: %ld: type: %d, name: %s",
+                     now.tv_sec, now.tv_usec,
+                     t_now, type, namebuf);
+        }
+      di->damping = ON;
+    }
+
+  /* execute event if we're not damping */
+  if (di->damping == OFF)
+    {
+      (*(di->event)) (di->target);
+      di->target_status = di->event_type;
+    }
+
+  /* if the penalty goes beyond suppress value, start damping */
+  if (di->penalty >= dc->suppress && di->damping == OFF)
+    {
+      if (IS_OSPF6_DEBUG_DAMP)
+        {
+          prefix2str (name, namebuf, sizeof (namebuf));
+          gettimeofday (&now, NULL);
+          zlog_info ("DAMP: %lu.%06lu start damping: %ld: type: %d, name: %s",
+                     now.tv_sec, now.tv_usec,
+                     t_now, type, namebuf);
+        }
+      di->damping = ON;
+    }
+
+  /* update last-updated-time field */
+  di->t_updated = t_now;
+
+  /* Insert it into the reuse list */
+  ospf6_reuse_list_add (di);
+}
+
+void
+ospf6_damp_event_up (u_short type, struct prefix *name,
+                     int (*event) (void *), void *target)
+{
+  struct timeval now;
+
+  gettimeofday (&now, NULL);
+  if (IS_OSPF6_DEBUG_DAMP)
+    zlog_info ("DAMP: Up   Event at %lu.%06lu", now.tv_sec, now.tv_usec);
+
+  ospf6_damp_event (event_up, type, name, event, target);
+}
+
+void
+ospf6_damp_event_down (u_short type, struct prefix *name,
+                       int (*event) (void *), void *target)
+{
+  struct timeval now;
+
+  gettimeofday (&now, NULL);
+  if (IS_OSPF6_DEBUG_DAMP)
+    zlog_info ("DAMP: Down Event at %lu.%06lu", now.tv_sec, now.tv_usec);
+
+  ospf6_damp_event (event_down, type, name, event, target);
+}
+
+int
+ospf6_damp_debug_thread (struct thread *thread)
+{
+  int i;
+  struct ospf6_damp_info *di;
+  char buf[256];
+  time_t t_now;
+  struct timeval now;
+
+  for (i = 0; i < dc->reuse_list_size; i++)
+    {
+      for (di = dc->reuse_list_array[i]; di; di = di->next)
+        {
+          t_now = time (NULL);
+          gettimeofday (&now, NULL);
+          prefix2str (&di->name, buf, sizeof (buf));
+          zlog_info ("DAMP: %lu.%06lu %c %-32s penalty %7u",
+                     now.tv_sec, now.tv_usec,
+                     (di->damping == ON ? 'D' : 'A'), buf,
+                     (u_int) (di->penalty *
+                              ospf6_damp_decay (t_now - di->t_updated)));
+        }
+    }
+  thread_add_timer (master, ospf6_damp_debug_thread, NULL, 1);
+  return 0;
+}
+
+DEFUN (show_ipv6_ospf6_route_flapping,
+       show_ipv6_ospf6_route_flapping_cmd,
+       "show ipv6 ospf6 route flapping",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR)
+{
+  int i;
+  struct ospf6_damp_info *di;
+  char buf[256];
+  time_t t_now;
+
+  t_now = time (NULL);
+  vty_out (vty, "%c %-32s %7s%s", ' ', "Prefix", "penalty", VTY_NEWLINE);
+
+  for (i = 0; i < dc->reuse_list_size; i++)
+    {
+      for (di = dc->reuse_list_array[i]; di; di = di->next)
+        {
+          prefix2str (&di->name, buf, sizeof (buf));
+          vty_out (vty, "%c %-32s %7u%s",
+                   (di->damping == ON ? 'D' : ' '), buf,
+                   (u_int) (di->penalty *
+                            ospf6_damp_decay (t_now - di->t_updated)),
+                   VTY_NEWLINE);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (flap_damping_route,
+       flap_damping_route_cmd,
+       "flap-damping route <0-4294967295> <0-4294967295> "
+                          "<0-4294967295> <0-4294967295>",
+       "enable flap dampening\n"
+       "enable route flap dampening\n"
+       "half-life in second\n"
+       "reuse value\n"
+       "suppress value\n"
+       "t-hold in second (maximum time that the target can be damped)\n"
+      )
+{
+  u_int half_life, reuse, suppress, t_hold;
+
+  if (argc)
+    {
+      half_life = (u_int) strtoul (argv[0], NULL, 10);
+      reuse     = (u_int) strtoul (argv[1], NULL, 10);
+      suppress  = (u_int) strtoul (argv[2], NULL, 10);
+      t_hold    = (u_int) strtoul (argv[3], NULL, 10);
+    }
+  else
+    {
+      half_life = (u_int) DEFAULT_HALF_LIFE;
+      reuse     = (u_int) DEFAULT_REUSE;
+      suppress  = (u_int) DEFAULT_SUPPRESS;
+      t_hold    = (u_int) DEFAULT_HALF_LIFE * 4;
+    }
+
+  if (reuse && suppress && reuse >= suppress)
+    {
+      vty_out (vty, "reuse value exceeded suppress value, failed%s\n",
+               VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  if (half_life && t_hold && half_life >= t_hold)
+    {
+      vty_out (vty, "half-life exceeded t-hold, failed%s\n", VTY_NEWLINE);
+      return CMD_SUCCESS;
+    }
+
+  ospf6_damp_init_config (half_life, reuse, suppress, t_hold);
+
+  if (ospf6_reuse_thread == NULL)
+    ospf6_reuse_thread =
+      thread_add_timer (master, ospf6_damp_reuse_timer, NULL, dc->delta_reuse);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ipv6_ospf6_damp_config,
+       show_ipv6_ospf6_camp_config_cmd,
+       "show ipv6 ospf6 damp config",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Flap-dampening information\n"
+       "shows dampening configuration\n"
+      )
+{
+  int i;
+
+  vty_out (vty, "%10s %10s %10s %10s%s",
+           "Half life", "Suppress", "Reuse", "T-hold",
+           VTY_NEWLINE);
+  vty_out (vty, "%10u %10u %10u %10u%s",
+           dc->half_life, dc->suppress, dc->reuse, dc->t_hold,
+           VTY_NEWLINE);
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  vty_out (vty, "Delta-t = %u%s", dc->delta_t, VTY_NEWLINE);
+  vty_out (vty, "Delta-Reuse = %u%s", dc->delta_reuse, VTY_NEWLINE);
+  vty_out (vty, "Default-Penalty = %u%s", dc->default_penalty, VTY_NEWLINE);
+  vty_out (vty, "Ceiling = %u%s", dc->ceiling, VTY_NEWLINE);
+  vty_out (vty, "ScaleFactor = %f%s", dc->scale_factor, VTY_NEWLINE);
+
+  vty_out (vty, "DecayArray(%d) =%s", dc->decay_array_size, VTY_NEWLINE);
+  for (i = 0; i < dc->decay_array_size; i++)
+    {
+      if (i % 10 == 0)
+        vty_out (vty, "  ");
+      vty_out (vty, " %f", dc->decay_array[i]);
+      if (i % 10 == 0)
+        vty_out (vty, "%s", VTY_NEWLINE);
+    }
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  vty_out (vty, "ReuseIndexArray(%d) =%s",
+           dc->reuse_index_array_size, VTY_NEWLINE);
+  for (i = 0; i < dc->reuse_index_array_size; i++)
+    {
+      if (i % 10 == 0)
+        vty_out (vty, "  ");
+      vty_out (vty, " %d", dc->reuse_index_array[i]);
+      if (i % 10 == 0)
+        vty_out (vty, "%s", VTY_NEWLINE);
+    }
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  return CMD_SUCCESS;
+}
+
+void
+ospf6_damp_config_write (struct vty *vty)
+{
+  if (dc->enabled == ON)
+    {
+      vty_out (vty, " flap-damping route %u %u %u %u%s",
+               dc->half_life, dc->reuse, dc->suppress, dc->t_hold,
+               VTY_NEWLINE);
+    }
+}
+
+DEFUN (debug_ospf6_damp,
+       debug_ospf6_damp_cmd,
+       "debug ospf6 damp",
+       DEBUG_STR
+       OSPF6_STR
+       "Flap-dampening information\n"
+      )
+{
+  ospf6_damp_debug = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_ospf6_damp,
+       no_debug_ospf6_damp_cmd,
+       "no debug ospf6 damp",
+       NO_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Flap-dampening information\n"
+      )
+{
+  ospf6_damp_debug = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_debug_ospf6_damp,
+       show_debug_ospf6_damp_cmd,
+       "show debugging ospf6 damp",
+       SHOW_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Flap-dampening information\n"
+      )
+{
+  vty_out (vty, "debugging ospf6 damp is ");
+  if (IS_OSPF6_DEBUG_DAMP)
+    vty_out (vty, "enabled.");
+  else
+    vty_out (vty, "disabled.");
+  vty_out (vty, "%s", VTY_NEWLINE);
+  return CMD_SUCCESS;
+}
+
+void
+ospf6_damp_init ()
+{
+  int i;
+  for (i = 0; i < OSPF6_DAMP_TYPE_MAX; i++)
+    damp_info_table[i] = route_table_init ();
+
+  install_element (VIEW_NODE, &show_ipv6_ospf6_route_flapping_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_route_flapping_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_camp_config_cmd);
+  install_element (OSPF6_NODE, &flap_damping_route_cmd);
+
+  install_element (ENABLE_NODE, &show_debug_ospf6_damp_cmd);
+  install_element (CONFIG_NODE, &debug_ospf6_damp_cmd);
+  install_element (CONFIG_NODE, &no_debug_ospf6_damp_cmd);
+
+  thread_add_event (master, ospf6_damp_debug_thread, NULL, 0);
+}
+
+#endif /* HAVE_OSPF6_DAMP */
+
+
diff --git a/ospf6d/ospf6_damp.h b/ospf6d/ospf6_damp.h
new file mode 100644
index 0000000..19bdbc7
--- /dev/null
+++ b/ospf6d/ospf6_damp.h
@@ -0,0 +1,109 @@
+/*
+ * OSPF flap dampening by Manav Bhatia
+ * Copyright (C) 2002 
+ * 
+ * This file is part of GNU Zebra.
+ * 
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ * 
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+/*
+ * Flap Damping (target e.g. link/route)
+ */
+
+#define HAVE_OSPF6_DAMP
+
+typedef enum
+{
+  OFF,
+  ON,
+} onoff_t;
+
+typedef enum
+{
+  event_none,
+  event_up,
+  event_down,
+} damp_event_t;
+
+/* Structure maintained per target basis */
+struct ospf6_damp_info
+{
+  /* identifier to decide which target */
+  u_short type;
+  struct prefix name;
+
+  /* do we damping this info */
+  onoff_t damping;
+
+  u_int penalty;
+  u_int flap;
+  time_t t_start;   /* First flap (down event) time */
+  time_t t_updated; /* Last time the penalty was updated */
+
+  /* index and double-link for reuse list */
+  int                    index;
+  struct ospf6_damp_info *next;
+  struct ospf6_damp_info *prev;
+
+  /* the last event that we are avoiding */
+  int (*event) (void *target);
+  void *target;
+  damp_event_t event_type;
+  damp_event_t target_status;
+};
+
+#define OSPF6_DAMP_TYPE_ROUTE      0
+#define OSPF6_DAMP_TYPE_MAX        1
+
+/* Global Configuration Parameters */
+struct ospf6_damp_config
+{
+  /* is damping enabled ? */
+  onoff_t enabled;
+
+  /* configurable parameters */
+  u_int half_life;
+  u_int suppress;
+  u_int reuse;
+  u_int t_hold;                 /* Maximum hold down time */
+
+  /* Non configurable parameters */
+  u_int   delta_t;
+  u_int   delta_reuse;
+  u_int   default_penalty;
+  u_int   ceiling;              /* Max value a penalty can attain */
+  double  scale_factor;
+
+  int     decay_array_size;     /* Calculated using config parameters */
+  double *decay_array;          /* Storage for decay values */
+
+  int  reuse_index_array_size;  /* Size of reuse index array */
+  int *reuse_index_array;
+
+  int  reuse_list_size;         /* Number of reuse lists */
+  struct ospf6_damp_info **reuse_list_array;
+};
+
+int ospf6_damp_reuse_timer (struct thread *);
+void ospf6_damp_event_up   (u_short type, struct prefix *name,
+                           int (*exec_up)   (void *), void *target);
+void ospf6_damp_event_down (u_short type, struct prefix *name,
+                           int (*exec_down) (void *), void *target);
+
+void ospf6_damp_config_write (struct vty *);
+void ospf6_damp_init ();
+
diff --git a/ospf6d/ospf6_dbex.c b/ospf6d/ospf6_dbex.c
new file mode 100644
index 0000000..b10d9ae
--- /dev/null
+++ b/ospf6d/ospf6_dbex.c
@@ -0,0 +1,704 @@
+/*
+ * 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
new file mode 100644
index 0000000..fbb7dc5
--- /dev/null
+++ b/ospf6d/ospf6_dbex.h
@@ -0,0 +1,59 @@
+/*
+ * 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
new file mode 100644
index 0000000..e950ec8
--- /dev/null
+++ b/ospf6d/ospf6_dump.c
@@ -0,0 +1,314 @@
+/*
+ * 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,
+  ""
+};
+
+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
new file mode 100644
index 0000000..18a6e46
--- /dev/null
+++ b/ospf6d/ospf6_dump.h
@@ -0,0 +1,95 @@
+/*
+ * 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
new file mode 100644
index 0000000..fc9e185
--- /dev/null
+++ b/ospf6d/ospf6_hook.c
@@ -0,0 +1,174 @@
+/*
+ * 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
new file mode 100644
index 0000000..fa882a5
--- /dev/null
+++ b/ospf6d/ospf6_hook.h
@@ -0,0 +1,87 @@
+/*
+ * 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
new file mode 100644
index 0000000..d394f21
--- /dev/null
+++ b/ospf6d/ospf6_interface.c
@@ -0,0 +1,1028 @@
+/*
+ * 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"
+
+#include "if.h"
+#include "log.h"
+#include "command.h"
+
+#include "ospf6_lsdb.h"
+
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_interface.h"
+
+char *ospf6_interface_state_string[] =
+{
+  "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 *))
+{
+  listnode node;
+  struct ospf6_neighbor *nei;
+
+  for (node = listhead (o6i->neighbor_list); node; nextnode (node))
+    {
+      nei = (struct ospf6_neighbor *) getdata (node);
+      (*func) (arg, val, nei);
+    }
+}
+
+static int
+ospf6_interface_maxage_remover (struct thread *t)
+{
+  int count;
+  struct ospf6_interface *o6i = (struct ospf6_interface *) THREAD_ARG (t);
+
+  o6i->maxage_remover = (struct thread *) 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;
+}
+
+void
+ospf6_interface_schedule_maxage_remover (void *arg, int val, void *obj)
+{
+  struct ospf6_interface *o6i = (struct ospf6_interface *) obj;
+
+  if (o6i->maxage_remover != NULL)
+    return;
+
+  o6i->maxage_remover =
+    thread_add_event (master, ospf6_interface_maxage_remover, o6i, 0);
+}
+
+/* Create new ospf6 interface structure */
+struct ospf6_interface *
+ospf6_interface_create (struct interface *ifp)
+{
+  struct ospf6_interface *o6i;
+
+  o6i = (struct ospf6_interface *)
+    XMALLOC (MTYPE_OSPF6_IF, sizeof (struct ospf6_interface));
+
+  if (o6i)
+    memset (o6i, 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 ();
+
+  o6i->ack_list = ospf6_lsdb_create ();
+  o6i->lsdb = ospf6_lsdb_create ();
+
+  o6i->transdelay = 1;
+  o6i->priority = 1;
+  o6i->hello_interval = 10;
+  o6i->dead_interval = 40;
+  o6i->rxmt_interval = 5;
+  o6i->cost = 1;
+  o6i->ifmtu = 1280;
+
+  o6i->foreach_nei = ospf6_interface_foreach_neighbor;
+
+  /* link both */
+  o6i->interface = ifp;
+  ifp->info = o6i;
+
+  CALL_ADD_HOOK (&interface_hook, o6i);
+
+  /* Get the interface's link-local if any */
+  ospf6_interface_address_update(ifp);
+
+  return o6i;
+}
+
+void
+ospf6_interface_delete (struct ospf6_interface *o6i)
+{
+  listnode n;
+  struct ospf6_neighbor *o6n;
+
+  CALL_REMOVE_HOOK (&interface_hook, o6i);
+
+  for (n = listhead (o6i->neighbor_list); n; nextnode (n))
+    {
+      o6n = (struct ospf6_neighbor *) getdata (n);
+      ospf6_neighbor_delete (o6n);
+    }
+  list_delete (o6i->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;
+    }
+
+  ospf6_lsdb_delete (o6i->ack_list);
+  ospf6_lsdb_remove_all (o6i->lsdb);
+  ospf6_lsdb_delete (o6i->lsdb);
+
+  /* cut link */
+  o6i->interface->info = NULL;
+
+  /* plist_name */
+  if (o6i->plist_name)
+    XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name);
+
+  XFREE (MTYPE_OSPF6_IF, o6i);
+}
+
+static struct in6_addr *
+ospf6_interface_update_linklocal_address (struct interface *ifp)
+{
+  listnode n;
+  struct connected *c;
+  struct in6_addr *l = (struct in6_addr *) NULL;
+
+  /* for each connected address */
+  for (n = listhead (ifp->connected); n; nextnode (n))
+    {
+      c = (struct connected *) getdata (n);
+
+      /* if family not AF_INET6, ignore */
+      if (c->address->family != AF_INET6)
+        continue;
+
+      /* linklocal scope check */
+      if (IN6_IS_ADDR_LINKLOCAL (&c->address->u.prefix6))
+        l = &c->address->u.prefix6;
+    }
+  return l;
+}
+
+void
+ospf6_interface_if_add (struct interface *ifp)
+{
+  struct ospf6_interface *o6i;
+
+  o6i = (struct ospf6_interface *) ifp->info;
+  if (!o6i)
+    return;
+
+  o6i->if_id = ifp->ifindex;
+
+  ospf6_interface_address_update (ifp);
+
+  /* interface start */
+  if (o6i->area)
+    thread_add_event (master, interface_up, o6i, 0);
+}
+
+void
+ospf6_interface_if_del (struct interface *ifp)
+{
+  struct ospf6_interface *o6i;
+
+  o6i = (struct ospf6_interface *) ifp->info;
+  if (!o6i)
+    return;
+
+  /* interface stop */
+  if (o6i->area)
+    thread_execute (master, interface_down, o6i, 0);
+
+  listnode_delete (o6i->area->if_list, o6i);
+  o6i->area = (struct ospf6_area *) NULL;
+
+  /* cut link */
+  o6i->interface = NULL;
+  ifp->info = NULL;
+
+  ospf6_interface_delete (o6i);
+}
+
+void
+ospf6_interface_state_update (struct interface *ifp)
+{
+  struct ospf6_interface *o6i;
+
+  o6i = (struct ospf6_interface *) ifp->info;
+  if (! o6i)
+    return;
+  if (! o6i->area)
+    return;
+
+  if (if_is_up (ifp))
+    thread_add_event (master, interface_up, o6i, 0);
+  else
+    thread_add_event (master, interface_down, o6i, 0);
+
+  return;
+}
+
+void
+ospf6_interface_address_update (struct interface *ifp)
+{
+  struct ospf6_interface *o6i;
+
+  o6i = (struct ospf6_interface *) ifp->info;
+  if (! o6i)
+    return;
+
+  /* reset linklocal pointer */
+  o6i->lladdr = ospf6_interface_update_linklocal_address (ifp);
+
+  /* if area is null, can't make link-lsa */
+  if (! o6i->area)
+    return;
+
+  /* create new Link-LSA */
+  CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
+
+  CALL_CHANGE_HOOK (&interface_hook, o6i);
+}
+
+struct ospf6_interface *
+ospf6_interface_lookup_by_index (int ifindex)
+{
+  struct ospf6_interface *o6i;
+  struct interface *ifp;
+
+  ifp = if_lookup_by_index (ifindex);
+
+  if (! ifp)
+    return (struct ospf6_interface *) NULL;
+
+  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))
+    {
+      o6n = (struct ospf6_neighbor *) getdata (n);
+      if (o6n->state == state)
+        count++;
+    }
+  return count;
+}
+
+int
+ospf6_interface_count_full_neighbor (struct ospf6_interface *o6i)
+{
+  listnode n;
+  struct ospf6_neighbor *o6n;
+  int count = 0;
+
+  for (n = listhead (o6i->neighbor_list); n; nextnode (n))
+    {
+      o6n = (struct ospf6_neighbor *) getdata (n);
+      if (o6n->state == NBS_FULL)
+        count++;
+    }
+  return count;
+}
+
+int
+ospf6_interface_is_enabled (unsigned int ifindex)
+{
+  struct ospf6_interface *o6i;
+
+  o6i = ospf6_interface_lookup_by_index (ifindex);
+  if (! o6i)
+    return 0;
+
+  if (! o6i->area)
+    return 0;
+
+  if (o6i->state <= IFS_DOWN)
+    return 0;
+
+  return 1;
+}
+
+void
+ospf6_interface_delayed_ack_add (struct ospf6_lsa *lsa,
+                                 struct ospf6_interface *o6i)
+{
+  struct ospf6_lsa *summary;
+  summary = ospf6_lsa_summary_create (lsa->header);
+  ospf6_lsdb_add (summary, o6i->ack_list);
+}
+
+void
+ospf6_interface_delayed_ack_remove (struct ospf6_lsa *lsa,
+                                    struct ospf6_interface *o6i)
+{
+  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);
+}
+
+/* show specified interface structure */
+int
+ospf6_interface_show (struct vty *vty, struct interface *iface)
+{
+  struct ospf6_interface *ospf6_interface;
+  struct connected *c;
+  struct prefix *p;
+  listnode i;
+  char strbuf[64], dr[32], bdr[32];
+  char *updown[3] = {"down", "up", NULL};
+  char *type;
+
+  /* check physical interface type */
+  if (if_is_loopback (iface))
+    type = "LOOPBACK";
+  else if (if_is_broadcast (iface))
+    type = "BROADCAST";
+  else if (if_is_pointopoint (iface))
+    type = "POINTOPOINT";
+  else
+    type = "UNKNOWN";
+
+  vty_out (vty, "%s is %s, type %s%s",
+           iface->name, updown[if_is_up (iface)], type,
+	   VTY_NEWLINE);
+  vty_out (vty, "  Interface ID: %d%s", iface->ifindex, VTY_NEWLINE);
+
+  if (iface->info == NULL)
+    {
+      vty_out (vty, "   OSPF not enabled on this interface%s", VTY_NEWLINE);
+      return 0;
+    }
+  else
+    ospf6_interface = (struct ospf6_interface *) iface->info;
+
+  vty_out (vty, "  Internet Address:%s", VTY_NEWLINE);
+  for (i = listhead (iface->connected); i; nextnode (i))
+    {
+      c = (struct connected *)getdata (i);
+      p = c->address;
+      prefix2str (p, strbuf, sizeof (strbuf));
+      switch (p->family)
+        {
+        case AF_INET:
+          vty_out (vty, "   inet : %s%s", strbuf,
+		   VTY_NEWLINE);
+          break;
+        case AF_INET6:
+          vty_out (vty, "   inet6: %s%s", strbuf,
+		   VTY_NEWLINE);
+          break;
+        default:
+          vty_out (vty, "   ???  : %s%s", strbuf,
+		   VTY_NEWLINE);
+          break;
+        }
+    }
+
+  if (ospf6_interface->area)
+    {
+      inet_ntop (AF_INET, &ospf6_interface->area->ospf6->router_id,
+                 strbuf, sizeof (strbuf));
+      vty_out (vty, "  Instance ID %d, Router ID %s%s",
+	       ospf6_interface->instance_id, strbuf,
+	       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,
+	   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,
+	   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);
+
+  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;
+
+  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;
+
+  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);
+
+  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);
+}
+
+/* show interface */
+DEFUN (show_ipv6_ospf6_interface,
+       show_ipv6_ospf6_interface_ifname_cmd,
+       "show ipv6 ospf6 interface IFNAME",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       INTERFACE_STR
+       IFNAME_STR
+       )
+{
+  struct interface *ifp;
+  listnode i;
+
+  if (argc)
+    {
+      ifp = if_lookup_by_name (argv[0]);
+      if (!ifp)
+        {
+          vty_out (vty, "No such Interface: %s%s", argv[0],
+		   VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+      ospf6_interface_show (vty, ifp);
+    }
+  else
+    {
+      for (i = listhead (iflist); i; nextnode (i))
+        {
+          ifp = (struct interface *)getdata (i);
+          ospf6_interface_show (vty, ifp);
+        }
+    }
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_ipv6_ospf6_interface,
+       show_ipv6_ospf6_interface_cmd,
+       "show ipv6 ospf6 interface",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       INTERFACE_STR
+       )
+
+/* interface variable set command */
+DEFUN (ipv6_ospf6_cost,
+       ipv6_ospf6_cost_cmd,
+       "ipv6 ospf6 cost COST",
+       IP6_STR
+       OSPF6_STR
+       "Interface cost\n"
+       "<1-65535> Cost\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 (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);
+
+  return CMD_SUCCESS;
+}
+
+/* interface variable set command */
+DEFUN (ipv6_ospf6_hellointerval,
+       ipv6_ospf6_hellointerval_cmd,
+       "ipv6 ospf6 hello-interval HELLO_INTERVAL",
+       IP6_STR
+       OSPF6_STR
+       "Time between HELLO packets\n"
+       SECONDS_STR
+       )
+{
+  struct ospf6_interface *ospf6_interface;
+  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);
+  return CMD_SUCCESS;
+}
+
+/* interface variable set command */
+DEFUN (ipv6_ospf6_deadinterval,
+       ipv6_ospf6_deadinterval_cmd,
+       "ipv6 ospf6 dead-interval ROUTER_DEAD_INTERVAL",
+       IP6_STR
+       OSPF6_STR
+       "Interval after which a neighbor is declared dead\n"
+       SECONDS_STR
+       )
+{
+  struct ospf6_interface *ospf6_interface;
+  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);
+  return CMD_SUCCESS;
+}
+
+/* interface variable set command */
+DEFUN (ipv6_ospf6_transmitdelay,
+       ipv6_ospf6_transmitdelay_cmd,
+       "ipv6 ospf6 transmit-delay TRANSMITDELAY",
+       IP6_STR
+       OSPF6_STR
+       "Link state transmit delay\n"
+       SECONDS_STR
+       )
+{
+  struct ospf6_interface *ospf6_interface;
+  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);
+  return CMD_SUCCESS;
+}
+
+/* interface variable set command */
+DEFUN (ipv6_ospf6_retransmitinterval,
+       ipv6_ospf6_retransmitinterval_cmd,
+       "ipv6 ospf6 retransmit-interval RXMTINTERVAL",
+       IP6_STR
+       OSPF6_STR
+       "Time between retransmitting lost link state advertisements\n"
+       SECONDS_STR
+       )
+{
+  struct ospf6_interface *ospf6_interface;
+  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);
+  return CMD_SUCCESS;
+}
+
+/* interface variable set command */
+DEFUN (ipv6_ospf6_priority,
+       ipv6_ospf6_priority_cmd,
+       "ipv6 ospf6 priority PRIORITY",
+       IP6_STR
+       OSPF6_STR
+       "Router priority\n"
+       "<0-255> Priority\n"
+       )
+{
+  struct ospf6_interface *ospf6_interface;
+  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);
+
+  if (ospf6_interface->area)
+    ifs_change (dr_election (ospf6_interface), "Priority reconfigured",
+                ospf6_interface);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_ospf6_instance,
+       ipv6_ospf6_instance_cmd,
+       "ipv6 ospf6 instance-id INSTANCE",
+       IP6_STR
+       OSPF6_STR
+       "Instance ID\n"
+       "<0-255> Instance ID\n"
+       )
+{
+  struct ospf6_interface *ospf6_interface;
+  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->instance_id = strtol (argv[0], NULL, 10);
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_ospf6_passive,
+       ipv6_ospf6_passive_cmd,
+       "ipv6 ospf6 passive",
+       IP6_STR
+       OSPF6_STR
+       "passive interface: No Adjacency will be formed on this I/F\n"
+       )
+{
+  struct ospf6_interface *o6i;
+  struct interface *ifp;
+  listnode node;
+  struct ospf6_neighbor *o6n;
+
+  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;
+    }
+
+  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);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_ospf6_passive,
+       no_ipv6_ospf6_passive_cmd,
+       "no ipv6 ospf6 passive",
+       NO_STR
+       IP6_STR
+       OSPF6_STR
+       "passive interface: No Adjacency will be formed on this I/F\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_PASSIVE);
+  if (o6i->thread_send_hello == NULL)
+    thread_add_event (master, ospf6_send_hello, o6i, 0);
+
+  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);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_ospf6_advertise_prefix_list,
+       ipv6_ospf6_advertise_prefix_list_cmd,
+       "ipv6 ospf6 advertise prefix-list WORD",
+       IP6_STR
+       OSPF6_STR
+       "Advertising options\n"
+       "Filter prefix using prefix-list\n"
+       "Prefix list name\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 (o6i->plist_name)
+    XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name);
+  o6i->plist_name = XSTRDUP (MTYPE_PREFIX_LIST_STR, argv[0]);
+
+  /* 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_prefix_list,
+       no_ipv6_ospf6_advertise_prefix_list_cmd,
+       "no ipv6 ospf6 advertise prefix-list",
+       NO_STR
+       IP6_STR
+       OSPF6_STR
+       "Advertising options\n"
+       "Filter prefix using prefix-list\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 (o6i->plist_name)
+    {
+      XFREE (MTYPE_PREFIX_LIST_STR, o6i->plist_name);
+      o6i->plist_name = NULL;
+    }
+
+  /* execute LSA hooks */
+  CALL_FOREACH_LSA_HOOK (hook_interface, hook_change, o6i);
+
+  CALL_CHANGE_HOOK (&interface_hook, o6i);
+
+  return CMD_SUCCESS;
+}
+
+int
+ospf6_interface_config_write (struct vty *vty)
+{
+  listnode i;
+  struct ospf6_interface *o6i;
+  struct interface *ifp;
+
+  for (i = listhead (iflist); i; nextnode (i))
+    {
+      ifp = (struct interface *) getdata (i);
+      o6i = (struct ospf6_interface *) ifp->info;
+      if (! o6i)
+        continue;
+
+      vty_out (vty, "interface %s%s",
+               o6i->interface->name, VTY_NEWLINE);
+      vty_out (vty, " ipv6 ospf6 cost %d%s",
+               o6i->cost, VTY_NEWLINE);
+      vty_out (vty, " ipv6 ospf6 hello-interval %d%s",
+               o6i->hello_interval, VTY_NEWLINE);
+      vty_out (vty, " ipv6 ospf6 dead-interval %d%s",
+               o6i->dead_interval, VTY_NEWLINE);
+      vty_out (vty, " ipv6 ospf6 retransmit-interval %d%s",
+               o6i->rxmt_interval, VTY_NEWLINE);
+      vty_out (vty, " ipv6 ospf6 priority %d%s",
+               o6i->priority, VTY_NEWLINE);
+      vty_out (vty, " ipv6 ospf6 transmit-delay %d%s",
+               o6i->transdelay, VTY_NEWLINE);
+      vty_out (vty, " ipv6 ospf6 instance-id %d%s",
+               o6i->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)
+        vty_out (vty, " ipv6 ospf6 advertise prefix-list %s%s",
+                 o6i->plist_name, VTY_NEWLINE);
+
+      if (CHECK_FLAG (o6i->flag, OSPF6_INTERFACE_FLAG_PASSIVE))
+        vty_out (vty, " ipv6 ospf6 passive%s", VTY_NEWLINE);
+
+      vty_out (vty, "!%s", VTY_NEWLINE);
+    }
+  return 0;
+}
+
+struct cmd_node interface_node =
+{
+  INTERFACE_NODE,
+  "%s(config-if)# ",
+};
+
+void
+ospf6_interface_init ()
+{
+  /* Install interface node. */
+  install_node (&interface_node, ospf6_interface_config_write);
+
+  install_element (VIEW_NODE, &show_ipv6_ospf6_interface_cmd);
+  install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_cmd);
+
+  install_default (INTERFACE_NODE);
+  install_element (INTERFACE_NODE, &interface_desc_cmd);
+  install_element (INTERFACE_NODE, &no_interface_desc_cmd);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_cost_cmd);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_deadinterval_cmd);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_hellointerval_cmd);
+  install_element (INTERFACE_NODE, &ipv6_ospf6_priority_cmd);
+  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);
+}
+
+
diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h
new file mode 100644
index 0000000..a96ef25
--- /dev/null
+++ b/ospf6d/ospf6_interface.h
@@ -0,0 +1,153 @@
+/*
+ * 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_INTERFACE_H
+#define OSPF6_INTERFACE_H
+
+#include "ospf6_message.h"
+
+/* This file defines interface data structure. */
+
+struct ospf6_interface
+{
+  /* IF info from zebra */
+  struct interface *interface;
+
+  /* back pointer */
+  struct ospf6_area *area;
+
+  /* list of ospf6 neighbor */
+  list neighbor_list;
+
+  /* linklocal address of this I/F */
+  struct in6_addr *lladdr;
+
+  /* Interface ID; same as ifindex */
+  u_int32_t if_id;
+
+  /* ospf6 instance id */
+  u_char instance_id;
+
+  /* I/F transmission delay */
+  u_int32_t transdelay;
+
+  /* Router Priority */
+  u_char priority;
+
+  /* Timers */
+  u_int16_t hello_interval;
+  u_int16_t dead_interval;
+  u_int32_t rxmt_interval;
+
+  /* Cost */
+  u_int32_t cost;
+
+  /* I/F MTU */
+  u_int32_t ifmtu;
+
+  /* Interface State */
+  u_char state;
+
+  /* OSPF6 Interface flag */
+  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;
+
+  /* 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_message_stat message_stat[OSPF6_MESSAGE_TYPE_MAX];
+
+  void (*foreach_nei) (struct ospf6_interface *, void *, int,
+                       void (*func) (void *, int, void *));
+
+  struct thread *maxage_remover;
+
+  /* route-map to filter connected prefix */
+  char *plist_name;
+};
+
+extern char *ospf6_interface_state_string[];
+
+#define OSPF6_INTERFACE_FLAG_PASSIVE      0x01
+#define OSPF6_INTERFACE_FLAG_FORCE_PREFIX 0x02
+
+
+/* Function Prototypes */
+
+void
+ospf6_interface_schedule_maxage_remover (void *arg, int val, void *obj);
+
+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_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_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);
+
+#endif /* OSPF6_INTERFACE_H */
+
diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c
new file mode 100644
index 0000000..b9c9ebd
--- /dev/null
+++ b/ospf6d/ospf6_intra.c
@@ -0,0 +1,896 @@
+/*
+ * Copyright (C) 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 "ospf6d.h"
+
+static int intra_index;
+#define IS_OSPF6_DUMP_INTRA (ospf6_dump_is_on (intra_index))
+
+#define ADD    0
+#define REMOVE 1
+
+static void
+ospf6_intra_route_calculate (int type, struct ospf6_lsa *lsa,
+                             struct ospf6_route_req *topo_entry)
+{
+  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;
+
+  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);
+    }
+
+  intra_prefix = OSPF6_LSA_HEADER_END (lsa->header);
+
+  area = lsa->scope;
+  assert (area);
+
+  start = (char *) (intra_prefix + 1);
+  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))
+    {
+      memset (&request, 0, sizeof (request));
+
+      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);
+      else
+        assert (0);
+    }
+}
+
+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);
+    }
+  return 0;
+}
+
+void
+ospf6_intra_topology_add (void *data)
+{
+  struct ospf6_route_req *topo_entry = data;
+  struct ospf6_area *area;
+  struct ospf6_intra_area_prefix_lsa *iap;
+  struct ospf6_lsdb_node node;
+
+  area = ospf6_area_lookup (topo_entry->path.area_id, ospf6);
+  if (! area)
+    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_add (topo_entry, ospf6->topology_table);
+
+  for (ospf6_lsdb_type (&node, htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
+                        area->lsdb);
+       ! ospf6_lsdb_is_end (&node);
+       ospf6_lsdb_next (&node))
+    {
+      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 ("INTRA: 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 (ADD, node.lsa, topo_entry);
+    }
+}
+
+void
+ospf6_intra_topology_remove (void *data)
+{
+  struct ospf6_route_req *topo_entry = data;
+  struct ospf6_area *area;
+  struct ospf6_intra_area_prefix_lsa *iap;
+  struct ospf6_lsdb_node node;
+
+  area = ospf6_area_lookup (topo_entry->path.area_id, ospf6);
+  if (! area)
+    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);
+
+  for (ospf6_lsdb_type (&node, htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
+                        area->lsdb);
+       ! ospf6_lsdb_is_end (&node);
+       ospf6_lsdb_next (&node))
+    {
+      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);
+    }
+}
+
+
+/*****************************************/
+/* RFC2740 3.4.3.7 Intra-Area-Prefix-LSA */
+/*****************************************/
+
+#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;\
+    }
+
+#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;\
+    }
+
+
+int
+ospf6_lsa_intra_prefix_show (struct vty *vty, 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;
+  char *start, *end, *current;
+
+  assert (lsa->header);
+  iap_lsa = (struct ospf6_intra_area_prefix_lsa *) (lsa->header + 1);
+
+  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));
+
+  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);
+
+  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_intra_prefix_update_transit (char *ifname)
+{
+  char buffer [MAXLSASIZE];
+  u_int16_t size;
+  struct ospf6_lsa *old;
+  struct interface *ifp;
+  struct ospf6_interface *o6i;
+  struct ospf6_neighbor *o6n;
+
+  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;
+
+  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;
+    }
+
+  /* find previous LSA */
+  old = ospf6_lsdb_lookup (htons (OSPF6_LSA_TYPE_INTRA_PREFIX),
+                           htonl (o6i->if_id), ospf6->router_id,
+                           o6i->area);
+
+  /* Don't originate Network-LSA if not DR */
+  if (o6i->state != IFS_DR)
+    {
+      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);
+
+  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))
+    {
+      if (IS_LSA_MAXAGE (n.lsa))
+        continue;
+
+      if (IS_OSPF6_DUMP_PREFIX)
+        zlog_info ("Update Intra-Prefix (Transit): Checking %s",
+                    n.lsa->str);
+
+      /* Check status of the advertising router */
+      if (n.lsa->header->adv_router != o6i->area->ospf6->router_id)
+        {
+          o6n = ospf6_neighbor_lookup (n.lsa->header->adv_router, o6i);
+          if (! o6n)
+            {
+              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);
+              continue;
+            }
+        }
+
+      /* For each Prefix in this Link-LSA */
+      link = (struct ospf6_link_lsa *) (n.lsa->header + 1);
+      prefix_num = ntohl (link->llsa_prefix_num);
+
+      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 = (struct ospf6_prefix *) current;
+          ospf6_prefix_string (prefix, buf, sizeof (buf));
+
+          /* Check duplicate prefix */
+          dup = ospf6_prefix_lookup (adv_list, prefix);
+          if (dup)
+            {
+              if (IS_OSPF6_DUMP_PREFIX)
+                zlog_info ("  Duplicate %s", buf);
+              dup->prefix_options |= prefix->prefix_options;
+              continue;
+            }
+
+          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 --;
+        }
+    }
+
+  /* if no prefix to advertise, return */
+  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_NETWORK);
+  iap->refer_lsid = htonl (o6i->if_id);
+  iap->refer_advrtr = o6i->area->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 (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);
+}
+
+int
+ospf6_lsa_intra_prefix_hook_interface (void *interface)
+{
+  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);
+    }
+  return 0;
+}
+
+int
+ospf6_lsa_intra_prefix_hook_neighbor (void *neighbor)
+{
+  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);
+    }
+  return 0;
+}
+
+int
+ospf6_intra_prefix_link_database_hook (void *new)
+{
+  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;
+  u_int32_t id;
+
+  id = ntohl (lsa->header->id);
+  if (id)
+    {
+      o6i = ospf6_interface_lookup_by_index (id);
+      if (o6i)
+        ospf6_lsa_intra_prefix_update_transit (o6i->interface->name);
+      else
+        ospf6_lsa_premature_aging (lsa);
+    }
+  else
+    {
+      o6a = lsa->scope;
+      ospf6_lsa_intra_prefix_update_stub (o6a->area_id);
+    }
+
+  return 0;
+}
+
+void
+ospf6_intra_prefix_register ()
+{
+  struct ospf6_lsa_slot slot, *sp;
+  struct ospf6_hook hook;
+
+  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);
+
+  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);
+
+  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);
+
+  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);
+}
+
+void
+ospf6_intra_database_hook_intra_prefix (struct ospf6_lsa *old,
+                                        struct ospf6_lsa *new)
+{
+  if (old)
+    ospf6_intra_prefix_database_hook_remove (old);
+  if (new && ! IS_LSA_MAXAGE (new))
+    ospf6_intra_prefix_database_hook_add (new);
+}
+
+void
+ospf6_intra_database_hook_link (struct ospf6_lsa *old,
+                                struct ospf6_lsa *new)
+{
+  ospf6_intra_prefix_link_database_hook (new);
+  ospf6_spf_database_hook (old, new);
+}
+
+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;
+
+  intra_index = ospf6_dump_install ("intra-area", "Intra-area calculation\n");
+  ospf6_intra_prefix_register ();
+}
+
+
diff --git a/ospf6d/ospf6_intra.h b/ospf6d/ospf6_intra.h
new file mode 100644
index 0000000..4fb68e9
--- /dev/null
+++ b/ospf6d/ospf6_intra.h
@@ -0,0 +1,31 @@
+/*
+ * 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_INTRA_H
+#define OSPF6_INTRA_H
+
+void ospf6_intra_topology_add (void *);
+void ospf6_intra_topology_remove (void *);
+
+void ospf6_intra_init ();
+
+#endif /* OSPF6_INTRA_H */
+
diff --git a/ospf6d/ospf6_ism.c b/ospf6d/ospf6_ism.c
new file mode 100644
index 0000000..d13be12
--- /dev/null
+++ b/ospf6d/ospf6_ism.c
@@ -0,0 +1,519 @@
+/*
+ * 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 (nbpi->router_id > nbpj->router_id)
+                {
+                  list_delete_node (candidate_list, j);
+                  continue;
+                }
+              else if (nbpi->router_id < 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
new file mode 100644
index 0000000..12470d9
--- /dev/null
+++ b/ospf6d/ospf6_ism.h
@@ -0,0 +1,53 @@
+/*
+ * 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
new file mode 100644
index 0000000..8c17935
--- /dev/null
+++ b/ospf6d/ospf6_linklist.c
@@ -0,0 +1,193 @@
+
+#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
new file mode 100644
index 0000000..6d97899
--- /dev/null
+++ b/ospf6d/ospf6_linklist.h
@@ -0,0 +1,35 @@
+
+#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
new file mode 100644
index 0000000..b14979f
--- /dev/null
+++ b/ospf6d/ospf6_lsa.c
@@ -0,0 +1,1926 @@
+/*
+ * LSA function
+ * 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 other stuffs */
+#include "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 "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
+
+/* test LSAs identity */
+static int
+ospf6_lsa_issame (struct ospf6_lsa_header__ *lsh1,
+                  struct ospf6_lsa_header__ *lsh2)
+{
+  assert (lsh1 && lsh2);
+
+  if (lsh1->adv_router != lsh2->adv_router)
+    return 0;
+
+  if (lsh1->id != lsh2->id)
+    return 0;
+
+  if (lsh1->type != lsh2->type)
+    return 0;
+
+  return 1;
+}
+
+/* RFC2328: Section 13.2 */
+int
+ospf6_lsa_differ (struct ospf6_lsa *lsa1,
+                  struct ospf6_lsa *lsa2)
+{
+  int diff, cmplen;
+
+  if (! ospf6_lsa_issame (lsa1->header, lsa2->header))
+    return 1;
+
+  /* check Options field */
+  /* xxx */
+
+  ospf6_lsa_age_current (lsa1);
+  ospf6_lsa_age_current (lsa2);
+  if (ntohs (lsa1->header->age) == MAXAGE &&
+      ntohs (lsa2->header->age) != MAXAGE)
+    return 1;
+  if (ntohs (lsa1->header->age) != MAXAGE &&
+      ntohs (lsa2->header->age) == MAXAGE)
+    return 1;
+
+  /* compare body */
+  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;
+}
+
+int
+ospf6_lsa_match (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+                 struct ospf6_lsa_header *lsh)
+{
+  if (lsh->advrtr != adv_router)
+    return 0;
+
+  if (lsh->ls_id != id)
+    return 0;
+
+  if (lsh->type != type)
+    return 0;
+
+  return 1;
+}
+
+/* ospf6 age functions */
+/* calculate birth and set expire timer */
+static void
+ospf6_lsa_age_set (struct ospf6_lsa *lsa)
+{
+  struct timeval now;
+
+  assert (lsa && lsa->header);
+
+  if (gettimeofday (&now, (struct timezone *)NULL) < 0)
+    zlog_warn ("LSA: gettimeofday failed, may fail LSA AGEs: %s",
+               strerror (errno));
+
+  lsa->birth.tv_sec = now.tv_sec - ntohs (lsa->header->age);
+  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);
+  else
+    lsa->expire = NULL;
+  return;
+}
+
+/* this function calculates current age from its birth,
+   then update age field of LSA header. return value is current age */
+u_int16_t
+ospf6_lsa_age_current (struct ospf6_lsa *lsa)
+{
+  struct timeval now;
+  u_int32_t ulage;
+  u_int16_t age;
+
+  assert (lsa);
+  assert (lsa->header);
+
+  /* current time */
+  if (gettimeofday (&now, (struct timezone *)NULL) < 0)
+    zlog_warn ("LSA: gettimeofday failed, may fail 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;
+
+  lsa->header->age = htons (age);
+  return age;
+}
+
+/* update age field of LSA header with adding InfTransDelay */
+void
+ospf6_lsa_age_update_to_send (struct ospf6_lsa *lsa, u_int32_t transdelay)
+{
+  unsigned short age;
+
+  age = ospf6_lsa_age_current (lsa) + transdelay;
+  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 (lsa->expire)
+    thread_cancel (lsa->expire);
+  lsa->expire = (struct thread *) NULL;
+  if (lsa->refresh)
+    thread_cancel (lsa->refresh);
+  lsa->refresh = (struct thread *) NULL;
+
+  memset (&lsa->birth, 0, sizeof (struct timeval));
+  thread_execute (master, ospf6_lsa_expire, lsa, 0);
+}
+
+/* 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)
+{
+  signed long seqnuma, seqnumb;
+  u_int16_t cksuma, cksumb;
+  u_int16_t agea, ageb;
+
+  assert (a && a->header);
+  assert (b && b->header);
+  assert (ospf6_lsa_issame (a->header, b->header));
+
+  seqnuma = ((signed long) ntohl (a->header->seqnum))
+             - (signed long) INITIAL_SEQUENCE_NUMBER;
+  seqnumb = ((signed long) ntohl (b->header->seqnum))
+             - (signed long) INITIAL_SEQUENCE_NUMBER;
+
+  /* compare by sequence number */
+    /* xxx, care about LS sequence number wrapping */
+  recent_reason = "seqnum";
+  if (seqnuma > seqnumb)
+    return -1;
+  else if (seqnuma < seqnumb)
+    return 1;
+
+  /* Checksum */
+  cksuma = ntohs (a->header->checksum);
+  cksumb = ntohs (b->header->checksum);
+  if (cksuma > cksumb)
+    return -1;
+  if (cksuma < cksumb)
+    return 0;
+
+  /* Age check */
+  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)
+    return -1;
+  else if (agea != OSPF6_LSA_MAXAGE && ageb == OSPF6_LSA_MAXAGE)
+    return 1;
+
+  recent_reason = "age differ";
+  if (agea > ageb && agea - ageb >= OSPF6_LSA_MAXAGEDIFF)
+    return 1;
+  else if (agea < ageb && ageb - agea >= OSPF6_LSA_MAXAGEDIFF)
+    return -1;
+
+  /* neither recent */
+  recent_reason = "the same instance";
+  return 0;
+}
+
+int
+ospf6_lsa_lsd_num (struct ospf6_lsa_header *lsa_header)
+{
+  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;
+}
+
+void *
+ospf6_lsa_lsd_get (int index, struct ospf6_lsa_header *lsa_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;
+}
+
+/* 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)
+{
+  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;
+}
+
+void
+ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa)
+{
+  char adv_router[64], id[64], type[32];
+
+  assert (lsa);
+  assert (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);
+  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),
+           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;
+      }
+  }
+
+  vty_out (vty, "%sUnknown LSA type ...%s", VTY_NEWLINE, VTY_NEWLINE);
+}
+
+void
+ospf6_lsa_show_summary_header (struct vty *vty)
+{
+  vty_out (vty, "%-12s %-15s %-15s %4s %8s %4s %4s %-8s%s",
+           "Type", "LSId", "AdvRouter", "Age", "SeqNum",
+           "Cksm", "Len", "Duration", VTY_NEWLINE);
+}
+
+void
+ospf6_lsa_show_summary (struct vty *vty, struct ospf6_lsa *lsa)
+{
+  char adv_router[16], id[16], type[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));
+
+  vty_out (vty, "%-12s %-15s %-15s %4hu %8lx %04hx %4hu %8s%s",
+           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);
+}
+
+void
+ospf6_lsa_show_dump (struct vty *vty, struct ospf6_lsa *lsa)
+{
+  u_char *start, *end, *current;
+  char byte[4];
+
+  start = (char *) lsa->header;
+  end = (char *) lsa->header + ntohs (lsa->header->length);
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+  vty_out (vty, "%s:%s", lsa->str, VTY_NEWLINE);
+
+  for (current = start; current < end; current ++)
+    {
+      if ((current - start) % 16 == 0)
+        vty_out (vty, "%s        ", VTY_NEWLINE);
+      else if ((current - start) % 4 == 0)
+        vty_out (vty, " ");
+
+      snprintf (byte, sizeof (byte), "%02x", *current);
+      vty_out (vty, "%s", byte);
+    }
+
+  vty_out (vty, "%s%s", VTY_NEWLINE, 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,
+                      void *scope)
+{
+  struct ospf6_lsa *lsa;
+  signed long seqnum;
+
+  /* get current database copy */
+  lsa = ospf6_lsdb_lookup (type, id, adv_router, scope);
+
+  /* if current database copy not found, return InitialSequenceNumber */
+  if (!lsa)
+    seqnum = INITIAL_SEQUENCE_NUMBER;
+  else
+    seqnum = (signed long) ntohl (lsa->header->seqnum) + 1;
+
+  return (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)
+{
+  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[32];
+
+  /* whole length of this LSA */
+  lsa_size = ntohs (source->length);
+
+  /* allocate memory for this LSA */
+  lsa_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);
+
+  /* LSA information structure */
+  /* allocate memory */
+  lsa = (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 */
+
+  /* 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);
+
+  /* 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*/
+
+  return lsa;
+}
+
+struct ospf6_lsa *
+ospf6_lsa_summary_create (struct ospf6_lsa_header__ *source)
+{
+  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);
+
+  /* allocate memory for this LSA */
+  lsa_header = (struct ospf6_lsa_header *)
+    XMALLOC (MTYPE_OSPF6_LSA_SUMMARY, lsa_size);
+  memset (lsa_header, 0, lsa_size);
+
+  /* copy LSA from source */
+  memcpy (lsa_header, source, lsa_size);
+
+  /* LSA information structure */
+  /* allocate memory */
+  lsa = (struct ospf6_lsa *)
+          XMALLOC (MTYPE_OSPF6_LSA_SUMMARY, 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 */
+
+  /* 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);
+
+  /* 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*/
+
+  return lsa;
+}
+
+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;
+    }
+
+  /* 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;
+
+#ifdef DEBUG
+  if (IS_OSPF6_DUMP_LSA)
+      zlog_info ("Delete %s (%p/%p)", lsa->str, lsa, lsa->header);
+#endif /*DEBUG*/
+
+  /* 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);
+}
+
+/* increment reference counter of  struct ospf6_lsa */
+void
+ospf6_lsa_lock (struct ospf6_lsa *lsa)
+{
+  lsa->lock++;
+  return;
+}
+
+/* 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);
+
+  if (lsa->lock == 0)
+    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)
+{
+  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;
+
+  /* find previous LSA */
+  old = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id,
+                           lsa->header->adv_router, lsa->scope);
+  if (old)
+    {
+      /* Check if this is neither different instance nor refresh, return */
+      if (! CHECK_FLAG (old->flag, OSPF6_LSA_FLAG_REFRESH) &&
+          ! ospf6_lsa_differ (lsa, old))
+        {
+          if (IS_OSPF6_DUMP_LSA)
+            zlog_info ("LSA: Suppress updating %s", lsa->str);
+          ospf6_lsa_delete (lsa);
+          return;
+        }
+    }
+
+  lsa->refresh = thread_add_timer (master, ospf6_lsa_refresh, lsa,
+                                   OSPF6_LS_REFRESH_TIME);
+  gettimeofday (&lsa->originated, NULL);
+
+  //if (IS_OSPF6_DUMP_LSA)
+    zlog_info ("LSA: originate %s seq: %#x age: %hu %ld.%06ld",
+               lsa->str, ntohl (lsa->header->seqnum),
+               ospf6_lsa_age_current (lsa),
+               lsa->originated.tv_sec, lsa->originated.tv_usec);
+
+  ospf6_dbex_remove_from_all_retrans_list (lsa);
+  ospf6_dbex_flood (lsa, NULL);
+  ospf6_lsdb_install (lsa);
+}
+
+
+/* ospf6_lsa expired */
+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);
+
+  lsa->expire = (struct thread *) NULL;
+
+  /* log */
+  if (IS_OSPF6_DUMP_LSA)
+    zlog_info ("LSA: Expire: %s", lsa->str);
+
+  if (!lsa->summary)
+    {
+      /* 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) */
+    }
+
+  return 0;
+}
+
+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);
+
+  /* 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);
+
+  slot = ospf6_lsa_slot_get (lsa->header->type);
+  if (slot)
+    {
+      zlog_info ("LSA Refresh: %s", slot->name);
+      (*slot->func_refresh) (lsa);
+      return 0;
+    }
+
+  zlog_warn ("Can't Refresh LSA: Unknown type: %#x",
+             ntohs (lsa->header->type));
+  return 1;
+}
+
+
+
+/* enhanced Fletcher checksum algorithm, RFC1008 7.2 */
+#define MODX                4102
+#define LSA_CHECKSUM_OFFSET   15
+
+unsigned short
+ospf6_lsa_checksum (struct ospf6_lsa_header *lsa_header)
+{
+  u_char *sp, *ep, *p, *q;
+  int c0 = 0, c1 = 0;
+  int x, y;
+  u_int16_t length;
+
+  lsa_header->checksum = 0;
+  length = ntohs (lsa_header->length) - 2;
+  sp = (char *) &lsa_header->type;
+
+  for (ep = sp + length; sp < ep; sp = q)
+    {
+      q = sp + MODX;
+      if (q > ep)
+        q = ep;
+      for (p = sp; p < q; p++)
+        {
+          c0 += *p;
+          c1 += c0;
+        }
+      c0 %= 255;
+      c1 %= 255;
+    }
+
+  /* r = (c1 << 8) + c0; */
+  x = ((length - LSA_CHECKSUM_OFFSET) * c0 - c1) % 255;
+  if (x <= 0)
+    x += 255;
+  y = 510 - c0 - x;
+  if (y > 255)
+    y -= 255;
+
+  lsa_header->checksum = htons ((x << 8) + y);
+
+  return (lsa_header->checksum);
+}
+
+int
+ospf6_lsa_is_known_type (struct ospf6_lsa_header *lsa_header)
+{
+  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;
+
+  return 0;
+}
+
+int
+ospf6_lsa_slot_unregister (u_int16_t type)
+{
+  struct ospf6_lsa_slot *slot;
+
+  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);
+  end = (char *) lsa->header + ntohs (lsa->header->length);
+  for (current = start; current + sizeof (struct ospf6_router_lsd) <= end;
+       current += sizeof (struct ospf6_router_lsd))
+    {
+      lsdesc = (struct ospf6_router_lsd *) current;
+
+      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);
+    }
+  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;
+
+  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);
+}
+
diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h
new file mode 100644
index 0000000..02ad7c6
--- /dev/null
+++ b/ospf6d/ospf6_lsa.h
@@ -0,0 +1,426 @@
+/*
+ * LSA function
+ * 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_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)
+
+/* 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 */
+
+/* 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
+
+/* 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_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 */
+#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))
+
+/* 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 */
+  u_int32_t adv_router; /* Advertising Router */
+  u_int32_t seqnum;     /* LS sequence number */
+  u_int16_t checksum;   /* LS checksum */
+  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)))
+
+struct ospf6_lsa
+{
+  char                   str[256];  /* 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 */
+
+  /* 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_slot
+{
+  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;
+};
+
+#define OSPF6_LSA_FLAG_FLOODBACK  0x01
+#define OSPF6_LSA_FLAG_DUPLICATE  0x02
+#define OSPF6_LSA_FLAG_IMPLIEDACK 0x04
+#define OSPF6_LSA_FLAG_REFRESH    0x08
+
+/* 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)
+
+/* MaxAge check.  */
+/* ospf6_lsa_is_maxage (struct ospf6_lsa *lsa) */
+#define IS_LSA_MAXAGE(L)      (ospf6_lsa_age_current (L) == OSPF6_LSA_MAXAGE)
+
+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 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__);\
+        }\
+    }
+
+void ospf6_lsa_init ();
+
+/* Function Prototypes */
+
+struct router_lsd *
+get_router_lsd (u_int32_t, struct ospf6_lsa *);
+unsigned long get_ifindex_to_router (u_int32_t, struct ospf6_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 *);
+
+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 *);
+
+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);
+
+int ospf6_lsa_expire (struct thread *);
+int ospf6_lsa_refresh (struct thread *);
+
+u_short ospf6_lsa_checksum (struct ospf6_lsa_header *);
+
+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);
+
+u_int16_t ospf6_lsa_get_scope_type (u_int16_t);
+int ospf6_lsa_is_known_type (struct ospf6_lsa_header *lsa_header);
+
+char *ospf6_lsa_type_string (u_int16_t type, char *buf, int bufsize);
+char *ospf6_lsa_router_bits_string (u_char router_bits, char *buf, int size);
+
+u_long
+ospf6_lsa_has_elasped (u_int16_t, u_int32_t, u_int32_t, void *);
+void
+ospf6_lsa_originate (u_int16_t, u_int32_t, u_int32_t, char *, int, void *);
+
+#endif /* OSPF6_LSA_H */
+
diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c
new file mode 100644
index 0000000..ad53eb4
--- /dev/null
+++ b/ospf6d/ospf6_lsdb.c
@@ -0,0 +1,723 @@
+/*
+ * Copyright (C) 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 "memory.h"
+#include "log.h"
+#include "command.h"
+#include "if.h"
+
+#include "ospf6_dump.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 ()
+{
+  struct ospf6_lsdb *lsdb;
+
+  lsdb = XCALLOC (MTYPE_OSPF6_LSDB, sizeof (struct ospf6_lsdb));
+  if (lsdb == NULL)
+    {
+      zlog_warn ("Can't malloc lsdb");
+      return NULL;
+    }
+  memset (lsdb, 0, sizeof (struct ospf6_lsdb));
+
+  lsdb->table = route_table_init ();
+  return lsdb;
+}
+
+void
+ospf6_lsdb_delete (struct ospf6_lsdb *lsdb)
+{
+  ospf6_lsdb_remove_all (lsdb);
+  route_table_finish (lsdb->table);
+  XFREE (MTYPE_OSPF6_LSDB, lsdb);
+}
+
+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)
+{
+  int len = 0;
+  memset (key, 0, sizeof (struct prefix_ipv6));
+
+  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);
+
+  key->family = AF_INET6;
+  key->prefixlen = len * 8;
+}
+
+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;
+
+  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);
+
+  rn = route_node_get (lsdb->table, (struct prefix *) &key);
+  if (rn->info)
+    old = rn->info;
+  rn->info = lsa;
+  ospf6_lsa_lock (lsa);
+
+  if (old)
+    ospf6_lsa_unlock (old);
+  else
+    lsdb->count++;
+}
+
+void
+ospf6_lsdb_remove (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb)
+{
+  int flag;
+  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);
+
+  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;
+    }
+
+  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;
+    }
+
+  rn->info = NULL;
+  ospf6_lsa_unlock (old);
+  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;
+
+  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;
+    }
+}
+
+struct ospf6_lsa *
+ospf6_lsdb_lookup (u_int16_t type, u_int32_t id, u_int32_t adv_router,
+                   void *scope)
+{
+  struct ospf6_interface *o6i;
+  struct ospf6_area *o6a;
+  listnode i, j;
+
+  if (scope == (void *) ospf6)
+    return ospf6_lsdb_lookup_lsdb (type, id, adv_router, ospf6->lsdb);
+
+  for (i = listhead (ospf6->area_list); i; nextnode (i))
+    {
+      o6a = getdata (i);
+
+      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;
+}
+
+void
+ospf6_lsdb_install (struct ospf6_lsa *new)
+{
+  struct ospf6_lsdb *lsdb;
+  struct ospf6_lsa *old;
+  int need_hook = 0;
+  void (*hook) (struct ospf6_lsa *, struct ospf6_lsa *);
+
+  struct ospf6 *as = NULL;
+  struct ospf6_area *area = NULL;
+  struct ospf6_interface *linklocal = NULL;
+  hook = NULL;
+
+  switch (ntohs (new->header->type) & OSPF6_LSTYPE_SCOPE_MASK)
+    {
+      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;
+    }
+
+  /* whether schedule calculation or not */
+  old = ospf6_lsdb_lookup_lsdb (new->header->type, new->header->id,
+                                new->header->adv_router, lsdb);
+
+  if (! old || ospf6_lsa_differ (old, new))
+    need_hook++;
+
+  /* log */
+  if (IS_OSPF6_DUMP_LSDB)
+    zlog_info ("LSDB: Install: %s %s", new->str,
+               ((IS_LSA_MAXAGE (new)) ? "(MaxAge)" : ""));
+
+  if (old)
+    ospf6_lsa_lock (old);
+
+  ospf6_lsdb_add (new, lsdb);
+  gettimeofday (&new->installed, NULL);
+
+  hook = ospf6_lsdb_hook[ntohs (new->header->type) &
+                         OSPF6_LSTYPE_CODE_MASK].hook;
+  if (need_hook && hook)
+    (*hook) (old, new);
+
+  /* old LSA should be freed here */
+  if (old)
+    ospf6_lsa_unlock (old);
+}
+
+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);
+}
+
+
diff --git a/ospf6d/ospf6_lsdb.h b/ospf6d/ospf6_lsdb.h
new file mode 100644
index 0000000..50eedc8
--- /dev/null
+++ b/ospf6d/ospf6_lsdb.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 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_LSDB_H
+#define OSPF6_LSDB_H
+
+#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 *);
+};
+
+/* int  ospf6_lsdb_is_end (struct ospf6_lsdb_node *lsdb_node); */
+#define ospf6_lsdb_is_end(lsdb_node) ((lsdb_node)->node == NULL ? 1 : 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;
+
+/* Function Prototypes */
+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);
+
+void ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb);
+void ospf6_lsdb_remove (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb);
+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);
+
+void ospf6_lsdb_init ();
+
+#endif /* OSPF6_LSDB_H */
+
diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c
new file mode 100644
index 0000000..5ab517f
--- /dev/null
+++ b/ospf6d/ospf6_main.c
@@ -0,0 +1,326 @@
+/*
+ * 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 "getopt.h"
+#include "thread.h"
+#include "log.h"
+#include "version.h"
+#include "command.h"
+#include "vty.h"
+#include "memory.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 options, we use GNU getopt library. */
+struct option longopts[] = 
+{
+  { "daemon",      no_argument,       NULL, 'd'},
+  { "config_file", required_argument, NULL, 'f'},
+  { "pid_file",    required_argument, NULL, 'i'},
+  { "vty_addr",    required_argument, NULL, 'A'},
+  { "vty_port",    required_argument, NULL, 'P'},
+  { "version",     no_argument,       NULL, 'v'},
+  { "help",        no_argument,       NULL, 'h'},
+  { 0 }
+};
+
+/* Configuration file and directory. */
+char config_current[] = OSPF6_DEFAULT_CONFIG;
+char config_default[] = SYSCONFDIR OSPF6_DEFAULT_CONFIG;
+
+/* ospf6d program name. */
+
+/* is daemon? */
+int daemon_mode = 0;
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* Process ID saved for use by init system */
+char *pid_file = PATH_OSPF6D_PID;
+
+/* for reload */
+char _cwd[64];
+char _progpath[64];
+int _argc;
+char **_argv;
+char **_envp;
+
+/* Help information display. */
+static void
+usage (char *progname, int status)
+{
+  if (status != 0)
+    fprintf (stderr, "Try `%s --help' for more information.\n", progname);
+  else
+    {    
+      printf ("Usage : %s [OPTION...]\n\n\
+Daemon which manages OSPF version 3.\n\n\
+-d, --daemon       Runs in daemon mode\n\
+-f, --config_file  Set configuration file name\n\
+-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\
+-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);
+    }
+
+  exit (status);
+}
+
+
+void
+_reload ()
+{
+  zlog_notice ("OSPF6d (Zebra-%s ospf6d-%s) reloaded",
+               ZEBRA_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",
+               ZEBRA_VERSION, OSPF6_DAEMON_VERSION);
+  exit (i);
+}
+
+/* SIGHUP handler. */
+void 
+sighup (int sig)
+{
+  zlog_info ("SIGHUP received");
+  _reload ();
+}
+
+/* SIGINT handler. */
+void
+sigint (int sig)
+{
+  zlog_info ("SIGINT received");
+  terminate (0);
+}
+
+/* SIGTERM handler. */
+void
+sigterm (int sig)
+{
+  zlog_info ("SIGTERM received");
+  terminate (0);
+}
+
+/* SIGUSR1 handler. */
+void
+sigusr1 (int sig)
+{
+  zlog_info ("SIGUSR1 received");
+  zlog_rotate (NULL);
+}
+
+/* Signale wrapper. */
+RETSIGTYPE *
+signal_set (int signo, void (*func)(int))
+{
+  int ret;
+  struct sigaction sig;
+  struct sigaction osig;
+
+  sig.sa_handler = func;
+  sigemptyset (&sig.sa_mask);
+  sig.sa_flags = 0;
+#ifdef SA_RESTART
+  sig.sa_flags |= SA_RESTART;
+#endif /* SA_RESTART */
+
+  ret = sigaction (signo, &sig, &osig);
+
+  if (ret < 0) 
+    return (SIG_ERR);
+  else
+    return (osig.sa_handler);
+}
+
+/* Initialization of signal handles. */
+void
+signal_init ()
+{
+  signal_set (SIGHUP, sighup);
+  signal_set (SIGINT, sigint);
+  signal_set (SIGTERM, sigterm);
+  signal_set (SIGPIPE, SIG_IGN);
+#ifdef SIGTSTP
+  signal_set (SIGTSTP, SIG_IGN);
+#endif
+#ifdef SIGTTIN
+  signal_set (SIGTTIN, SIG_IGN);
+#endif
+#ifdef SIGTTOU
+  signal_set (SIGTTOU, SIG_IGN);
+#endif
+  signal_set (SIGUSR1, sigusr1);
+}
+
+/* Main routine of ospf6d. Treatment of argument and start ospf finite
+   state machine is handled here. */
+int
+main (int argc, char *argv[], char *envp[])
+{
+  char *p;
+  int opt;
+  char *vty_addr = NULL;
+  int vty_port = 0;
+  char *config_file = NULL;
+  char *progname;
+  struct thread thread;
+  int flag;
+
+  /* Set umask before anything for security */
+  umask (0027);
+
+  /* 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) 
+    {
+      opt = getopt_long (argc, argv, "df:hp:A:P:v", longopts, 0);
+    
+      if (opt == EOF)
+        break;
+
+      switch (opt) 
+        {
+        case 0:
+          break;
+        case 'd':
+          daemon_mode = 1;
+          break;
+        case 'f':
+          config_file = optarg;
+          break;
+        case 'A':
+          vty_addr = optarg;
+          break;
+        case 'i':
+          pid_file = optarg;
+          break;
+        case 'P':
+          vty_port = atoi (optarg);
+          break;
+        case 'v':
+          print_version (progname);
+          exit (0);
+          break;
+        case 'h':
+          usage (progname, 0);
+          break;
+        default:
+          usage (progname, 1);
+          break;
+        }
+    }
+
+  /* thread master */
+  master = thread_master_create ();
+
+  /* Initializations. */
+  if (! daemon_mode)
+    flag = ZLOG_STDOUT;
+  else
+    flag = 0;
+
+  zlog_default = openzlog (progname, flag, ZLOG_OSPF6,
+			   LOG_CONS|LOG_NDELAY|LOG_PERROR|LOG_PID,
+			   LOG_DAEMON);
+  signal_init ();
+  cmd_init (1);
+  vty_init ();
+  ospf6_init ();
+  memory_init ();
+  sort_node ();
+
+  /* parse config file */
+  vty_read_config (config_file, config_current, config_default);
+
+  if (daemon_mode)
+    daemon (0, 0);
+
+  /* pid file create */
+#if 0
+  pid_output_lock (pid_file);
+#else
+  pid_output (pid_file);
+#endif
+
+  /* Make ospf protocol socket. */
+  ospf6_serv_sock ();
+  thread_add_read (master, ospf6_receive, NULL, ospf6_sock);
+
+  /* Make ospf vty socket. */
+  vty_serv_sock (vty_addr,
+		 vty_port ? vty_port : OSPF6_VTY_PORT, OSPF6_VTYSH_PATH);
+
+  /* Print start message */
+  zlog_notice ("OSPF6d (Zebra-%s ospf6d-%s) starts",
+               ZEBRA_VERSION, OSPF6_DAEMON_VERSION);
+
+  /* Start finite state machine, here we go! */
+  while (thread_fetch (master, &thread))
+    thread_call (&thread);
+
+  /* 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
new file mode 100644
index 0000000..f6577a9
--- /dev/null
+++ b/ospf6d/ospf6_message.c
@@ -0,0 +1,1972 @@
+/*
+ * 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"
+
+int
+is_ospf6_message_dump (u_char type)
+{
+  if (type > OSPF6_MESSAGE_TYPE_LSACK)
+    type = OSPF6_MESSAGE_TYPE_UNKNOWN;
+
+  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;
+}
+#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)
+{
+  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;
+
+  /* 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));
+
+  hello = (struct ospf6_hello *) message[1].iov_base;
+
+  inet_ntop (AF_INET, &hello->dr, dr_str, sizeof (dr_str));
+  inet_ntop (AF_INET, &hello->bdr, bdr_str, sizeof (bdr_str));
+
+  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);
+
+  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))
+    {
+      char neighbor[16];
+      inet_ntop (AF_INET, current, neighbor, sizeof (neighbor));
+      zlog_info ("    Neighbor: %s", neighbor);
+    }
+}
+
+static void
+ospf6_message_log_dbdesc (struct iovec *message)
+{
+  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;
+
+  /* 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));
+
+  dbdesc = (struct ospf6_dbdesc *) message[1].iov_base;
+  ospf6_options_string (dbdesc->options, buffer, sizeof (buffer));
+
+  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));
+
+  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);
+
+  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;
+    }
+}
+
+static void
+ospf6_message_log_lsreq (struct iovec *message)
+{
+  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];
+
+  /* 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));
+
+  for (i = 1; message[i].iov_base; i++)
+    {
+      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;
+    }
+}
+
+static void
+ospf6_message_log_lsupdate (struct iovec *message)
+{
+  struct ospf6_header *ospf6_header;
+  u_int16_t length_left;
+  int i, lsanum;
+  struct ospf6_lsupdate *lsupdate;
+  struct ospf6_lsa_header *lsa_header;
+
+  /* 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));
+
+  lsupdate = (struct ospf6_lsupdate *) message[1].iov_base;
+  lsanum = ntohl (lsupdate->lsupdate_num);
+
+  zlog_info ("    Number of LSA: #%d", lsanum);
+
+  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 (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;
+    }
+}
+
+static void
+ospf6_message_log_lsack (struct iovec *message)
+{
+  struct ospf6_header *ospf6_header;
+  u_int16_t length_left;
+  struct ospf6_lsa_header *lsa_header;
+  int i;
+
+  /* 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));
+
+  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;
+    }
+}
+
+struct {
+  void (*message_log) (struct iovec *);
+} ospf6_message_log_body [] =
+{
+  {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;
+
+  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)
+    {
+      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));
+    }
+
+  /* HelloInterval check */
+  if (ntohs (hello->hello_interval) != o6i->hello_interval)
+    {
+      zlog_warn ("HelloInterval mismatch with %s", o6n->str);
+      return;
+    }
+
+  /* RouterDeadInterval check */
+  if (ntohs (hello->router_dead_interval)
+      != o6i->dead_interval)
+    {
+      zlog_warn ("RouterDeadInterval mismatch with %s", o6n->str);
+      return;
+    }
+
+  /* check options */
+  /* Ebit */
+  if (ospf6_opt_is_mismatch (OSPF6_OPT_E, hello->options, o6i->area->options))
+    {
+      zlog_warn ("Ebit mismatch with %s", o6n->str);
+      return;
+    }
+
+  /* RouterPriority set */
+  if (o6n->priority != hello->rtr_pri)
+    {
+      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;
+    }
+
+  /* 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++)
+    {
+      if (*router_id_ptr == o6i->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);
+
+  /* BackupSeen check */
+  if (o6i->state == IFS_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)
+        backupseen++;
+      else if (hello->dr == o6n->router_id && hello->bdr == 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++;
+
+  /* schedule interface events */
+  if (backupseen)
+    thread_add_event (master, backup_seen, o6i, 0);
+  if (nbchange)
+    thread_add_event (master, neighbor_change, o6i, 0);
+
+  return;
+}
+
+int
+ospf6_dbdesc_is_master (struct ospf6_neighbor *o6n)
+{
+  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;
+
+  /* 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:
+        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");
+      return;
+    }
+
+  if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr)))
+    {
+      if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
+        zlog_info ("From Secondary I/F of the neighbor: ignore");
+      return;
+    }
+
+  /* interface mtu check */
+    /* xxx */
+
+  /* check am I master */
+  Im_master = ospf6_dbdesc_is_master (o6n);
+  if (Im_master < 0)
+    {
+      return; /* can't decide which is master, return */
+    }
+
+  if (Im_master)
+    ospf6_process_dbdesc_master (message, o6n);
+  else
+    ospf6_process_dbdesc_slave (message, o6n);
+
+  return;
+}
+
+void
+ospf6_process_lsreq (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_lsreq *lsreq;
+  struct iovec response[OSPF6_MESSAGE_IOVEC_SIZE];
+  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);
+
+  /* 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)
+    {
+      if (IS_OSPF6_DUMP_LSREQ)
+        zlog_info ("  neighbor not found, reject");
+      return;
+    }
+
+  if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr)))
+    {
+      if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
+        zlog_info ("From Secondary I/F of the neighbor: ignore");
+      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 (IS_OSPF6_DUMP_LSREQ)
+        zlog_info ("  neighbor state less than Exchange, reject");
+      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++)
+    {
+      inet_ntop (AF_INET, &lsreq->adv_router, buf_router, sizeof (buf_router));
+      inet_ntop (AF_INET, &lsreq->id, buf_id, sizeof (buf_id));
+
+      /* 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)
+        {
+          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);
+          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++;
+    }
+
+  /* send response LSUpdate to this request */
+  if (lsanum)
+    {
+      lsupdate.lsupdate_num = htonl (lsanum);
+
+      ospf6_message_send (OSPF6_MESSAGE_TYPE_LSUPDATE, response,
+                          &o6n->hisaddr, o6i->if_id);
+    }
+
+  /* statistics */
+  o6n->lsa_receive[OSPF6_MESSAGE_TYPE_LSREQ]
+    += length / sizeof (struct ospf6_lsreq);
+}
+
+void
+ospf6_process_lsupdate (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_lsupdate *lsupdate;
+  struct ospf6_neighbor *o6n;
+  unsigned long lsanum;
+  struct ospf6_lsa_header *lsa_header;
+
+  /* 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);
+
+  /* find neighbor. if cannot be found, reject this message */
+  o6n = ospf6_neighbor_lookup (router_id, o6i);
+  if (! o6n)
+    {
+      if (IS_OSPF6_DUMP_LSUPDATE)
+        zlog_info ("  neighbor not found, reject");
+      return;
+    }
+
+  if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr)))
+    {
+      if (IS_OSPF6_DUMP_MESSAGE (ospf6_header->type))
+        zlog_info ("From Secondary I/F of the neighbor: ignore");
+      return;
+    }
+
+  /* if neighbor state less than ExChange, reject this message */
+  if (o6n->state < NBS_EXCHANGE)
+    {
+      if (IS_OSPF6_DUMP_LSUPDATE)
+        zlog_info ("  neighbor state less than Exchange, reject");
+      return;
+    }
+
+  /* set linkstate update pointer */
+  lsupdate = (struct ospf6_lsupdate *) message[1].iov_base;
+
+  /* save linkstate update info */
+  lsanum = ntohl (lsupdate->lsupdate_num);
+
+  /* statistics */
+  o6n->ospf6_stat_received_lsa += lsanum;
+  o6n->ospf6_stat_received_lsupdate++;
+
+  /* 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;
+}
+
+void
+ospf6_process_lsack (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_lsa_header *lsa_header;
+  struct ospf6_lsa *lsa, *copy, *rem;
+
+  /* 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);
+
+  /* find neighbor. if cannot be found, reject this message */
+  o6n = ospf6_neighbor_lookup (router_id, o6i);
+  if (!o6n)
+    {
+      if (IS_OSPF6_DUMP_LSACK)
+        zlog_info ("LSACK: neighbor not found, reject");
+      return;
+    }
+
+  if (memcmp (src, &o6n->hisaddr, sizeof (struct in6_addr)))
+    {
+      if (IS_OSPF6_DUMP_LSACK)
+        zlog_info ("LSACK: From Secondary I/F of the neighbor: ignore");
+      return;
+    }
+
+  /* if neighbor state less than ExChange, reject this message */
+  if (o6n->state < NBS_EXCHANGE)
+    {
+      if (IS_OSPF6_DUMP_LSACK)
+        zlog_info ("LSACK: neighbor state less than Exchange, reject");
+      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++)
+    {
+      /* 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));
+
+      /* if no database copy */
+      if (!copy)
+        {
+          if (IS_OSPF6_DUMP_LSACK)
+            zlog_info ("LSACK: no database copy, ignore");
+          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)
+        {
+          if (IS_OSPF6_DUMP_LSACK)
+            zlog_info ("LSACK: not on %s's retranslist, ignore", o6n->str);
+          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
+        {
+          /* Log the 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));
+        }
+
+      /* release temporary LSA from Ack message */
+      ospf6_lsa_delete (lsa);
+    }
+
+  ospf6_maxage_remover ();
+  return;
+}
+
+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;
+}
+
+int
+ospf6_receive (struct thread *thread)
+{
+  int sockfd;
+  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);
+
+  /* add next read thread */
+  thread_add_read (master, ospf6_receive, NULL, sockfd);
+
+  /* initialize */
+  OSPF6_MESSAGE_CLEAR (message);
+  memset (&ospf6_header, 0, sizeof (struct ospf6_header));
+
+  OSPF6_MESSAGE_ATTACH (message, &ospf6_header, sizeof (struct ospf6_header));
+  OSPF6_MESSAGE_ATTACH (message, buffer, OSPF6_MESSAGE_RECEIVE_BUFSIZE);
+
+  /* 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)
+    {
+      //zlog_warn ("*** received interface ospf6 disabled");
+      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);
+
+  return 0;
+}
+
+
+/* send section */
+int
+ospf6_message_length (struct iovec *message)
+{
+  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
+        memcpy (src_name, "Unknown", sizeof (src_name));
+      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;
+  int i;
+
+  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (o6n);
+
+  /* LSReq will be send only in ExStart or Loading */
+  if (o6n->state != NBS_EXCHANGE && o6n->state != NBS_LOADING)
+    return 0;
+
+  /* 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;
+
+  /* schedule loading_done if request list is empty */
+  if (o6n->request_list->count == 0)
+    {
+      thread_add_event (master, loading_done, o6n, 0);
+      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))
+    {
+      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++;
+    }
+
+  ospf6_message_send (OSPF6_MESSAGE_TYPE_LSREQ, message, &o6n->hisaddr,
+                      o6n->ospf6_interface->interface->ifindex);
+
+  /* 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;
+
+  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)
+{
+  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);
+}
+
+/* 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
new file mode 100644
index 0000000..105cb4f
--- /dev/null
+++ b/ospf6d/ospf6_message.h
@@ -0,0 +1,202 @@
+/*
+ * 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_MESSAGE_H
+#define OSPF6_MESSAGE_H
+
+#include "ospf6_prefix.h"
+#include "ospf6_lsa.h"
+
+/* 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_LSUPDATE 0x4  /* Database update */
+#define OSPF6_MESSAGE_TYPE_LSACK    0x5  /* Flooding acknowledgment */
+#define OSPF6_MESSAGE_TYPE_MAX      0x6
+
+/* OSPFv3 packet header */
+struct ospf6_header
+{
+  u_char    version;
+  u_char    type;
+  u_int16_t len;
+  u_int32_t router_id;
+  u_int32_t area_id;
+  u_int16_t cksum;
+  u_char    instance_id;
+  u_char    reserved;
+};
+
+/* Hello */
+#define MAXLISTEDNBR     64
+struct ospf6_hello
+{
+  u_int32_t interface_id;
+  u_char    rtr_pri;
+  u_char    options[3];
+  u_int16_t hello_interval;
+  u_int16_t router_dead_interval;
+  u_int32_t dr;
+  u_int32_t bdr;
+};
+
+/* Database Description */
+struct ospf6_dbdesc
+{
+  u_char    mbz1;
+  u_char    options[3];
+  u_int16_t ifmtu;
+  u_char    mbz2;
+  u_char    bits;
+  u_int32_t seqnum;
+  /* Followed by LSAs */
+};
+#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
+
+/* Link State Request */
+struct ospf6_lsreq
+{
+  u_int16_t mbz;          /* Must Be Zero */
+  u_int16_t type;         /* LS type */
+  u_int32_t id;           /* Link State ID */
+  u_int32_t adv_router;   /* Advertising Router */
+};
+
+/* Link State Update */
+struct ospf6_lsupdate
+{
+  u_int32_t lsupdate_num;
+};
+
+/* Link State Acknowledgement */
+  /* no need for structure,
+     it will include only LSA header in the packet body.*/
+
+/* definition for ospf6_message.c */
+#define OSPF6_MESSAGE_RECEIVE_BUFSIZE 5120
+#define OSPF6_MESSAGE_IOVEC_END       1024
+
+#define IS_OVER_MTU(message,mtu,addsize) \
+          (iov_totallen(message)+(addsize) >= \
+            (mtu)-sizeof(struct ospf6_header))
+
+#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)
+
+#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);
+
+#endif /* OSPF6_MESSAGE_H */
+
diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c
new file mode 100644
index 0000000..72735d5
--- /dev/null
+++ b/ospf6d/ospf6_neighbor.c
@@ -0,0 +1,602 @@
+/*
+ * 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"
+
+#include <zebra.h>
+
+#include "log.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 "ospf6_lsa.h"
+#include "ospf6_lsdb.h"
+
+char *ospf6_neighbor_state_string[] =
+{
+  "None", "Down", "Attempt", "Init", "Twoway",
+  "ExStart", "ExChange", "Loading", "Full", NULL
+};
+
+int
+ospf6_neighbor_last_dbdesc_release (struct thread *thread)
+{
+  struct ospf6_neighbor *o6n;
+
+  o6n = (struct ospf6_neighbor *) THREAD_ARG (thread);
+  assert (o6n);
+  memset (&o6n->last_dd, 0, sizeof (struct ospf6_dbdesc));
+  return 0;
+}
+
+
+
+void
+ospf6_neighbor_thread_cancel_all (struct ospf6_neighbor *o6n)
+{
+  if (o6n->inactivity_timer)
+    thread_cancel (o6n->inactivity_timer);
+  o6n->inactivity_timer = (struct thread *) NULL;
+
+  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)
+    {
+      zlog_info ("Neighbor %s summary-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->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);
+    }
+}
+
+/* create ospf6_neighbor */
+struct ospf6_neighbor *
+ospf6_neighbor_create (u_int32_t router_id, struct ospf6_interface *o6i)
+{
+  struct ospf6_neighbor *new;
+  char buf[32];
+
+  new = (struct ospf6_neighbor *)
+    XMALLOC (MTYPE_OSPF6_NEIGHBOR, sizeof (struct ospf6_neighbor));
+  if (new == 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;
+  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;
+
+  new->summary_list = ospf6_lsdb_create ();
+  new->request_list = ospf6_lsdb_create ();
+  new->retrans_list = ospf6_lsdb_create ();
+  new->dbdesc_list = ospf6_lsdb_create ();
+
+  listnode_add (o6i->neighbor_list, new);
+  new->ospf6_interface = o6i;
+
+  CALL_ADD_HOOK (&neighbor_hook, new);
+
+  return new;
+}
+
+void
+ospf6_neighbor_delete (struct ospf6_neighbor *o6n)
+{
+  CALL_REMOVE_HOOK (&neighbor_hook, o6n);
+
+  ospf6_neighbor_thread_cancel_all (o6n);
+  ospf6_neighbor_lslist_clear (o6n);
+
+  list_free (o6n->dbdesc_lsa);
+
+  ospf6_lsdb_delete (o6n->summary_list);
+  ospf6_lsdb_delete (o6n->request_list);
+  ospf6_lsdb_delete (o6n->retrans_list);
+  ospf6_lsdb_delete (o6n->dbdesc_list);
+
+  XFREE (MTYPE_OSPF6_NEIGHBOR, o6n);
+}
+
+struct ospf6_neighbor *
+ospf6_neighbor_lookup (u_int32_t router_id,
+                       struct ospf6_interface *o6i)
+{
+  listnode n;
+  struct ospf6_neighbor *o6n;
+
+  for (n = listhead (o6i->neighbor_list); n; nextnode (n))
+    {
+      o6n = (struct ospf6_neighbor *) getdata (n);
+      if (o6n->router_id == router_id)
+        return o6n;
+    }
+  return (struct ospf6_neighbor *) NULL;
+}
+
+
+/* vty functions */
+/* show neighbor structure */
+void
+ospf6_neighbor_show_summary (struct vty *vty, struct ospf6_neighbor *o6n)
+{
+  char router_id[16];
+  char dr[16], bdr[16];
+  char duration[16];
+  struct timeval now, res;
+
+/*
+    vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s",
+             "RouterID", "State", "Duration", "DR", "BDR", "I/F",
+             "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));
+
+  gettimeofday (&now, NULL);
+  ospf6_timeval_sub (&now, &o6n->last_changed, &res);
+  ospf6_timeval_string_summary (&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],
+           VTY_NEWLINE);
+}
+
+void
+ospf6_neighbor_show (struct vty *vty, struct ospf6_neighbor *o6n)
+{
+  char hisaddr[64], timestring[32];
+  struct timeval now, res;
+
+  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);
+
+  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);
+}
+
+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_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, "    %-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);
+}
+
+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,
+       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;
+
+  OSPF6_CMD_CHECK_RUNNING ();
+  i = j = k = l = NULL;
+
+  for (i = listhead (ospf6->area_list); i; nextnode (i))
+    {
+      o6a = (struct ospf6_area *) getdata (i);
+      for (j = listhead (o6a->if_list); j; nextnode (j))
+        {
+          o6i = (struct ospf6_interface *) getdata (j);
+          for (k = listhead (o6i->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);
+                }
+            }
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+void
+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 (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);
+}
+
+
diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h
new file mode 100644
index 0000000..c3821c6
--- /dev/null
+++ b/ospf6d/ospf6_neighbor.h
@@ -0,0 +1,161 @@
+/*
+ * 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_NEIGHBOR_H
+#define OSPF6_NEIGHBOR_H
+
+/* Neighbor structure */
+struct ospf6_neighbor
+{
+  /* Neighbor Router ID String */
+  char str[32];
+
+  /* OSPFv3 Interface this neighbor belongs to */
+  struct ospf6_interface *ospf6_interface;
+
+  /* Neighbor state */
+  u_char state;
+  struct timeval last_changed;
+
+  /* Neighbor Router ID */
+  u_int32_t router_id;
+
+  /* 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;
+
+  /* Link-LSA's options field */
+  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;
+
+  /* For Database Exchange */
+  u_char               dbdesc_bits;
+  u_int32_t            dbdesc_seqnum;
+  struct ospf6_dbdesc *dbdesc_previous;
+
+  /* last received DD , including OSPF capability of this neighbor */
+  struct ospf6_dbdesc last_dd;
+
+  /* LSAs to retransmit to this neighbor */
+  list dbdesc_lsa;
+
+  /* placeholder for DbDesc */
+  struct iovec dbdesc_last_send[1024];
+
+  struct thread *inactivity_timer;
+
+  /* DbDesc */
+  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;
+};
+
+extern char *ospf6_neighbor_state_string[];
+
+
+/* Function Prototypes */
+int
+ospf6_neighbor_last_dbdesc_release (struct thread *);
+
+void
+ospf6_neighbor_lslist_clear (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 *);
+
+void ospf6_neighbor_init ();
+
+#endif /* OSPF6_NEIGHBOR_H */
+
diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c
new file mode 100644
index 0000000..041d829
--- /dev/null
+++ b/ospf6d/ospf6_network.c
@@ -0,0 +1,501 @@
+/*
+ * 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 "memory.h"
+#include "log.h"
+#include "sockunion.h"
+
+#include "ospf6d.h"
+#include "ospf6_proto.h"
+
+extern int errno;
+extern struct sockaddr_in6 allspfrouters6;
+extern struct sockaddr_in6 alldrouters6;
+extern int ospf6_sock;
+extern struct thread_master *master;
+
+/* 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 ()
+{
+  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);
+
+  /* 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));
+#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.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));
+#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.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);
+#if 0
+  else
+    zlog_info ("Network: Leave AllDRouters on ifindex %d", ifindex);
+#endif
+}
+
+/* setsockopt ReUseAddr to on */
+void
+ospf6_set_reuseaddr ()
+{
+  u_int on = 0;
+  if (setsockopt (ospf6_sock, SOL_SOCKET, SO_REUSEADDR, &on,
+                  sizeof (u_int)) < 0)
+    zlog_warn ("Network: set SO_REUSEADDR failed: %s", strerror (errno));
+}
+
+/* setsockopt MulticastLoop to off */
+void
+ospf6_reset_mcastloop ()
+{
+  u_int off = 0;
+  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
+                  &off, sizeof (u_int)) < 0)
+    zlog_warn ("Network: reset IPV6_MULTICAST_LOOP failed: %s",
+               strerror (errno));
+}
+
+void
+ospf6_set_pktinfo ()
+{
+  u_int on = 1;
+#ifdef IPV6_RECVPKTINFO	/*2292bis-01*/
+  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+                  &on, sizeof (u_int)) < 0)
+    zlog_warn ("Network: set IPV6_RECVPKTINFO failed: %s", strerror (errno));
+#else /*RFC2292*/
+  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_PKTINFO,
+                  &on, sizeof (u_int)) < 0)
+    zlog_warn ("Network: set IPV6_PKTINFO failed: %s", strerror (errno));
+#endif
+}
+
+void
+ospf6_set_checksum ()
+{
+  int offset = 12;
+#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));
+#else
+  zlog_warn ("Network: Don't set IPV6_CHECKSUM");
+#endif /* DISABLE_IPV6_CHECKSUM */
+}
+
+void
+ospf6_sendmsg (struct in6_addr *src, struct in6_addr *dst,
+               unsigned int *ifindex, struct iovec *message)
+{
+  int retval;
+  struct msghdr smsghdr;
+  struct cmsghdr *scmsgp;
+  u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))];
+  struct in6_pktinfo *pktinfo;
+  struct sockaddr_in6 dst_sin6;
+
+  assert (dst);
+  assert (*ifindex);
+
+  scmsgp = (struct cmsghdr *)cmsgbuf;
+  pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp));
+  memset (&dst_sin6, 0, sizeof (struct sockaddr_in6));
+
+  /* source address */
+  pktinfo->ipi6_ifindex = *ifindex;
+  if (src)
+    memcpy (&pktinfo->ipi6_addr, src, sizeof (struct in6_addr));
+  else
+    memset (&pktinfo->ipi6_addr, 0, sizeof (struct in6_addr));
+
+  /* destination address */
+  dst_sin6.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+  dst_sin6.sin6_len = sizeof (struct sockaddr_in6);
+#endif /*SIN6_LEN*/
+  memcpy (&dst_sin6.sin6_addr, dst, sizeof (struct in6_addr));
+#ifdef HAVE_SIN6_SCOPE_ID
+  dst_sin6.sin6_scope_id = *ifindex;
+#endif
+
+  /* send control msg */
+  scmsgp->cmsg_level = IPPROTO_IPV6;
+  scmsgp->cmsg_type = IPV6_PKTINFO;
+  scmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo));
+  /* scmsgp = CMSG_NXTHDR (&smsghdr, scmsgp); */
+
+  /* send msg hdr */
+  smsghdr.msg_iov = message;
+  smsghdr.msg_iovlen = iov_count (message);
+  smsghdr.msg_name = (caddr_t) &dst_sin6;
+  smsghdr.msg_namelen = sizeof (struct sockaddr_in6);
+  smsghdr.msg_control = (caddr_t) cmsgbuf;
+  smsghdr.msg_controllen = sizeof (cmsgbuf);
+
+  retval = sendmsg (ospf6_sock, &smsghdr, 0);
+  if (retval != iov_totallen (message))
+    zlog_warn ("Network: sendmsg (ifindex: %d) failed: %s(%d)",
+               *ifindex, strerror (errno), errno);
+}
+
+void
+ospf6_recvmsg (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, 0);
+  if (retval < 0)
+    {
+      zlog_warn ("Network: 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));
+    }
+
+  /* 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));
+}
+
+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
new file mode 100644
index 0000000..934cce5
--- /dev/null
+++ b/ospf6d/ospf6_network.h
@@ -0,0 +1,58 @@
+/*
+ * 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_NETWORK_H
+#define OSPF6_NETWORK_H
+
+
+
+/* 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);
+
+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);
+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 *);
+
+#endif /* OSPF6_NETWORK_H */
+
diff --git a/ospf6d/ospf6_nsm.c b/ospf6d/ospf6_nsm.c
new file mode 100644
index 0000000..aa08d40
--- /dev/null
+++ b/ospf6d/ospf6_nsm.c
@@ -0,0 +1,391 @@
+/*
+ * 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
new file mode 100644
index 0000000..d70f1e8
--- /dev/null
+++ b/ospf6d/ospf6_nsm.h
@@ -0,0 +1,67 @@
+/*
+ * 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
new file mode 100644
index 0000000..1542200
--- /dev/null
+++ b/ospf6d/ospf6_prefix.c
@@ -0,0 +1,213 @@
+/*
+ * 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
new file mode 100644
index 0000000..65a8cbc
--- /dev/null
+++ b/ospf6d/ospf6_prefix.h
@@ -0,0 +1,83 @@
+/*
+ * 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
new file mode 100644
index 0000000..71e575f
--- /dev/null
+++ b/ospf6d/ospf6_proto.c
@@ -0,0 +1,40 @@
+/*
+ * 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 "ospf6_proto.h"
+
+char *
+ospf6_options_string (u_char opt_capability[3], char *buffer, 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;
+}
+
diff --git a/ospf6d/ospf6_proto.h b/ospf6d/ospf6_proto.h
new file mode 100644
index 0000000..9a95444
--- /dev/null
+++ b/ospf6d/ospf6_proto.h
@@ -0,0 +1,75 @@
+/*
+ * 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_PROTO_H
+#define OSPF6_PROTO_H
+
+/* OSPF protocol version */
+#define OSPF6_VERSION		3
+
+/* OSPF protocol number. */
+#ifndef IPPROTO_OSPFIGP
+#define IPPROTO_OSPFIGP         89
+#endif
+
+/* TOS field normaly null */
+#define OSPF6_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 ALLSPFROUTERS6 "ff02::5"
+#define ALLDROUTERS6   "ff02::6"
+
+/* Configurable Constants */
+
+#define DEFAULT_HELLO_INTERVAL    10
+#define DEFAULT_ROUTER_DEAD_TIMER 40
+
+/* OSPF options */
+/* present in HELLO, DD, LSA */
+#define OSPF6_OPT_SET(x,opt)   ((x)[2] |=  (opt))
+#define OSPF6_OPT_ISSET(x,opt) ((x)[2] &   (opt))
+#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 */
+
+char *
+ospf6_options_string (u_char opt_capability[3], char *buffer, int size);
+
+#endif /* OSPF6_PROTO_H */
+
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c
new file mode 100644
index 0000000..c35efa6
--- /dev/null
+++ b/ospf6d/ospf6_route.c
@@ -0,0 +1,1130 @@
+/*
+ * 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"
+
+char *
+dtype_name[OSPF6_DEST_TYPE_MAX] =
+{
+  "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;
+}
+
+int
+ospf6_nexthop_cmp (void *arg1, void *arg2)
+{
+  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;
+}
+
+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)
+{
+  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));
+}
+
+int
+ospf6_route_count (struct ospf6_route_req *request)
+{
+  return request->count;
+}
+
+int
+ospf6_route_lookup (struct ospf6_route_req *request,
+                    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));
+
+  node = route_node_lookup (table->table, prefix);
+  if (! node)
+    return 0;
+
+  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;
+}
+
+void
+ospf6_route_head (struct ospf6_route_req *request,
+                  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 (request, 0, sizeof (struct ospf6_route_req));
+
+  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);
+}
+
+int
+ospf6_route_end (struct ospf6_route_req *request)
+{
+  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;
+}
+
+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_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;
+
+  int route_change   = 0;
+  int path_change    = 0;
+  int nexthop_change = 0;
+
+  /* find the requested route */
+  route_node = route_node_get (table->table, &request->route.prefix);
+  rn = (struct ospf6_route_node *) route_node->info;
+
+  if (rn)
+    {
+      if (memcmp (&rn->route, &request->route, sizeof (struct ospf6_route)))
+        {
+          memcpy (&rn->route, &request->route, sizeof (struct ospf6_route));
+          route_change++;
+        }
+    }
+  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;
+    }
+
+  /* find the same path */
+  pn = ospf6_route_find_path_node (request, rn);
+
+  if (pn)
+    {
+      if (memcmp (&pn->path, &request->path, sizeof (struct ospf6_path)))
+        {
+          memcpy (&pn->path, &request->path, sizeof (struct ospf6_path));
+          path_change++;
+        }
+    }
+  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);
+    }
+
+  /* find the same nexthop */
+  nn = ospf6_route_find_nexthop_node (request, pn);
+
+  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 (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;
+}
+
+void
+ospf6_route_remove (struct ospf6_route_req *request,
+                    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;
+
+  /* find the requested route */
+  route_node = route_node_get (table->table, &request->route.prefix);
+  rn = (struct ospf6_route_node *) route_node->info;
+
+  if (! rn)
+    {
+      if (IS_OSPF6_DUMP_ROUTE)
+        {
+          ospf6_route_log_request ("Remove", table->name, request);
+          zlog_info ("ROUTE:   Can't remove: No such route");
+        }
+      return;
+    }
+
+  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, " ");
+                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, " ");
+                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);
+
+  /* clear flag */
+  nn->flag = 0;
+
+  /* remove nexthop */
+  linklist_remove (nn, pn->nexthop_list);
+  rn->count--;
+  XFREE (MTYPE_OSPF6_ROUTE, nn);
+
+  /* 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);
+
+  /* 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);
+}
+
+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_table *
+ospf6_route_table_create (char *name)
+{
+  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_node *rn)
+{
+  struct linklist_node pnode;
+  struct linklist_node nnode;
+  struct ospf6_path_node    *pn;
+  struct ospf6_nexthop_node *nn;
+
+  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];
+
+  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));
+  else
+    prefix_ls2str (&rn->route.prefix, prefix, sizeof (prefix));
+
+  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;
+
+          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++;
+    }
+}
+
+void
+ospf6_route_show_detail (struct vty *vty, struct ospf6_route_node *rn)
+{
+  struct linklist_node pnode;
+  struct linklist_node nnode;
+  struct ospf6_path_node    *pn;
+  struct ospf6_nexthop_node *nn;
+
+  u_int pc = 0;
+  u_int nc = 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))
+    {
+      pn = pnode.data;
+
+      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));
+
+      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);
+
+      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);
+
+          vty_out (vty, "       %c%s%%%s%s",
+                   (HEAD ? '*' : ' '), nexthop, ifname, VTY_NEWLINE);
+
+          nc++;
+        }
+      pc++;
+    }
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+int
+ospf6_route_table_show (struct vty *vty, int argc, char **argv,
+                        struct ospf6_route_table *table)
+{
+  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;
+
+  memset (&prefix, 0, sizeof (struct prefix));
+
+  for (i = 0; i < argc; i++)
+    {
+      if (! strcmp (argv[i], "detail"))
+        {
+          detail++;
+          break;
+        }
+
+      if (! arg_ipv6 && ! arg_ipv4 && ! arg_digit)
+        {
+
+          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;
+                }
+            }
+        }
+
+      if (arg_ipv4 || arg_digit)
+        {
+          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;
+                }
+            }
+        }
+    }
+
+  if (arg_ipv4 || arg_ipv6 || arg_digit)
+    {
+      node = route_node_match (table->table, &prefix);
+      if (node && node->info)
+        ospf6_route_show_detail (vty, node->info);
+      return CMD_SUCCESS;
+    }
+
+  if (! detail)
+    {
+      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);
+    }
+
+  for (node = route_top (table->table); node; node = route_next (node))
+    {
+      struct ospf6_route_node *route = node->info;
+
+      if (! route)
+        continue;
+
+      if (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++;
+    }
+
+  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;
+}
+
diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h
new file mode 100644
index 0000000..71b2562
--- /dev/null
+++ b/ospf6d/ospf6_route.h
@@ -0,0 +1,209 @@
+/*
+ * 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_ROUTE_H
+#define OSPF6_ROUTE_H
+
+#include "ospf6_hook.h"
+#include "ospf6_linklist.h"
+
+struct ospf6_route_table
+{
+  char name[128];
+
+  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;
+};
+
+
+
+struct ospf6_route
+{
+  /* Destination ID */
+  struct prefix prefix;
+
+  /* Destination Type */
+  u_char type;
+};
+
+/* Path */
+struct ls_origin
+{
+  u_int16_t type;
+  u_int32_t id;
+  u_int32_t adv_router;
+};
+
+struct ospf6_path
+{
+  /* Link State Origin */
+  struct ls_origin origin;
+
+  /* Router bits */
+  u_char router_bits;
+
+  /* Optional Capabilities */
+  u_char capability[3];
+
+  /* Prefix Options */
+  u_char prefix_options;
+
+  /* Associated Area */
+  u_int32_t area_id;
+
+  /* Path-type */
+  u_char type;
+
+  /* Cost */
+  u_int8_t metric_type;
+  u_int32_t cost;
+  u_int32_t cost_e2;
+};
+
+/* Nexthop */
+struct ospf6_nexthop
+{
+  /* Interface index */
+  unsigned int ifindex;
+
+  /* IP address, if any */
+  struct in6_addr address;
+};
+
+struct ospf6_route_node
+{
+  struct ospf6_route_table *table;
+  int count;
+  u_int32_t route_id;
+
+  struct route_node  *route_node;
+  struct ospf6_route  route;
+  struct linklist    *path_list;
+};
+
+struct ospf6_path_node
+{
+  struct ospf6_route_node *route_node;
+  struct ospf6_path        path;
+  struct linklist         *nexthop_list;
+};
+
+struct ospf6_nexthop_node
+{
+  int            flag;
+  struct timeval installed;
+
+  struct ospf6_path_node *path_node;
+  struct ospf6_nexthop    nexthop;
+};
+
+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;
+
+  int count;
+  struct ospf6_route   route;
+  struct ospf6_path    path;
+  struct ospf6_nexthop nexthop;
+};
+
+#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_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_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
+
+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);
+
+void ospf6_route_add (struct ospf6_route_req *, struct ospf6_route_table *);
+void ospf6_route_remove (struct ospf6_route_req *, struct ospf6_route_table *);
+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 ();
+
+int ospf6_route_table_show (struct vty *, int, char **,
+                            struct ospf6_route_table *);
+
+#endif /* OSPF6_ROUTE_H */
+
diff --git a/ospf6d/ospf6_routemap.c b/ospf6d/ospf6_routemap.c
new file mode 100644
index 0000000..14df794
--- /dev/null
+++ b/ospf6d/ospf6_routemap.c
@@ -0,0 +1,359 @@
+/*
+ * 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 (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);
+}
+
diff --git a/ospf6d/ospf6_routemap.h b/ospf6d/ospf6_routemap.h
new file mode 100644
index 0000000..c68e0ff
--- /dev/null
+++ b/ospf6d/ospf6_routemap.h
@@ -0,0 +1,27 @@
+/*
+ * 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
new file mode 100644
index 0000000..fd7fc77
--- /dev/null
+++ b/ospf6d/ospf6_spf.c
@@ -0,0 +1,1454 @@
+/*
+ * 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.  
+ */
+/* Shortest Path First calculation for OSPFv3 */
+
+#include "ospf6d.h"
+
+#include "linklist.h"
+#include "prefix.h"
+#include "table.h"
+
+#include "ospf6_proto.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_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;
+};
+
+int
+ospf6_spf_candidate_node_cmp (void *a, void *b)
+{
+  struct ospf6_spf_candidate_node *ca = a;
+  struct ospf6_spf_candidate_node *cb = b;
+  return ca->cost - cb->cost;
+}
+
+int
+ospf6_spf_vertex_cmp (void *a, void *b)
+{
+  return 1;
+}
+
+void
+ospf6_spf_candidate_node_print (int indent_num, void *node)
+{
+  struct ospf6_spf_candidate_node *cn = node;
+  char format[256];
+
+  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
+
+  return ret;
+}
+
+void
+ospf6_spf_candidate_remove (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);
+  XFREE (MTYPE_OSPF6_VERTEX, v);
+}
+
+static void
+ospf6_spf_vertex_merge (struct ospf6_vertex *w, struct ospf6_vertex *x)
+{
+  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;
+
+  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))
+    {
+      v = (struct ospf6_vertex *) getdata (node);
+      ospf6_spf_vertex_delete (v);
+    }
+  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++)
+        {
+          /* (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);
+        }
+    }
+
+  assert (listcount (candidate_list) == 0);
+  list_free (candidate_list);
+  assert (ospf6_spf_candidate_count () == 0);
+
+  /* Clear thread timer */
+  o6a->spf_tree->t_spf_calculation = (struct thread *) NULL;
+
+  if (IS_OSPF6_DUMP_SPF)
+    {
+      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);
+    }
+
+  ospf6_route_table_thaw (o6a->table_topology);
+  return 0;
+}
+
+int
+ospf6_spf_calculation_thread (struct thread *t)
+{
+  struct ospf6_area *o6a;
+  struct timeval start, end, runtime, interval;
+
+  o6a = (struct ospf6_area *) THREAD_ARG (t);
+  if (! o6a)
+    {
+      zlog_err ("SPF: Thread error");
+      return -1;
+    }
+
+  if (! o6a->spf_tree)
+    {
+      zlog_err ("SPF: Can't find SPF Tree for area: %s", o6a->str);
+      return -1;
+    }
+
+  /* execute SPF calculation */
+  gettimeofday (&start, (struct timezone *) NULL);
+  ospf6_spf_calculation (o6a);
+  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)
+    {
+      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;
+    }
+
+  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;
+
+  return 0;
+}
+
+void
+ospf6_spf_database_hook (struct ospf6_lsa *old, struct ospf6_lsa *new)
+{
+  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)
+    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;
+}
+
+void
+ospf6_spftree_delete (struct ospf6_spftree *spf_tree)
+{
+  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;
+  int restnum;
+  listnode node;
+
+  vty_out (vty, "%s+-%s%s", prefix, v->string, VTY_NEWLINE);
+
+  if (listcount (v->path_list) == 0)
+    return;
+
+  psize = strlen (prefix) + 3;
+  p = malloc (psize);
+  if (!p)
+    {
+      vty_out (vty, "depth too long ...%s", VTY_NEWLINE);
+      return;
+    }
+
+  restnum = listcount (v->path_list);
+  for (node = listhead (v->path_list); node; nextnode (node))
+    {
+      --restnum;
+      snprintf (p, psize, "%s%s", prefix, (current_rest ? "| " : "  "));
+      ospf6_spftree_show (vty, p, restnum,
+                          (struct ospf6_vertex *) getdata (node));
+    }
+
+  free (p);
+}
+
+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"
+       "Displays spf tree\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);
+  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
+       OSPF6_STR
+       OSPF6_AREA_STR
+       OSPF6_AREA_ID_STR
+       OSPF6_SPF_STR
+       "Displays SPF topology table\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);
+}
+
+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
+       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
+       )
+
+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
+       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
+       )
+
+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
new file mode 100644
index 0000000..de50e94
--- /dev/null
+++ b/ospf6d/ospf6_spf.h
@@ -0,0 +1,105 @@
+/*
+ * 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_SPF_H
+#define OSPF6_SPF_H
+
+#include "prefix.h"
+
+/* Transit Vertex */
+struct ospf6_vertex
+{
+  /* type of this vertex */
+  u_int8_t type;
+
+  /* Vertex Identifier */
+  struct prefix_ls vertex_id;
+
+  /* Identifier String */
+  char string[128];
+
+  /* Associated LSA */
+  struct ospf6_lsa *lsa;
+
+  /* Distance from Root (Cost) */
+  u_int16_t distance;
+
+  /* Depth of this node */
+  u_char depth;
+
+  /* nexthops to this node */
+  struct linklist *nexthop_list;
+
+  /* upper nodes in spf tree */
+  list parent_list;
+
+  /* lower nodes in spf tree */
+  list path_list;
+
+  /* capability bits */
+  u_char capability_bits;
+
+  /* Optional capabilities */
+  u_char opt_capability[3];
+};
+
+#define OSPF6_VERTEX_TYPE_ROUTER  0x01
+#define OSPF6_VERTEX_TYPE_NETWORK 0x02
+
+struct ospf6_spftree
+{
+  /* calculation thread */
+  struct thread *t_spf_calculation;
+
+  /* root of this tree */
+  struct ospf6_vertex *root;
+
+  /* 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);
+
+void ospf6_spf_init ();
+
+#endif /* OSPF6_SPF_H */
+
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
new file mode 100644
index 0000000..a8a058f
--- /dev/null
+++ b/ospf6d/ospf6_top.c
@@ -0,0 +1,401 @@
+/*
+ * OSPFv3 Top Level Data Structure
+ * 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 "vty.h"
+#include "linklist.h"
+#include "prefix.h"
+#include "table.h"
+#include "thread.h"
+#include "command.h"
+
+#include "ospf6_hook.h"
+#include "ospf6_proto.h"
+#include "ospf6_prefix.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"
+
+#define HEADER_DEPENDENCY
+#include "ospf6d.h"
+#undef HEADER_DEPENDENCY
+
+/* global ospf6d variable */
+struct ospf6 *ospf6;
+
+static void
+ospf6_top_foreach_area (struct ospf6 *o6, void *arg, int val,
+                        void (*func) (void *, int, void *))
+{
+  listnode node;
+  struct ospf6_area *o6a;
+
+  for (node = listhead (o6->area_list); node; nextnode (node))
+    {
+      o6a = (struct ospf6_area *) getdata (node);
+      (*func) (arg, val, o6a);
+    }
+}
+
+static void
+ospf6_top_foreach_interface (struct ospf6 *o6, void *arg, int val,
+                             void (*func) (void *, int, void *))
+{
+  listnode node;
+  struct ospf6_area *o6a;
+
+  for (node = listhead (o6->area_list); node; nextnode (node))
+    {
+      o6a = (struct ospf6_area *) getdata (node);
+      (*o6a->foreach_if) (o6a, arg, val, func);
+    }
+}
+
+static void
+ospf6_top_foreach_neighbor (struct ospf6 *o6, void *arg, int val,
+                            void (*func) (void *, int, void *))
+{
+  listnode node;
+  struct ospf6_area *o6a;
+
+  for (node = listhead (o6->area_list); node; nextnode (node))
+    {
+      o6a = (struct ospf6_area *) getdata (node);
+      (*o6a->foreach_nei) (o6a, arg, val, func);
+    }
+}
+
+static int
+ospf6_top_maxage_remover (struct thread *t)
+{
+  int count;
+  struct ospf6 *o6 = (struct ospf6 *) THREAD_ARG (t);
+
+  o6->maxage_remover = (struct thread *) NULL;
+
+  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_maxage (o6->lsdb);
+  return 0;
+}
+
+void
+ospf6_top_schedule_maxage_remover (void *arg, int val, struct ospf6 *o6)
+{
+  if (o6->maxage_remover != NULL)
+    return;
+
+  o6->maxage_remover =
+    thread_add_event (master, ospf6_top_maxage_remover, o6, 0);
+}
+
+void
+ospf6_show (struct vty *vty)
+{
+  listnode n;
+  struct ospf6_area *area;
+  char id_string[32];
+  unsigned long day, hour, min, sec;
+  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);
+
+  /* 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);
+
+  vty_out (vty, " Supports only single TOS(TOS0) routes%s", VTY_NEWLINE);
+
+  /* Redistribute config */
+  ospf6_redistribute_show_config (vty);
+
+  /* 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
+
+  /* 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))
+    {
+      area = (struct ospf6_area *) getdata (n);
+      ospf6_area_show (vty, area);
+    }
+}
+
+void
+ospf6_statistics_show (struct vty *vty, struct ospf6 *o6)
+{
+  listnode node;
+  struct ospf6_area *o6a;
+  char running_time[128];
+  struct timeval now, 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)
+{
+  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);
+}
+
+DEFUN (show_ipv6_ospf6_route,
+       show_ipv6_ospf6_route_cmd,
+       "show ipv6 ospf6 route",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Routing table\n"
+       )
+{
+  OSPF6_CMD_CHECK_RUNNING ();
+  return ospf6_route_table_show (vty, argc, argv, ospf6->route_table);
+}
+
+ALIAS (show_ipv6_ospf6_route,
+       show_ipv6_ospf6_route_prefix_cmd,
+       "show ipv6 ospf6 route (X::X|detail)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Routing table\n"
+       "match IPv6 prefix\n"
+       )
+
+DEFUN (show_ipv6_ospf6_topology,
+       show_ipv6_ospf6_topology_cmd,
+       "show ipv6 ospf6 topology",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Inter Area topology information\n"
+       )
+{
+  OSPF6_CMD_CHECK_RUNNING ();
+  return ospf6_route_table_show (vty, argc, argv, ospf6->topology_table);
+}
+
+ALIAS (show_ipv6_ospf6_topology,
+       show_ipv6_ospf6_topology_router_cmd,
+       "show ipv6 ospf6 topology (A.B.C.D|<0-4294967295>|detail)",
+       SHOW_STR
+       IP6_STR
+       OSPF6_STR
+       "Inter Area topology information\n"
+       OSPF6_ROUTER_ID_STR
+       OSPF6_ROUTER_ID_STR
+       "Detailed information\n"
+       )
+
+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
+       )
+
+void
+ospf6_top_init ()
+{
+  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 (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);
+}
+
diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h
new file mode 100644
index 0000000..4c68756
--- /dev/null
+++ b/ospf6d/ospf6_top.h
@@ -0,0 +1,96 @@
+/*
+ * OSPFv3 Top Level Data Structure
+ * 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_TOP_H
+#define OSPF6_TOP_H
+
+#include "routemap.h"
+
+/* ospfv3 top level data structure */
+struct ospf6
+{
+  /* process id */
+  u_long process_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;
+
+  /* redistribute route-map */
+  struct
+  {
+    char *name;
+    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 *));
+
+  struct thread *maxage_remover;
+
+  list nexthop_list;
+};
+ 
+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 ();
+
+#endif /* OSPF6_TOP_H */
+
diff --git a/ospf6d/ospf6_types.h b/ospf6d/ospf6_types.h
new file mode 100644
index 0000000..574e2f3
--- /dev/null
+++ b/ospf6d/ospf6_types.h
@@ -0,0 +1,43 @@
+/*
+ * 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
new file mode 100644
index 0000000..7b8a8dc
--- /dev/null
+++ b/ospf6d/ospf6_zebra.c
@@ -0,0 +1,727 @@
+/*
+ * 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"
+
+#include "ospf6_interface.h"
+#include "ospf6_asbr.h"
+
+#include "ospf6_linklist.h"
+
+/* information about zebra. */
+struct zclient *zclient = NULL;
+
+/* redistribute function */
+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])
+    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)
+{
+  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",
+               ifp->name, ifp->ifindex, ifp->mtu);
+
+  ospf6_interface_if_add (ifp);
+
+  return 0;
+}
+
+int
+ospf6_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length)
+{
+#if 0
+  struct interface *ifp = NULL;
+
+  ifp = zebra_interface_delete_read (zclient->ibuf);
+
+  /* log */
+  if (IS_OSPF6_DUMP_ZEBRA)
+    zlog_info ("ZEBRA: I/F delete: %s index %d mtu %d",
+               ifp->name, ifp->ifindex, ifp->mtu);
+
+  ospf6_interface_if_del (ifp);
+#endif
+
+  return 0;
+}
+
+int
+ospf6_zebra_if_state_update (int command, struct zclient *zclient,
+                             zebra_size_t length)
+{
+  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",
+               ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+
+  ospf6_interface_state_update (ifp);
+  return 0;
+}
+
+int
+ospf6_zebra_if_address_update_add (int command, struct zclient *zclient,
+                               zebra_size_t length)
+{
+  struct connected *c;
+  char buf[128];
+
+  c = zebra_interface_address_add_read (zclient->ibuf);
+  if (c == NULL)
+    return 0;
+
+  if (IS_OSPF6_DUMP_ZEBRA)
+    zlog_info ("ZEBRA: I/F %s address add: %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);
+
+  return 0;
+}
+
+int
+ospf6_zebra_if_address_update_delete (int command, struct zclient *zclient,
+                               zebra_size_t length)
+{
+  struct connected *c;
+  char buf[128];
+
+  c = zebra_interface_address_delete_read (zclient->ibuf);
+  if (c == NULL)
+    return 0;
+
+  if (IS_OSPF6_DUMP_ZEBRA)
+    zlog_info ("ZEBRA: I/F %s address del: %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);
+
+  return 0;
+}
+
+
+
+const char *zebra_route_name[ZEBRA_ROUTE_MAX] =
+{
+  "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" };
+
+int
+ospf6_zebra_read_ipv6 (int command, struct zclient *zclient,
+                       zebra_size_t length)
+{
+  struct stream *s;
+  struct zapi_ipv6 api;
+  unsigned long ifindex;
+  struct prefix_ipv6 p;
+  struct in6_addr *nexthop;
+  char prefixstr[128], nexthopstr[128];
+
+  s = zclient->ibuf;
+  ifindex = 0;
+  nexthop = NULL;
+  memset (&api, 0, sizeof (api));
+
+  /* Type, flags, message. */
+  api.type = stream_getc (s);
+  api.flags = stream_getc (s);
+  api.message = stream_getc (s);
+
+  /* IPv6 prefix. */
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  p.prefixlen = stream_getc (s);
+  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+
+  /* Nexthop, ifindex, distance, metric. */
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      api.nexthop_num = stream_getc (s);
+      nexthop = (struct in6_addr *)
+        malloc (api.nexthop_num * sizeof (struct in6_addr));
+      stream_get (nexthop, s, api.nexthop_num * sizeof (struct in6_addr));
+    }
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
+    {
+      api.ifindex_num = stream_getc (s);
+      ifindex = stream_getl (s);
+    }
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
+    api.distance = stream_getc (s);
+  else
+    api.distance = 0;
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
+    api.metric = stream_getl (s);
+  else
+    api.metric = 0;
+
+  /* log */
+  if (IS_OSPF6_DUMP_ZEBRA)
+    {
+      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);
+      else
+	zlog_info ("ZEBRA: Receive remove %s route: %s nexthop:%s ifindex:%ld",
+		   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);
+  else
+    ospf6_asbr_route_remove (api.type, ifindex, (struct prefix *) &p);
+
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+    free (nexthop);
+
+  return 0;
+}
+
+
+DEFUN (show_zebra,
+       show_zebra_cmd,
+       "show zebra",
+       SHOW_STR
+       "Zebra information\n")
+{
+  int i;
+  if (!zclient)
+    vty_out (vty, "Not connected to zebra%s", VTY_NEWLINE);
+
+  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, "  redistribute default: %d%s", zclient->redist_default,
+           VTY_NEWLINE);
+  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);
+  return CMD_SUCCESS;
+}
+
+DEFUN (router_zebra,
+       router_zebra_cmd,
+       "router zebra",
+       "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);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_router_zebra,
+       no_router_zebra_cmd,
+       "no router zebra",
+       NO_STR
+       "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;
+}
+
+/* Zebra configuration write function. */
+int
+ospf6_zebra_config_write (struct vty *vty)
+{
+  if (! zclient->enable)
+    {
+      vty_out (vty, "no router zebra%s", VTY_NEWLINE);
+      return 1;
+    }
+  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;
+    }
+  return 0;
+}
+
+/* Zebra node structure. */
+struct cmd_node zebra_node =
+{
+  ZEBRA_NODE,
+  "%s(config-zebra)# ",
+};
+
+#define ADD    0
+#define CHANGE 1
+#define REMOVE 2
+
+static void
+ospf6_zebra_route_update (int type, struct ospf6_route_req *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;
+  struct in6_addr **nexthops;
+  unsigned int *ifindexes;
+  struct prefix_ipv6 *p;
+  int i, ret = 0;
+
+  if (IS_OSPF6_DUMP_ZEBRA)
+    {
+      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);
+    }
+
+  if (zclient->sock < 0)
+    {
+      if (IS_OSPF6_DUMP_ZEBRA)
+        zlog_info ("ZEBRA:   failed: not connected to zebra");
+      return;
+    }
+
+  if (request->path.origin.adv_router == ospf6->router_id &&
+      (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");
+      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)))
+    {
+      /* this is not preferred best route, ignore */
+      if (IS_OSPF6_DUMP_ZEBRA)
+        zlog_info ("ZEBRA:   not best path, ignore");
+      return;
+    }
+
+  nexthop_list = linklist_create ();
+
+  /* for each nexthop */
+  for (ospf6_route_lookup (&route, &request->route.prefix, request->table);
+       ! ospf6_route_end (&route); ospf6_route_next (&route))
+    {
+      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);
+      return;
+    }
+
+  /* allocate memory for nexthop_list */
+  nexthops = XCALLOC (MTYPE_OSPF6_OTHER,
+                      nexthop_list->count * sizeof (struct in6_addr *));
+  if (! nexthops)
+    {
+      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);
+      return;
+    }
+
+  /* allocate memory for ifindex_list */
+  ifindexes = XCALLOC (MTYPE_OSPF6_OTHER,
+                       nexthop_list->count * sizeof (unsigned int));
+  if (! ifindexes)
+    {
+      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);
+      XFREE (MTYPE_OSPF6_OTHER, nexthops);
+      return;
+    }
+
+  i = 0;
+  for (linklist_head (nexthop_list, &node); ! linklist_end (&node);
+       linklist_next (&node))
+    {
+      nexthop = node.data;
+      if (IS_OSPF6_DUMP_ZEBRA)
+        {
+          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);
+        }
+      nexthops[i] = &nexthop->address;
+      ifindexes[i] = nexthop->ifindex;
+      i++;
+    }
+
+  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 = nexthops;
+  api.ifindex_num = nexthop_list->count;
+  api.ifindex = ifindexes;
+
+  p = (struct prefix_ipv6 *) &request->route.prefix;
+  if (type == REMOVE && nexthop_list->count == 1)
+    ret = zapi_ipv6_delete (zclient, p, &api);
+  else
+    ret = zapi_ipv6_add (zclient, p, &api);
+
+  if (ret < 0)
+    zlog_err ("ZEBRA: zapi_ipv6_add () failed: %s", 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);
+
+  return;
+}
+
+void
+ospf6_zebra_route_update_add (struct ospf6_route_req *request)
+{
+  ospf6_zebra_route_update (ADD, request);
+}
+
+void
+ospf6_zebra_route_update_remove (struct ospf6_route_req *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 (! node || ! node->info)
+        continue;
+      ospf6_zebra_route_update_add (node->info);
+    }
+}
+
+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");
+
+  zclient->redist[ZEBRA_ROUTE_OSPF6] = 1;
+
+  /* set zebra route table */
+  ospf6_zebra_redistribute_ospf6 ();
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_redistribute_ospf6,
+       no_redistribute_ospf6_cmd,
+       "no redistribute ospf6",
+       NO_STR
+       "Redistribute control\n"
+       "OSPF6 route\n")
+{
+  /* log */
+  if (IS_OSPF6_DUMP_CONFIG)
+    zlog_info ("Config: no redistribute ospf6");
+
+  zclient->redist[ZEBRA_ROUTE_OSPF6] = 0;
+
+  if (! ospf6)
+    return CMD_SUCCESS;
+
+  /* clean up zebra route table */
+  ospf6_zebra_no_redistribute_ospf6 ();
+
+  ospf6_route_hook_unregister (ospf6_zebra_route_update_add,
+                               ospf6_zebra_route_update_add,
+                               ospf6_zebra_route_update_remove,
+                               ospf6->route_table);
+
+  return CMD_SUCCESS;
+}
+
+void
+ospf6_zebra_init ()
+{
+  /* Allocate zebra structure. */
+  zclient = zclient_new ();
+  zclient_init (zclient, ZEBRA_ROUTE_OSPF6);
+  zclient->interface_add = ospf6_zebra_if_add;
+  zclient->interface_delete = ospf6_zebra_if_del;
+  zclient->interface_up = ospf6_zebra_if_state_update;
+  zclient->interface_down = ospf6_zebra_if_state_update;
+  zclient->interface_address_add = ospf6_zebra_if_address_update_add;
+  zclient->interface_address_delete = ospf6_zebra_if_address_update_delete;
+  zclient->ipv4_route_add = NULL;
+  zclient->ipv4_route_delete = NULL;
+  zclient->ipv6_route_add = ospf6_zebra_read_ipv6;
+  zclient->ipv6_route_delete = ospf6_zebra_read_ipv6;
+
+  /* redistribute connected route by default */
+  /* ospf6_zebra_redistribute (ZEBRA_ROUTE_CONNECT); */
+
+  /* Install zebra node. */
+  install_node (&zebra_node, ospf6_zebra_config_write);
+
+  /* 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 ()
+{
+  zclient_stop (zclient);
+  zclient_free (zclient);
+  zclient = (struct zclient *) NULL;
+}
+
diff --git a/ospf6d/ospf6_zebra.h b/ospf6d/ospf6_zebra.h
new file mode 100644
index 0000000..d86b2db
--- /dev/null
+++ b/ospf6d/ospf6_zebra.h
@@ -0,0 +1,46 @@
+/*
+ * 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_ZEBRA_H
+#define OSPF6_ZEBRA_H
+
+extern struct zclient *zclient;
+
+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 *); 
+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);
+
+#endif /*OSPF6_ZEBRA_H*/
+
diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c
new file mode 100644
index 0000000..dbe7a88
--- /dev/null
+++ b/ospf6d/ospf6d.c
@@ -0,0 +1,826 @@
+/*
+ * 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"
+
+#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;
+
+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)
+{
+  long usec, movedown = 0;
+
+  if (t1->tv_sec < t2->tv_sec ||
+      (t1->tv_sec == t2->tv_sec && t1->tv_usec < t2->tv_usec))
+    {
+      result->tv_sec = 0;
+      result->tv_usec = 0;
+      return;
+    }
+
+  if (t1->tv_usec < t2->tv_usec)
+    {
+      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;
+    }
+
+  movedown = t1->tv_sec % by;
+  result->tv_sec = t1->tv_sec / by;
+  result->tv_usec = (t1->tv_usec + movedown * TIMER_SEC_MICRO) / by;
+}
+
+void
+ospf6_timeval_decode (const struct timeval *t, long *dayp, long *hourp,
+                      long *minp, long *secp, long *msecp, long *usecp)
+{
+  long day, hour, min, sec, msec, usec, left;
+
+  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 (dayp) *dayp = day;
+  if (hourp) *hourp = hour;
+  if (minp) *minp = min;
+  if (secp) *secp = sec;
+  if (msecp) *msecp = msec;
+  if (usecp) *usecp = usec;
+}
+
+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")
+{
+  vty_out (vty, "Zebra OSPF6d Version: %s%s",
+           ospf6_daemon_version, VTY_NEWLINE);
+
+  return CMD_SUCCESS;
+}
+
+/* start ospf6 */
+DEFUN (router_ospf6,
+       router_ospf6_cmd,
+       "router ospf6",
+       OSPF6_ROUTER_STR
+       OSPF6_STR)
+{
+  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 (router_id,
+       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;
+}
+
+int
+ospf6_interface_bind_area (struct vty *vty,
+                           char *if_name, char *area_name,
+                           char *plist_name, int passive)
+{
+  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 (interface_area_plist,
+       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 (interface_area_plist_passive,
+       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 (interface_area,
+       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 (interface_area_passive,
+       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_interface_area,
+       no_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 (area_range,
+       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 (passive_interface,
+       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_passive_interface,
+       no_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, ZEBRA_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);
+        }
+    }
+  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_init ()
+{
+  /* Install ospf6 top node. */
+  install_node (&ospf6_node, ospf6_config_write);
+
+  install_element (VIEW_NODE, &show_ipv6_ospf6_cmd);
+  install_element (VIEW_NODE, &show_version_ospf6_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_ospf6_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);
+#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, &router_id_cmd);
+  install_element (OSPF6_NODE, &interface_area_cmd);
+  install_element (OSPF6_NODE, &interface_area_passive_cmd);
+  install_element (OSPF6_NODE, &interface_area_plist_cmd);
+  install_element (OSPF6_NODE, &interface_area_plist_passive_cmd);
+  install_element (OSPF6_NODE, &no_interface_area_cmd);
+  install_element (OSPF6_NODE, &passive_interface_cmd);
+  install_element (OSPF6_NODE, &no_passive_interface_cmd);
+  install_element (OSPF6_NODE, &area_range_cmd);
+
+  /* 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 ();
+
+  ospf6_top_init ();
+  ospf6_area_init ();
+  ospf6_interface_init ();
+  ospf6_neighbor_init ();
+  ospf6_zebra_init ();
+
+  ospf6_routemap_init ();
+  ospf6_lsdb_init ();
+
+  ospf6_spf_init ();
+
+  ospf6_intra_init ();
+  ospf6_abr_init ();
+  ospf6_asbr_init ();
+}
+
+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
new file mode 100644
index 0000000..71972f5
--- /dev/null
+++ b/ospf6d/ospf6d.conf.sample
@@ -0,0 +1,54 @@
+!
+! Zebra configuration saved from vty
+!   2000/05/11 02:09:37
+!
+hostname ospf6d@yasu3380
+password zebra
+log file /var/log/zebra-ospf6d.log
+log stdout
+!
+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
+!
+interface ed0
+ 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 transmit-delay 1
+ ipv6 ospf6 instance-id 0
+!
+interface lo0
+ 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 transmit-delay 1
+ ipv6 ospf6 instance-id 0
+!
+router ospf6
+ router-id 0.0.0.1
+ redistribute static route-map static-ospf6
+ interface ed0 area 0.0.0.0
+ interface lo0 area 0.0.0.0
+!
+ipv6 prefix-list hostroute seq 10 permit 3ffe:501:100c:4380::/60 le 128 ge 128
+!
+route-map static-ospf6 permit 50
+ match ipv6 address prefix-list hostroute
+ set metric-type type-2
+ set metric 30
+!
diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h
new file mode 100644
index 0000000..e0d310a
--- /dev/null
+++ b/ospf6d/ospf6d.h
@@ -0,0 +1,175 @@
+/*
+ * 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 OSPF6D_H
+#define OSPF6D_H
+
+#include <zebra.h>
+#include "linklist.h"
+
+#ifndef HEADER_DEPENDENCY
+/* Include other stuffs */
+#include "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.6o"
+
+#define AF_LINKSTATE  0xff
+
+/* 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
+#define OSPF6_VTYSH_PATH           "/tmp/.ospf6d"
+
+#ifdef INRIA_IPV6
+#ifndef IPV6_PKTINFO
+#define IPV6_PKTINFO IPV6_RECVPKTINFO
+#endif /* IPV6_PKTINFO */
+#endif /* INRIA_IPV6 */
+
+/* Historycal for KAME.  */
+#ifndef IPV6_JOIN_GROUP
+#ifdef IPV6_ADD_MEMBERSHIP
+#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
+#endif /* IPV6_ADD_MEMBERSHIP. */
+#ifdef IPV6_JOIN_MEMBERSHIP
+#define IPV6_JOIN_GROUP  IPV6_JOIN_MEMBERSHIP
+#endif /* IPV6_JOIN_MEMBERSHIP. */
+#endif /* ! IPV6_JOIN_GROUP*/
+
+#ifndef IPV6_LEAVE_GROUP
+#ifdef IPV6_DROP_MEMBERSHIP
+#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
+#endif /* IPV6_DROP_MEMBERSHIP */
+#endif /* ! IPV6_LEAVE_GROUP */
+
+#define OSPF6_CMD_CHECK_RUNNING() \
+  if (ospf6 == NULL) \
+    { \
+      vty_out (vty, "OSPFv3 is not running%s", VTY_NEWLINE); \
+      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);
+
+void
+ospf6_count_state (void *arg, int val, void *obj);
+
+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 */
+