Initial revision
diff --git a/lib/.cvsignore b/lib/.cvsignore
new file mode 100644
index 0000000..051b8e4
--- /dev/null
+++ b/lib/.cvsignore
@@ -0,0 +1,4 @@
+Makefile
+*.o
+version.c
+.deps
diff --git a/lib/ChangeLog b/lib/ChangeLog
new file mode 100644
index 0000000..b4d0ae1
--- /dev/null
+++ b/lib/ChangeLog
@@ -0,0 +1,1926 @@
+2002-09-28  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+	* vty.c (vty_flush): One line more on vty.
+
+2002-09-27  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+	* vector.c (vector_lookup): Add new function.
+
+2002-08-19  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+	* thread.c (timeval_adjust): Fix unconditional crush due to
+	FreeBSD's select() system call timeval value check.
+
+2002-07-07  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+	* zebra-0.93 released.
+
+2002-06-21  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+	* if.c (ifc_pointopoint): Add ifc_pointopoint() accoding to Frank
+	van Maarseveen's suggestion.
+
+2002-06-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c: Change bcopy() to memcpy().
+
+2001-12-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (config_password): Fix host.password clear bug.
+	Reported by Wang Jian <lark@linux.net.cn>.
+
+2001-08-29  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+	* thread.c (thread_should_yield): New function to check thread
+	should yeild it's execution to other thread.  Suggested by: Rick
+	Payne <rickp@ayrnetworks.com>
+
+2001-08-20  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+	* thread.c (thread_timer_cmp): Rewrite function.
+
+	* hash.c: Add hash_get().  Change hash_pull() to hash_release().
+
+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-12  Akihiro Mizutani <mizutani@dml.com>
+
+	* prefix.c (netmask_str2prefix_str): Convert "1.1.0.0 255.255.0.0"
+	string to "1.1.0.0/16".
+
+2001-08-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* filter.c (access_list_lookup): access_list_lookup's first
+	argument is changed from address family to AFI.
+
+	* plist.c: (prefix_list_lookup): Likewise.
+
+2001-07-27  Akihiro Mizutani <mizutani@dml.com>
+
+	* plist.c: ge and le display order is changed.  Old compatible
+	rule (len <= ge-value <= le-value) is removed.
+
+2001-07-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* prefix.h: Temporary fix for alignment of prefix problem.
+
+2001-06-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* prefix.h (struct prefix): Remove safi and padding field.
+	(struct prefix_ipv4): Likewise.
+	(struct prefix_ipv6): Likewise.
+	(struct prefix_ls): Likewise.
+	(struct prefix_rd): Likewise.
+
+	* command.h (enum node_type): Preparation for BGP new config.
+
+	* vty.c (vty_end_config): Likewise.
+
+2001-06-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* routemap.c (route_map_rule_delete): Call func_free when
+	route-map rule is deleted.
+
+2001-06-14  "Akihiro Mizutani" <mizutani@dml.com>
+
+	* routemap.c (route_map_index_lookup): Prevent to use deny and
+	permit for same route-map sequence.
+
+2001-04-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (vty_read_config): Fix warning.
+
+2001-03-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (IPV6_PREFIX_STR): Add '.' and '%' for IPv6 address
+	strings.
+
+2001-03-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra.h (_XPG4_2): Define _XPG4_2 and __EXTENSIONS__ for
+	CMSG_FIRSTHDR.
+
+2001-03-07  Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+	* zebra.h (struct in_pktinfo): structure in_pktinfo declaration.
+
+2001-02-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* memory.c (memory_list_lib): Add MTYPE_NEXTHOP for "show memory
+	lib" member.
+
+2001-02-13  Matthew Grant <grantma@anathoth.gen.nz>
+
+	* vty.c (vty_read_config): Revert check of integrate_default when
+	VTYSH is defined.
+
+2001-02-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (vty_read_config): Do not check integrate_default.  That
+	should be used only by vtysh.
+
+2001-02-08  Matthew Grant <grantma@anathoth.gen.nz>
+
+	* vty.c (vty_serv_un): Set umask 0077.
+	(vty_read_config): Stat for vtysh Zebra.conf, if found startup and
+	wait for boot configuration.
+
+	* if.c (if_lookup_address): Make it smart implementation.
+
+	* sockopt.c (setsockopt_multicast_ipv4): Set up a multicast socket
+	options for IPv4 This is here so that people only have to do their
+	OS multicast mess in one place rather than all through zebra,
+	ospfd, and ripd .
+
+2001-02-04  Akihiro Mizutani <mizutani@dml.com>
+
+	* plist.c (vty_prefix_list_install): Even when argument is
+	invalid, new memory is allocated.  Now memory allocation is done
+	after argument check.
+
+2001-02-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra-0.91 is released.
+
+2001-01-31  Akihiro Mizutani <mizutani@dml.com>
+
+	* vty.c (vty_login): Add vty login command.
+
+2001-01-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (vty_reset): Close accept socket.
+
+2001-01-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* memory.h (enum): MTYPE_ATTR_TRANSIT is added for unknown transit
+	attribute.
+
+2001-01-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zclient.c (zebra_interface_address_add_read): Fetch interface
+	address flag.
+	(zebra_interface_address_delete_read): Likewise.
+
+2001-01-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* table.c (route_node_match_ipv4): Utility function for IPv4
+	address lookup.
+	(route_node_match_ipv6): Utility function for IPv4 address lookup.
+
+2001-01-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if.c: Delete RIP_API part until new implementation comes out.
+
+2001-01-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* hash.h (struct Hash): Rename alloc to count.  Change type to
+	unsigned long.
+
+	* stream.c (stream_getc_from): New function.
+	(stream_getw_from): Likewise.
+
+	* zebra.h (ZEBRA_FLAG_STATIC): Add new flag for persistent route.
+
+2001-01-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* flap.c: File is removed.
+
+	* flap.c: Likewise.
+
+	* roken.h: Likewise.
+
+	* buffer.c (buffer_new): Remove type option to buffer_new().
+
+2001-01-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zclient.c (zapi_ipv4_delete): Remove OLD_RIB part.
+
+2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra-0.90 is released.
+
+	* command.c: Update Copyright year.
+
+2001-01-09  Matthew Grant <grantma@anathoth.gen.nz>
+
+	* if.c (if_create): Register connected_free() function for
+	deletion.
+	(if_delete): Free connected information when the interface is
+	deleted.
+	(if_lookup_by_index): Fix argument type from int to unsigned int.
+	(connected_add): Keep list in order if old info found, essential
+	for repeatable operation in some daemons.
+
+2001-01-09  endo@suri.co.jp (Masahiko Endo)
+
+	* vty.c (vty_flush): When vty->statis is VTY_CLOSE do not add vty
+	read thread.
+
+2001-01-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* filter.c (access_list_delete): Access-list name is not freed.
+
+	* plist.c (prefix_list_delete): Prefix-list name is not freed.
+
+2000-12-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zclient.c (zclient_start): Change to use UNIX domain
+	socket for zebra communication.
+
+	* vector.c (vector_init): vector_alloc and vector_data_alloc is
+	removed.  All memory allocation count should be maintained by
+	XMALLOC and XFREE macros.
+
+2000-12-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra.h (ZEBRA_NEXTHOP_IFINDEX): Define ZEBRA_NEXTHOP_* values.
+
+2000-12-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra.h (ZEBRA_ERR_RTEXIST): Make zebra error code to negative
+	value.
+
+2000-12-25  "Wataru Uno" <wataru@po.ntts.co.jp>
+
+	* vty.c (vtysh_read): Don't allocate new buffer because buffer is
+	allocated in vty_new ().
+
+2000-12-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* memory.h (enum): Add MTYPE_AS_FILTER_STR.
+
+	* command.c (config_write_terminal): Display "end" at the end of
+	configuration.
+
+	* plist.c (vty_prefix_list_install): Use AF_INET to determine
+	lenum length.
+
+2000-12-13  "Wataru Uno" <wataru@po.ntts.co.jp>
+
+	* buffer.c (buffer_flush_vty): If IOV_MAX defined in the System,
+	then all lines write by IOV_MAX.
+
+2000-12-12  Michael Rozhavsky <mrozhavsky@opticalaccess.com>
+
+	* command.c (config_write_file): Robust method for writing
+	configuration file and recover from backing up config file.
+
+2000-11-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* smux.c (smux_connect): More fail check.
+	(smux_trap): When SMUX connection is not established, do nothing.
+
+2000-11-28  Gleb Natapov <gleb@nbase.co.il>
+
+	* thread.c (thread_fetch): Execut event list first.  Old event
+	list is renamed to ready list.  With this change, event thread is
+	executed before any other thread.
+
+	* thread.h (struct thread_master): Add ready list.
+
+2000-11-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* linklist.c (listnode_add_after): Add node right after the
+	listnode pointer.
+
+2000-11-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* smux.h: Pass struct variable to WriteMethod.
+
+2000-11-25  Frank van Maarseveen <F.vanMaarseveen@inter.NL.net>
+
+	* if.c (if_lookup_address): When looking up interface with IP
+	address, Sometimes multiple interfaces will match.  Now PtP
+	interfaces prevail in such a case which seem the right thing to
+	do: There will probably also be host routes which usually prevail
+	over network routes.
+
+2000-11-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* smux.c (smux_trap): SMUX trap implementation.
+
+2000-11-19  Akihiro Mizutani <mizutani@dml.com>
+
+	* plist.c: Add automatic conversion function of an old rule. 
+	ex.) 10.0.0.0/8 ge 8 -> 10.0.0.0/8 le 32
+
+2000-11-16  Yon Uriarte <ukl2@rz.uni-karlsruhe.de>
+
+	* zclient.c (zebra_interface_add_read): Read hardware address when
+	hw_addr_len is greater than 0.
+
+2000-11-15  Akihiro Mizutani <mizutani@dml.com>
+
+	* plist.c: The rule of "len <= ge-value <= le-value" 
+	was changed to "len < ge-value <= le-value".
+
+2000-11-09  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* memory.[ch]: Added #define and functions for ospf6d.
+
+	* log.[ch]: some platform says that the data of used va_list
+	is undefined. Changed to hold list of va_list for each
+	vsnprintf.
+
+2000-11-07  Rick Payne <rickp@rossfell.co.uk>
+
+	* memory.h (enum): Add MTYPE_COMMUNITY_REGEXP.
+
+2000-11-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (config_exit): Fix bug of missing break after case
+	BGP_VPNV4_NODE.
+
+2000-10-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vector.c (vector_unset): Check i is not nevative.
+
+2000-10-24  Arkadiusz Miskiewicz <misiek@pld.org.pl>
+
+	* smux.c (smux_sock): Set terminating '\0'.  Check address family.
+
+	* vty.c (vty_serv_sock_addrinfo): Set terminating '\0'. Use
+	gai_strerror.  Check address family.
+
+2000-10-23  Jochen Friedrich <jochen@scram.de>
+
+	* smux.c: Use linklist rather than vector.
+	(smux_getnext): A SMUX subagent has to behave as if it manages the
+	whole SNMP MIB tree itself. It's the duty of the master agent to
+	collect the best answer and return it to the manager. See RFC 1227
+	chapter 3.1.6 for the glory details :-). ucd-snmp really behaves
+	bad here as it actually might ask multiple times for the same
+	GETNEXT request as it throws away the answer when it expects it in
+	a different subtree and might come back later with the very same
+	request.
+
+2000-10-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (cmd_init): Log related command are only installed for
+	terminal mode.
+
+2000-10-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* Makefile.am (libzebra_a_SOURCES): Remove duplicated buffer.c.
+
+	* zebra.h: Remove #warn directive.
+
+2000-10-20  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* keychain.c (keychain_init): Register "key chain" command to
+	KEYCHAIN_NODE and KEYCHAIN_KEY_NODE.
+
+	* vty.c (vty_end_config): Fix missing vty_cinfig_unlock for other
+	CONFIG_NODE.
+
+	* command.c (config_end): Likewise.
+
+	* keychain.c (keychain_get): Key is sorted by it's identifier
+	value.
+
+2000-10-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* linklist.c (list_delete_all_node): Call delete function if it is
+	defined.
+
+	* command.c (cmd_execute_command_strict): Add modification for
+	vtysh.
+	(cmd_execute_command_strict): Remove first argument cmdvec because
+	it is global varibale in command.c.
+
+2000-10-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (cmd_init): Install
+	copy_runningconfig_startupconfig_cmd only in terminal mode.
+
+	* linklist.c (list_delete_node): Simplify the function.
+	(listnode_lookup): Renamed from list_lookup_node.
+
+2000-10-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* stream.h: Undef stream_read and stream_write without
+	parenthesis.
+
+	* newlist.c: File removed.
+
+	* newlist.h: Likewise.
+
+	* linklist.c (list_new): Remove list_init().  To allocate new
+	linked list, please use list_new().
+	(listnode_add): Remove list_add_node().  To add new node to linked
+	list, please use listnode_add().
+	(list_delete_by_val): Revemove fucntion.
+
+2000-10-16  Nobuaki Tanaka <nobby@po.ntts.co.jp>
+
+	* table.c (route_table_free): Reimplement route_table_free().
+
+2000-10-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* keychain.c (keychain_get): Register key_delete_func to key
+	list's delete function.  Use linklist.c instead of newlist.c.
+
+2000-10-04  Akihiro Mizutani <mizutani@dml.com>
+
+	* filter.c (access_list_remark): Add access-list's remark command.
+	(no_access_list): "no access-list 100 permit any" error message
+	bug is fixed.
+
+2000-10-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* memory.h (enum): Add MTYPE_SOCKUNION.
+
+2000-10-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra-0.89 is released.
+
+2000-10-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* linklist.c (list_add_node_head): Delete unused function.
+	(list_add_node_tail): Likewise.
+
+2000-09-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* stream.c (stream_read_unblock): Add new function for unblocking
+	read.
+
+2000-09-26  Jochen Friedrich <jochen@nwe.de>
+
+	* smux.c (smux_register): Fix bug of can't register more than one
+	MIB with SMUX.
+
+2000-09-26  Makoto Otsuka <otsuka@inl.ntts.co.jp>
+
+	* vty.c (vty_close): Fix memory leak of sb_buffer.
+	(vty_new): Likewise.
+
+2000-09-21  steve@Watt.COM (Steve Watt)
+
+	* log.h: Do not declare zlog_priority[0] variable.
+
+2000-09-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* linklist.h (struct _list ): Add member cmp for compare function.
+	(struct _list ): Member up is deleted
+
+2000-09-12  David Lipovkov <dlipovkov@OpticalAccess.com>
+
+	* if.c: Include RIP_API header when RIP API is enabled.
+
+2000-09-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* prefix.c (prefix_free): Siplify prefix_free().
+
+	* keychain.c (key_match_for_accept): strncmp check bug is fixed.
+
+2000-09-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra.h: Merge roken.h into zebra.h.
+
+2000-09-05  Akihiro Mizutani <mizutani@dml.com>
+
+	* routemap.c (route_map_init_vty): Install route-map command to
+	RMAP_NODE.
+
+2000-08-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* thread.c (thread_get_id): Remove pthread related garbage.
+
+	* command.h (struct host): Likewise.
+
+	* zebra.h: Likewise.
+
+2000-08-20  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.h (node_type ): Add AAA node for authentication.
+
+	* vty.c (vty_close): Do not close stdout.
+
+2000-08-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (vty_init_vtysh): Added for vtysh.
+
+	* distribute.c (districute_list_prefix_all): Interface independent
+	filter can be set.
+	(distribute_list_all): Likewise.
+	(config_show_distribute): Display current distribute-list status
+	for "show ip protocols".
+
+2000-08-18  Akihiro Mizutani <mizutani@dml.com>
+
+	* command.c (config_terminal_no_length): no terminal monitor ->
+	terminal no monitor
+	(cmd_init): Do not install service_terminal_length_cmd into
+	ENABLE_NODE.
+
+	* vty.c (terminal_no_monitor): no terminal length -> terminal no
+	length.
+
+2000-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra-0.88 is released.
+
+2000-08-17  Magnus Ahltorp <ahltorp@nada.kth.se>
+
+	* vty.h (struct vty ): Add iac_sb_in_progress and sb_buffer for
+	better IAC handling.
+
+	* vty.c (vty_telnet_option): Change telnet option handling.
+
+2000-08-15  Gleb Natapov <gleb@nbase.co.il>
+
+	* zclient.c (zclient_redistribute_unset):  New function added.
+
+2000-08-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zclient.c (zebra_interface_add_read): Change ifindex restore
+	size from two octet to four.
+	(zebra_interface_state_read): Likewise.
+	(zebra_interface_address_add_read): Likewise.
+
+2000-08-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (vty_event): Use vector_set_index() instead of
+	vector_set().
+
+2000-08-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra.h (ZEBRA_XXX_DISTANCE_DEFAULT): Define Default
+	Administrative Distance of each protocol.
+
+2000-08-07  Matthew Grant <grantma@anathoth.gen.nz>
+
+	* if.h (struct interface ): Add new member bandwidth to struct
+	interface.
+
+	* zclient.c (zebra_interface_add_read): Fetch bandwidth value.
+	(zebra_interface_state_read): Likewise.
+
+2000-08-07  Gleb Natapov <gleb@nbase.co.il>
+
+	* routemap.c (route_map_event_hook): New hook route_map_event_hook
+	is added.  This hook is called when route-map is changed. The
+	parameters passed to the hook are 'event' and 'route-map name'
+
+	* routemap.h: Add prototype for route_map_event_hook().
+
+2000-08-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zclient.c (zebra_ipv4_route): zebra_ipv4_route(),
+	zebra_ipv4_add(), zebra_ipv4_delete() are removed.
+
+	* routemap.c (route_map_empty): Add new function.
+	(route_map_delete): Use route_map_index_delete() instead of
+	route_map_index_free().
+	(route_map_index_free): Function removed.
+
+2000-08-06  Gleb Natapov <gleb@nbase.co.il>
+
+	* routemap.c (route_map_index_delete): Add check for route-map is
+	empty or not.
+
+2000-08-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zclient.c (zebra_ipv4_add): Change socket arguemnt with struct
+	zclient.
+
+2000-08-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zclient.h (struct zebra): Add obuf for output buffer.
+
+	* if.c: Remove #ifdef NRL enclosing if_nametoindex() and
+	if_indextoname().
+
+2000-08-02  David Lipovkov <davidl@nbase.co.il>
+
+	* if.h (IF_PSEUDO_UNSET): IF_PSEUDO related macro added.
+	(IF_UNKNOWN_SET): IF_UNKNOWN related macro deleted.
+
+	* if.c (interface_pseudo): Add "pseudo" command to interface node.
+	(no_interface_pseudo): Add "no pseudo" command to interface node.
+
+	* zclient.c (zebra_interface_add_read): Set pseudo flag when it is
+	send from zebra.
+
+2000-08-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra.h (ZEBRA_IPV4_NEXTHOP_LOOKUP): Add new message.
+	(ZEBRA_IPV6_NEXTHOP_LOOKUP): Likewise.
+
+	* vty.c (vty_serv_un): Use AF_UNIX for backward compatibility.
+
+2000-07-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c: Use vector for VTY server thread listing instead of
+	single value.
+
+2000-07-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* keychain.c (no_key_chain): "no key chain WORD" command is added.
+
+2000-07-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (config_from_file): If command fail in
+	KEYCHAIN_KEY_NODE, down to KEYCHAIN_NODE.
+
+	* vty.h (struct vty ): Add index_sub member.
+
+2000-07-27  Akihiro Mizutani <mizutani@dml.com>
+
+	* if.c: Help strings updates.
+
+2000-07-11  Akihiro Mizutani <mizutani@dml.com>
+
+	* command.c (no_config_enable_password): Add "no enable password"
+	command.
+	(config_write_host): Display password string.
+
+	* routemap.c (route_map_delete_match): Add support for delete
+	match without argument.
+	(route_map_delete_set): Likewise.
+
+2000-07-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.h (node_type ): Change KEYCHAIN_NODE and
+	KEYCHAIN_KEY_NODE place just before INTERFACE_NODE.
+
+2000-07-09  Jochen Friedrich <jochen@scram.de>
+
+	* smux.c (config_write_smux): Fixes the option to override OID and
+	password for SMUX.
+
+2000-07-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.h (node_type ): Add SMUX_NODE for SMUX configuration.
+
+2000-07-09  Toshiaki Takada  <takada@zebra.org>
+
+	* command.c: Sort descvec command's help.
+
+	* vty.c (vty_describe_command): Display '<cr>' at the end of
+	descriptions.
+
+2000-07-05  Toshiaki Takada  <takada@zebra.org>
+
+	* command.c (cmd_ipv6_match), (cmd_ipv6_prefix_match):  Fix bug
+	treatment of double colon.
+
+2000-07-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zclient.h: Add zclient_redistribute_default_{set,unset}().
+
+	* keychain.c: New file for authentication key management.
+	* keychain.h: Likewise.
+	
+	* tcpfilter.c: New file for TCP/UDP base filtering using ipfw or
+	ipchains.
+	* tcpfilter.h: Likewise.
+	
+	* flap.h: New file for route flap dampening.
+	* flap.c: Likewise.
+
+2000-07-04  Toshiaki Takada <takada@zebra.org>
+
+	* filter.c (struct filter): Add exact flag.
+	(access_list): Add exact-match command.
+	(ipv6_access_list): Add exact-match command.
+	
+2000-07-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra.h (ZEBRA_REDISTRIBUTE_DEFAULT_ADD): New message for
+	request default route.
+
+2000-07-01  Hideaki YOSHIFUJI (吉藤英明) <yoshfuji@ecei.tohoku.ac.jp>
+
+	* smux.c: Add IPv6 smux connection code.
+
+2000-06-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (vty_complete_command): To cooperate readline library,
+	returned string is newly allocated.  So some match function case
+	need, free of memory.
+
+2000-06-12  Akihiro Mizutani <mizutani@dml.com>
+
+	* distribute.c: Fix help strings.
+
+2000-06-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (cmd_complete_command): Add check for vector_slot
+	(vline, index) is not NULL when calculating lcd.
+	(cmd_entry_function): First check variable arguemnt to prevent it
+	from completion.
+
+2000-06-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.h (struct vty ): Add output_count member for displaying
+	output route count.  Remove arugment arg from output_func because
+	the value is passed by vty argument.  Change output to output_rn.
+	Add output_clean function pointer member.  Add output_type member.
+
+2000-06-10  Toshiaki Takada <takada@zebra.org>
+
+	* command.c (show_startup_config): Add "show startup-config"
+	command.
+
+2000-06-06  Akihiro Mizutani <mizutani@dml.com>
+
+	* filter.c: Fix help strings.
+
+2000-06-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* prefix.h (struct prefix_rd): New prefix structure for routing
+	distinguisher.
+	(struct prefix): Add padding to every prefix structure.
+
+
+	* routemap.c (route_map_add_match): When completely same match
+	statement exists, don't duplicate it.
+
+2000-06-05  Akihiro Mizutani <mizutani@dml.com>
+
+	* routemap.c: Change NAME to WORD.
+
+	* plist.c: Fix help strings.
+
+2000-06-02  Akihiro Mizutani <mizutani@dml.com>
+
+	* routemap.c: Fix route-map help strings.
+
+2000-06-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (cmd_filter_by_completion): Fix CMD_VARARG treatment
+	to filter other non vararg commands.
+
+	* routemap.c (route_map_init_vty): Use install_default() for
+	install common commands into route-map node..
+
+2000-06-01  Akihiro Mizutani  <mizutani@dml.com>
+
+	* command.h (OSPF_STR):  Macro added.
+
+2000-05-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (cmd_complete_command): LCD completion must not modify
+	installed command string.
+
+	* plist.c (ipv6_prefix_list): Fix wrong syntax definition.  Change
+	X:X::X:X to X:X::X:X/M.
+
+2000-05-31  Toshiaki Takada  <takada@zebra.org>
+
+	* vty.c (show_history):  New defun added.
+
+2000-05-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.h (CMD_COMPLETE_LIST_MATCH): New define for completion
+	list.  CMD_COMPLETE_MATCH is used for LCD completion.
+
+	* vty.c (vty_complete_command): Matched string's LCD is completed.
+
+	* command.c (cmd_lcd): New function for calculate LCD of matched
+	strings.
+
+2000-05-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (install_default): config_write_terminal_cmd,
+	config_write_file_cmd, config_write_memory_cmd are added to
+	default node.
+
+	* memory.c (memory_init): Divide show memory command into each
+	sort.
+
+	* command.c (cmd_init): config_write_terminal_cmd,
+	config_write_file_cmd, config_write_memory_cmd are added to
+	CONFIG_NODE.
+
+	* routemap.c (route_map_index_free): New function.
+	(no_route_map_all): New DEFUN for "no route-map NAME".
+
+	* filter.c (no_access_list_all): New DEFUN for delete access-list
+	with NAME.
+	(no_ipv6_access_list_all): Likewise.
+
+2000-05-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* plist.c: Change IPV6_PREFIX to X:X::X:X.  When "any" is
+	specified, user can not use "ge" and "le" statement.
+
+2000-05-22  Thomas Molkenbur <tmo@datus.datus.com>
+
+	* routemap.c (route_map_add_set): Fix bug of next pointer missing.
+
+	* table.c (route_table_free): Like wise.
+
+2000-05-22  Toshiaki Takada  <takada@zebra.org>
+
+	* vty.c (vty_stop_input): Set history pointer to the latest one.
+
+	* vty.c (vty_hist_add): Do not add command line history when input
+	is as same as previous one.
+
+2000-05-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* memory.h (enum): Add MTYPE_ECOMMUNITY and MTYPE_ECOMMUNITY_VAL.
+
+2000-05-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.h (node_type ): Add BGP_VPNV4_NODE.
+
+2000-05-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (vtysh_accept): Add cast of struct sockaddr * to bind
+	argument.  Reported by: Vesselin Mladenov <mladenov@netbg.com>.
+
+	* filter.c (ipv6_access_list): Add IPv6 prefix example instead of
+	IPv4 example.  Reported by: Love <lha@s3.kth.se>.
+
+	* command.c (cmd_complete_command): Make it sure last element of
+	matchvec is NULL.  This fix problem which cause crush in
+	vty_complete_command().  Reported by: JINMEI Tatuya
+	<jinmei@isl.rdc.toshiba.co.jp>.
+
+2000-04-28  Love <lha@s3.kth.se>
+
+	* prefix.h (struct prefix): Add padding.
+
+2000-04-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (show_version): Update copyright year.
+
+2000-04-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* routemap.c (route_map_apply): When map is NULL, return deny.
+
+2000-04-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* filter.c (access_list_apply): When access is NULL, return deny.
+
+	* plist.c (prefix_list_apply): When plist is NULL, return deny.
+
+2000-04-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.h (node_type ): Change RDISC_NODE to IRDP_NODE.
+
+2000-04-18  Toshiaki Takada  <takada@zebra.org>
+
+	* filter.[ch] (access_list_add_hook), (access_list_delete_hook):
+	Add argument for hook function to give struct access_list *.
+
+2000-04-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* plist.c (prefix_list_entry_match): In case of le nor ge is
+	specified, exact match is performed.
+	(prefix_list_entry_match): Add any entry matching check.
+
+2000-04-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (exec_timeout): Separate timeout setting to minutes and
+	seconds.
+	(no_exec_timeout): Add "no exec-timeout" command.
+
+	* vty.h (VTY_TIMEOUT_DEFAULT): Change default value from 300 to
+	600.
+
+2000-03-31  Jochen Friedrich <jochen@scram.de>
+
+	* smux.h (SMUX_CLOSE): The SMUX_CLOSE PDU is implicit integer, so
+	it is a primitive encoding and not constructed.
+
+2000-03-28  Toshiaki Takada  <takada@zebra.org>
+
+	* memory.[ch] (enum): Add MTYPE_OSPF_EXTERNAL_INFO.
+
+2000-03-26  Love <lha@s3.kth.se>
+
+	* zclient.c (zclient_read): Add nbytes size check for
+	ZEBRA_HEADER_SIZE.  Check return value of steam_read ().
+
+2000-03-26  Rick Payne <rickp@rossfell.co.uk>
+
+	* routemap.c: Add flexible route-map commands such as on-match
+	next, on-match goto N.
+
+	* routemap.h: Likewise
+
+2000-03-23  Adrian Bool <aid@u.net.uk>
+
+	* command.c (config_log_trap): Add new command "log trap
+	PRIORITY".
+
+2000-03-14  Toshiaki Takada  <takada@zebra.org>
+
+	* memory.c (struct memory_list): Add Link List and Link Node
+	to view.
+	
+	* memory.h (enum): Remove MTYPE_OSPF_EXTERNAL_ROUTE.
+	
+2000-01-20  Hideto Yamakawa <hideto.yamakawa@soliton.co.jp>
+
+	* str.c (snprintf): Fix bug of calling sprintf instead of
+	vsprintf.
+
+2000-01-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* memory.h (enum): Add MTYPE_RIP_PEER.
+
+2000-01-15  Toshiaki Takada  <takada@zebra.org>
+
+	* memory.h (enum): Add MTYPE_OSPF_CRYPT_KEY.
+
+2000-01-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.h (node_type ): Add MASC_NODE for masc.
+
+2000-01-09  Wang Jianliang <wangjl@soim.net>
+
+	* routemap.c (route_map_index_add): When route_map_index is not
+	empty and insert new item at the head, it can cause core dump.
+	Fix "if (index == map->head)" to "if (point == map->head).
+	(route_map_add_set): If there is an old set command, override old
+	set command with new one.
+	(route_map_index_delete): Use while() instead of for for() for
+	logical correctness.
+
+1999-12-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* memory.h (enum): Add MTYPE_BGP_STATIC.
+
+1999-12-23  Alex Zinin <zinin@amt.ru>
+	* zebra.h, zclient.*: dynamic int up/down message
+	support
+
+1999-12-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* thread.c (thread_cancel_event): Add a function for clean up
+	events.
+
+1999-12-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* dropline.c: Delete file.
+	dropline.h: Linewise.	
+
+1999-12-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* filter.c (access_list_filter_delete): Wrong pointer
+	access->master was pointed out after access is freed.  I store
+	master value at the beginning of the function.
+
+1999-12-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (exec_timeout): Change of VTY timeout affect to current
+	VTY connection.
+	(vty_accept): Instead of immediate exit() return -1.
+
+1999-12-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (vty_configure_lock): Configuration lock function added.
+	Only one VTY can use CONFI_NODE at the same time.
+
+	* log.c: Delete zvlog_* functions.  Now zlog_* does the same
+	thing.
+
+	* log.c (log_init): Function removed.
+	(log_close): Likewise.
+	(log_flush): Likewise.
+	(log_open): Likewise.
+
+	* vty.c (terminal_monitor): Add new command.
+	(no_terminal_monitor): Likewise.
+
+	* log.c (old_log): Function removed.
+	(old_log2): Likewise.
+	(old_log_warn): Likewise.
+
+1999-12-04  Toshiaki Takada  <takada@zebra.org>
+
+	* command.c (cmd_ipv6_match): New function added.
+	(cmd_ipv6_prefix_match): Likewise.
+	
+1999-12-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (cmd_ipv6_match): 
+
+	* table.c: Delete #ifdef HAVE_MBGPV4.
+
+	* prefix.h (struct prefix): Add safi member.
+	(struct prefix_ipv4): Likewise.
+	(struct prefix_ipv6): Likewise.
+
+1999-12-04  Rumen Svobodnikov <rumen@linux.tu-varna.acad.bg>
+
+	* memory.c (struct mstat): Revert to support MEMORY_LOG.
+
+1999-11-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* version.h: Bump up to 0.81c for testing new kernel codes.
+
+1999-11-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* thread.h (struct thread): Pthread support is disabled all
+	platform.
+
+1999-11-21  Michael Handler <handler@sub-rosa.com>
+
+	* Include <limits.h> and <strings.h> under SUNOS_5.
+
+1999-11-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* sockunion.c (in6addr_cmp): Enclosed by #define HAVE_IPV6
+1999-11-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.h (node_type ): Add BGP_IPV4_NODE and BGP_IPV6_NODE.
+
+1999-11-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (disable): Add `disable' command.
+
+1999-11-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* plist.c (vty_prefix_list_install): Add any check.
+
+1999-11-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.h (node_type ): Add DUMP_NODE.
+
+1999-11-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* smux.c: Change default SMUX oid to compatible with gated.
+
+1999-10-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if_rmap.c: New file added.
+
+	* if_rmap.h: New file added.
+
+1999-10-29  Alex Zinin  <zinin@amt.ru>
+
+	* hash.c: add hash_free() function
+
+1999-10-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* hash.c (hash_clean): Add clean function.
+
+	* plist.c (prefix_list_reset): Add reset function.
+
+	* filter.c (access_list_reset): Add reset function.
+
+1999-10-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* client.c: Merged with zclient.c.
+	* client.h: Merged with zclient.h.
+
+1999-10-15  Jordan Mendelson <jordy@wserv.com>
+
+	* md5.c: Imported from GNU C Library.
+	* md5-gnu.h: Likewise.
+
+1999-10-15  Jochen Friedrich <jochen@scram.de>
+
+	* smux.c (smux_getresp_send): SMUX_GETRSP codes improvement.
+
+1999-10-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* smux.h: New file added.
+
+	* snmp.c: Rename to smux.c.
+
+1999-10-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (cmd_execute_command_strict): Filter ambious commands.
+	(cmd_filter_by_string): Change to return enum match_type.
+
+1999-10-01  Toshiaki Takada  <takada@zebra.org>
+
+	* vty.c (vty_describe_fold): New function which does VTY
+	description line fold.
+	* vty.c (vty_describe_command): Set description column.
+
+1999-09-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* plist.c (prefix_list_init_ipv4): VTY user interface is improved.
+
+1999-09-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (cmd_filter_by_string): Fix bug of CMD_IPV4 and
+	CMD_IPV4_PREFIX check.  Both return type must be exact_match.
+
+1999-09-24  Toshiaki Takada  <takada@zebra.org>
+
+	* command.c (cmd_filter_by_completion),
+	(is_cmd_ambiguous): Check IPv4 address, IPv4 prefix and range 
+	parameter matches range.
+
+1999-09-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* routemap.c (route_map_apply): Returm RM_DENYMATCH when no match
+	is performed.
+
+1999-09-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (vty_read): Control-C stop VTY_MORE mode.
+
+1999-09-20  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.h (node_type ): Add ACCESS_IPV6_NODE and
+	PREFIX_IPV6_NODE.
+
+	* distribute.h: New file added.
+
+	* command.h (node_type ): Delete DISTRIBUTE_NODE.
+
+1999-09-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (vty_terminate_all): New function added for reload
+	support.
+
+1999-09-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* memory.h (enum): Add new type MTYPE_OSPF_EXTERNAL_ROUTE.
+
+1999-08-31  Janos Farkas <chexum@shadow.banki.hu>
+
+	* vty.c (vty_read): Handle also 0x7f (alt-backspace), just like
+	esc-ctrl-h (delete word backwards).
+
+1999-08-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if.h: Add if_nametoindex for NRL.
+
+1999-08-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if.c (if_create): New function.
+
+1999-08-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* snmp.c: New file.
+
+1999-08-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* stream.c (stream_put): stream_memcpy () is changed to stream_put
+	().  stream_get () is added.
+
+1999-08-18  Toshiaki Takada  <takada@zebra.org>
+
+	* memory.h (enum): Add MTYPE_OSPF_LSA_DATA.
+	
+1999-08-18  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* table.c (route_table_finish): add function frees table.
+
+1999-08-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* memory.h (enum): Add MTYPE_RTADV_PREFIX.
+
+1999-08-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if.h (struct interface ): hw_address, hw_address_len added.
+
+1999-08-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if.h (struct interface ): Change structure member if_data to
+	info, index to ifindex.
+
+1999-08-08  Rick Payne <rickp@rossfell.co.uk>
+
+	* routemap.c: Multi protocol route-map modification.
+
+	* routemap.c (route_map_apply): Route match process bug is fixed.
+
+1999-08-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* thread.c (thread_fetch): When signal comes, goto retry point.
+
+1999-08-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* Makefile.am: Add sockopt.c and sockopt.h
+	* sockopt.c: New file.
+	* sockopt.h: New file.
+	
+1999-08-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* version.h (ZEBRA_VERSION): Release zebra-0.75
+
+1999-08-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* memory.h (enum): Add MTYPE_RIPNG_AGGREGATE.
+
+1999-07-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* sockunion.h: Add sockunion_getpeername ().
+
+1999-07-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* version.h: Release zebra-0.74
+
+1999-07-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.h (struct host): Delete lines from struct host.  Add
+	lines to struct vty.
+
+	* command.c: Delete `lines LINES'.  Terminal display line settings
+	should be done by `terminal length' command.
+
+1999-07-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* memory.h (enum): MTYPE_OSPF_PATH are added.
+
+1999-07-22  Toshiaki Takada  <takada@zebra.org>
+
+	* memory.h (enum): MTYPE_OSPF_NEXTHOP is added.
+
+1999-07-21  Toshiaki Takada  <takada@zebra.org>
+
+	* linklist.c (list_add_node_prev), (list_add_node_next),
+	(list_add_list): New function added.
+
+	* table.c (route_table_free): New function added.
+	
+1999-07-21  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* plist.c (config_write_prefix): Set write flag when configuration
+	is written.
+
+1999-07-15  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp> 
+
+	* prefix.c : prefix_cmp() added. change apply_mask() to
+	apply_mask_ipv4(), and new apply_mask() added.
+
+1999-07-14  Yasuhiro Ohara  <yasu@sfc.wide.ad.jp>
+
+	* prefix.c (prefix2str): append prefixlen.
+
+1999-07-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (config_terminal): Change "config terminal" to
+	"configure terminal".  Reported by Georg Hitsch
+	<georg@atnet.at>.
+	(config_terminal_length): `terminal length <0-512>' is added.  At
+	this moment this command is only usef for vty interface.
+	Suggested by Georg Hitsch <georg@atnet.at>.
+
+1999-07-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* routemap.c (rulecmp): Add wrapper function of strcmp.
+
+1999-07-08  Rick Payne <rickp@rossfell.co.uk>
+
+	* sockunion.c (inet_aton): Fix bug of inet_aton.
+
+1999-07-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* version.h (ZEBRA_VERSION): Start zebra-0.73
+
+1999-07-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* version.h: Bump up to 0.72.
+
+1999-07-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (install_default): New function for install default
+	commands to the node.
+
+	* memory.h (enum): MTYPE_NEXTHOP is added.
+
+1999-07-01    <kunihiro@zebra.org>
+
+	* command.c (no_banner_motd): `no banner motd' command added.
+
+1999-06-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* regex.c: Update to glibc-2.1.1's posix/regex.c
+
+	* regex-gnu.h: Update to glibc-2.1.1's posix/regex.h
+
+	* prefix.h (IPV4_ADDR_SAME): Macro added.
+	(IPV6_ADDR_SAME): Likewise.
+
+1999-06-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* memory.h (enum): Add MTYPE_OSPF_VERTEX
+
+	* version.h: Bump up to 0.71.
+
+	* vty.c (vty_serv_sock_addrinfo): Use addrinfo function to bind
+	VTY socket when IPv6 is enabled.
+
+1999-06-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (vty_serv_sock): Change vty_serv_sock determine which
+	address family to bind.
+
+	* command.c: Add quit command.
+
+1999-06-26  NOGUCHI kay <kay@dti.ad.jp>
+
+	* vty.c (vty_read_config): Fix bug of configuration file path
+	detection.
+
+1999-06-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* version.h: Bump up to 0.70.
+
+1999-06-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* buffer.h (GETL): Remove GETL macro.
+
+	* version.h: Bump up to 0.69.
+
+1999-06-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if.c (connected_add): Commented out connected_log.
+
+1999-06-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.h (struct cmd_element ): strvec and descvec is combined
+	into newstrvec.
+
+	* command.c (desc_make): Function removed.
+	(desc_next): Function removed.
+
+	* command.h (struct cmd_element ): docvec is removed from struct
+	cmd_element.
+
+1999-06-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (cmd_execute_command): Remove command NULL check.
+
+	* command.h (struct cmd_element ): Add newstrvec entry to struct
+	cmd_element.
+	(DEFUN2): DEFUN2 macro is removed.  DEFUN is extended to support
+	(a|b|c) statement.
+	(DESC): DESC macro is removed.
+
+	* vty.c (vty_complete_command): When return value is
+	CMD_ERR_NO_MATCH, don't display error message.
+
+1999-06-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* table.c (route_next_until): New function.
+
+	* version.h: Bump up to 0.68.
+
+1999-06-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (vty_close): Free vty->buf when vty is closed.
+
+	* memory.h (enum): Add MTYPE_COMMUNITY_ENTRY and
+	MTYPE_COMMUNITY_LIST.
+
+	* vty.h (struct vty ): Change buf from static length buffer to
+	variable length buffer.
+
+	* vty.c (vty_ensure): New function added.
+	
+1999-06-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.h (node_type ): Add COMMUNITY_LIST_NODE.
+
+	* command.c (config_enable_password): Freeing host.enable bug is
+	fixed.
+	(config_enable_password): Add argc count check.
+
+1999-05-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* version.h: Bump up to 0.67.
+
+1999-05-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (zencrypt): New function for encrypt password.
+
+	* command.h (struct host): Add password_encrypt and
+	enable_encrypt.
+
+1999-05-30  Jochen Friedrich <jochen@scram.de>
+
+	* command.h (struct host): New member encrypt is added for
+	encrypted password.
+
+1999-05-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c: Remove all_digit_check function.  Instead use all_digit.
+
+	* prefix.c (all_digit): New function for checking string is made
+	from digit character.
+
+1999-05-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* Makefile.am (libzebra_a_SOURCES): Add zclient.c.
+	(noinst_HEADERS): Add zclient.h
+
+	* zclient.[ch]: New file for zebra client routine.
+
+	* memory.h (enum): Add MTYPE_ZEBRA.
+
+1999-05-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* version.h (ZEBRA_VERSION): Update to 0.66.
+
+1999-05-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* buffer.h (GETC,GETW): Macro deleted.
+
+1999-05-15  Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+	* prefix.h (IPV4_NET0, IPV4_NET127): Macro added.
+
+1999-05-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (service_advanced_vty): New command added.
+	(no_service_advanced_vty): Likewise.
+
+1999-05-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (vty_auth): If advanced flag is set and enable password is
+	not set, directly login to the ENABLE_NODE.  This feature is
+	originally designed and implemented by Stephen R. van den Berg
+	<srb@cuci.nl>.
+
+	* command.h (host): Add advanced flag to struct host for advanced
+	vty terminal interface.
+
+	* version.h (ZEBRA_VERSION): Update to 0.65 for next beta release.
+
+1999-05-14  Stephen R. van den Berg <srb@cuci.nl>
+
+	* command.h (node_type ): Add TABLE_NODE.
+	
+	* vty.c (vty_telnet_option): Check host.lines value.
+
+	* command.c (config_lines): DEFUN for 'lines LINES' command.
+
+	* zebra.h: Include <sys/utsname.h> for uname().
+	(RT_TABLE_MAIN): Defined as 0 if OS does not support multiple
+	routing table.
+
+	* vty.c (vty_auth): Directly login to the ENABLE_NODE when enable
+	password is not set.
+	(vty_prompt): Get machine's hostname when hostname is not set.
+
+1999-05-11  James Willard <james@whispering.org>
+
+	* command.c (config_exit): Close connection when `exit' command is
+	executed at ENABLE_NODE.
+
+1999-05-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (vty_stop_input): `C-c' key change node to ENABLE_NODE.
+
+	* command.c (cmd_execute_command_strict): Matched command size
+	check added.
+	(cmd_make_desc_line): New function for DEFUN2.
+
+	* command.h (struct cmd_element ): Add descsize.
+
+1999-05-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.h (struct cmd_element ): Remame descvec to docvec.
+	(struct cmd_element ): Add descvec for new description system.
+
+	* command.c (desc_make): Check cmd->descvec.
+
+1999-05-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* memory.h (enum): Add MTYPE_CLUSTER, MTYPE_CLUSTER_VAL.
+
+1999-05-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* version.h (ZEBRA_VERSION): Bump up to 0.64 for next beta
+	release.
+
+1999-05-04  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+	* linklist.c (list_delete_all_node): bug fix. 
+	previous code loses current position when node
+	is deleted.
+
+1999-05-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.h (DESC): Macro added.
+	(struct cmd_element2): Delete struct cmd_element2.
+
+	* plist.c (prefix_list): Sequential number option check is added.
+
+1999-05-02  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+	* log.c (zvlog_{debug,info,notice,warn,err}): have been
+	added. now we can log both console and file, but still 
+	need some fix about config write.
+
+1999-05-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* log.c (zvlog_debug): Fix yasu's change.
+
+1999-05-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* plist.c (prefix_list): Fix typo.
+
+1999-04-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* Set version to 0.63 for first beta package.
+
+1999-04-27  Carlos Barcenilla <barce@frlp.utn.edu.ar>
+
+	* prefix.c (str2prefix_ipv4): Fix prefix length check.
+	(str2prefix_ipv6): Likewise.
+
+1999-04-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* memory.h (enum): Add MTPYE_PREFIX_LIST and
+	MTYPE_PREFIX_LIST_ENTRY.
+
+	* command.h (node_type ): Add PREFIX_NODE.
+
+1999-04-25  Carlos Barcenilla <barce@frlp.utn.edu.ar>
+
+	* command.c: ALIAS (config_write_memory_cmd) and ALIAS
+	(copy_runningconfig_startupconfig_cmd) is added.
+
+	* table.c (route_node_lookup): Unused match variable deletion.
+
+1999-04-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* Makefile.am (libzebra_a_SOURCES): plist.c added.
+	(noinst_HEADERS): plist.h added.
+
+	* plist.c, plist.h: New file added.
+
+	* memory.h (enum): Rename MTYPE_AS_PASN to MTYPE_AS_STR.
+	* memory.c: Likewise.
+
+1999-04-19  Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+	* command.c (show_version): `show version' command added.
+
+1999-04-19  Kunihiro Ishiguro <kunihiro@zebra.org>
+
+	* prefix.c (str2prefix_ipv6): Prefix length overflow check.
+
+1999-04-19  Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+	* prefix.c (str2prefix_ipv4): Prefix length overflow check.
+
+1999-04-19  Alex Bligh <amb@gxn.net>
+
+	* prefix.c (sockunion2hostprefix): Function added.
+	(sockunion2prefix): Address family was not set.  Now it is set.
+	
+	* vty.c: VTY access-class command is added.
+
+1999-04-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* memory.c: Change xmalloc to zmalloc.  xcalloc, xrealloc, xfree,
+	xstrdup are likewise.
+
+1999-04-18  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+	* thread.c: Add thread_execute for other routing daemon.
+	OSPF tasks need to be generated by "sheduled" and "executed".
+
+1999-04-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* buffer.c: Rewrite buffer_write and buffer_flush related
+	functions for fixing bugs.  Reason of the problem and fix is
+	suggested by Alex Bligh <amb@gxn.net>.
+	
+1999-04-12  Alex Bligh <amb@gxn.net>
+
+	* command.c (cmd_entry_function_descr): Added for variable
+	argument help display.
+
+1999-04-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* regex.c, regex-gnu.h: Imported from GNU sed-3.02 distribution.
+
+1999-03-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* stream.c: stream_fifo_free bug is fixed.
+
+1999-03-19  Toshiaki Takada  <takada@zebra.org>
+
+	* stream.c (stream_strncpy): Added for getting any length bytes
+	from stream.
+
+1999-03-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* version.h (ZEBRA_BUG_ADDRESS): New macro added.
+
+1999-03-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* buffer.c (buffer_flush_window): If ep is same as buffer's size
+	length and lp is overrun one octet.
+
+1999-03-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.h: add VTY's timeout function.
+
+1999-03-05    <kunihiro@zebra.org>
+
+	* command.h (node_type ): Add OSPF6_node.
+
+1999-03-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra.h: Check HAVE_SYS_SELECT_H when include <sys/select.h>
+
+1999-03-03  Jeroen Ruigrok/Asmodai <asmodai@wxs.nl>
+
+	* zebra.h: Include <net/if_var.h> if it exists.
+
+1999-03-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* getopt.[ch],getopt1.c: Sync with glibc-2.1.
+
+	* log.c (zlog): Tempolary ZLOG_STDOUT feature added.
+
+	* command.h: Include vector.h and vty.h
+
+1999-02-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* routemap.h (struct route_map_rule_cmd): Add prefix arguemnt.
+
+	* routemap.c (route_map_apply_index): Add prefix argument.
+	(route_map_apply): Likewise.
+
+	* memory.h (enum): Add MTYPE_ROUTE_MAP_COMPILED.
+
+	* stream.c: Add stream_fifo related functions.
+
+1999-02-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* daemon.c: Return integer value.  File descriptor close is added.
+
+	* memory.h (enum): add MTYPE_OSPF_LSA.
+
+1999-02-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rsh.c: Remove empty file.
+
+1999-02-22    <kunihiro@zebra.org>
+
+	* routemap.c: Add add/delete hook to route_map_master.
+
+1999-02-19  Peter Galbavy  <Peter.Galbavy@knowledge.com>
+
+	* str.[ch] added to supply wrappers for snprintf(), strlcat() and
+	strlcpy on system without these.
+
+1999-02-18  Peter Galbavy  <Peter.Galbavy@knowledge.com>
+
+	* syslog support added
+
+1999-02-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* filter.c (access_list_add_hook): added for hook function management.
+	* filter.c (access_list_delete_hook): Likewise.
+
+1999-01-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* stream.c: New file.
+	* stream.h: New file.
+	* Divide stream related fucntions from buffer.[ch] into stream.[ch].
+	
+1999-01-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* memory.h (enum): add MTYPE_STREAM, MTYPE_STREAM_DATA
+
+	* buffer.c (stream_new): Set MTYPE_STREAM to XMALLOC argument.
+
+1998-12-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* routemap.c: route_map_index_delete() added.
+
+1998-12-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* buffer.c (buffer_empty): check cp instead of sp.
+
+1998-12-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* radix.[ch]: Deleted.
+
+1998-12-15  Magnus Ahltorp <map@stacken.kth.se>
+
+	* buffer.c: Prototype fixes.
+	* prefix.c: Likewise.
+	* sockunion.c: Likewise.
+	* sockunion.h: Likewise.
+
+1998-12-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (vty_read): DELETE key works as vty_delete_char.
+
+1998-12-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* log.c (time_print): chane %y to %Y.
+
+1998-12-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* distribute.c: new file.
+
+1998-12-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* filter.c: Remove all of struct prefix_{ipv4,ipv6} and add
+	complete support of IPv6 access list.
+
+	* command.c (config_write_element): function delete.
+	(config_write_host): function add.  password and enable password
+	isn't printed to vty interface.
+
+1998-12-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* filter.c: Change prefix_ipv4 to prefix and add support of
+	prefix_ipv6 filtering.
+
+1998-12-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* Makefile.am (INCLUDES): add @INCLUDES@ for Linux IPv6 inet6-apps
+	header includes.
+
+1998-12-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* log.c (log_flush): fix function name typo.
+
+1998-12-04  Yasuhiro Ohara <yasu@sfc.wide.ad.jp>
+
+	* memory.h: OSPF memory type is added.
+
+1998-11-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (sort_node): add sort_node() for pretty printing of
+	command on vty interface.
+	(config_password): delete the restriction of charaster of password
+	string.
+
+1998-09-05  Kunihiro Ishiguro  <kunihiro@debian.zebra.org>
+
+	* prefix.c (prefix_ipv4_any): add prefix_ipv4_any().
+
+1998-08-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* network.h: New file.
+
+1998-08-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (vty_will_echo): function name change from vty_off_echo.
+
+1998-08-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* buffer.h: add PUTC,PUTW,PUTL macros.
+
+1998-07-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* route.[ch]: renamed to prefix.[ch]
+
+1998-06-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* prefix_in, prefix_in6 is replaced by prefix_ipv4, prefix_ipv6.
+
+	* Makefile.am: @INCLUDES@ is deleted from INCLUDES.
+
+1998-06-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* host.[ch]: merged with command.[ch]
+
+1998-05-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* Makefile.am (libzebra_a_SOURCES): add route.c to libzebra_a_SOURCES.
+
+1998-05-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* route.c (str2prefix): str2prefix () is gone.
+
+1998-05-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (vty_read_config): change CONDIR to SYSCONFDIR.
+
+	* .cvsignore: add file.
+
+	* memory.c (xerror): add arguent `type' and `size'.
+
+	* socket.c: deleted.
+
+1998-05-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vector.c: malloc,free,realloc -> XMALLOC,XFREE,XREALLOC.
+	* linklist.c: same as above.
+
+1998-04-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* filter.[ch]: added.
+
+1998-04-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (config_who): return CMD_SUCCESS
+
+1998-04-01  Jochen Friedrich <jochen@scram.de>
+
+	* table.c (route_dump_node): route_dump_node is IPv6 specific
+	function so move #ifdef to the end of route_dump_node ().
+
+1998-03-05  "Hannes R. Boehm" <hannes@boehm.org>
+
+	* if.c: DEFUN(interface_desc) added.
+
+1998-03-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* if.c: separated from ripd/rip_interface.c
+
+1998-03-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* thread.[ch] : added.
+
+1998-02-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (vty_delete_char): fix size bug.
+	(vty_backward_pure_word): function added.
+	(vty_read): ESC + 'f' perform vty_forward_word.
+	(vty_read): ESC + 'b' perform vty_backward_word.
+
+1998-02-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* radix.c (radix_lookup_rt): add mask check.
+	(radix_delete_duproute): add mask check.
+
+1998-02-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (config_write_file): fix vty -> file_vty.
+
+1998-02-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (cmd_filter_ambiguous): add complex type treatment.
+
+1998-02-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c (vty_time_print): function added.
+	(vty_complete_command): now [...] element isn't shown by completion.
+
+1998-01-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c : change from cmd_install_node() to install_node().
+
+1998-01-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* route.[ch]: struct rt{} is replaced by struct prefix{}.
+
+1998-01-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.c (cmd_execute_command): check command length.
+
+	* timer.c (zebra_timer_set): add zebra_timer_set.
+
+1998-01-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.h (node_type ): add ZEBRA_NODE.
+
+	* command.c (config_exit): add RIP_NODE.
+	(config_write_file): add RIP_NODE.
+
+1998-01-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* print_version.c (print_version): Now Copyright is 1996-1998.
+
+	* sockunion.c (sockunion_log): moved from ../zebra/route.c
+
+1997-12-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* host.c (config_logfile): change 'log PATH' to 'logfile PATH'.
+
+	* sockunion.c (sockunion_sameprefix): add same prefix for
+	sockunion.
+
+1997-12-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* radix.[ch] : are moved from ../zebra directroy.
+	
+	* command.c (config_from_file): if command execution failed down
+	level to CONFIG_NODE.
+
+	* host.c: config_log function which enable 'log FILENAME' command.
+
+1997-12-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* vty.c: add vty_transpose_chars ().  Now you can use '^T' to
+	transpose character.
+
+	* command.c: cmd_cmdsize add, this is useful to check incomplete
+	command.
+
+1997-12-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* fd.h: add family for address family
+
+1997-12-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* command.o
+	* vty.o
+	* host.o    is moved from ../zebra
+
+1997-08-14  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* make library directory.
+
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..81f1e41
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,29 @@
+## Process this file with automake to produce Makefile.in.
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+
+noinst_LIBRARIES = libzebra.a
+
+libzebra_a_SOURCES = \
+	version.c network.c pid_output.c getopt.c getopt1.c daemon.c \
+	print_version.c checksum.c vector.c linklist.c vty.c command.c \
+	sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \
+	filter.c routemap.c distribute.c stream.c str.c log.c plist.c \
+	zclient.c sockopt.c smux.c md5.c if_rmap.c keychain.c
+
+libzebra_a_DEPENDENCIES = @LIB_REGEX@
+
+libzebra_a_LIBADD = @LIB_REGEX@
+
+noinst_HEADERS = \
+	buffer.h command.h filter.h getopt.h hash.h if.h linklist.h log.h \
+	memory.h network.h prefix.h routemap.h distribute.h sockunion.h \
+	str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \
+	plist.h zclient.h sockopt.h smux.h md5-gnu.h if_rmap.h keychain.h
+
+EXTRA_DIST = regex.c regex-gnu.h
+
+version.c: Makefile
+	echo '' >version.c
+	echo 'char *host_name = "$(host_alias)";' >>version.c
diff --git a/lib/Makefile.in b/lib/Makefile.in
new file mode 100644
index 0000000..d821f23
--- /dev/null
+++ b/lib/Makefile.in
@@ -0,0 +1,469 @@
+# 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@
+
+noinst_LIBRARIES = libzebra.a
+
+libzebra_a_SOURCES = \
+	version.c network.c pid_output.c getopt.c getopt1.c daemon.c \
+	print_version.c checksum.c vector.c linklist.c vty.c command.c \
+	sockunion.c prefix.c thread.c if.c memory.c buffer.c table.c hash.c \
+	filter.c routemap.c distribute.c stream.c str.c log.c plist.c \
+	zclient.c sockopt.c smux.c md5.c if_rmap.c keychain.c
+
+
+libzebra_a_DEPENDENCIES = @LIB_REGEX@
+
+libzebra_a_LIBADD = @LIB_REGEX@
+
+noinst_HEADERS = \
+	buffer.h command.h filter.h getopt.h hash.h if.h linklist.h log.h \
+	memory.h network.h prefix.h routemap.h distribute.h sockunion.h \
+	str.h stream.h table.h thread.h vector.h version.h vty.h zebra.h \
+	plist.h zclient.h sockopt.h smux.h md5-gnu.h if_rmap.h keychain.h
+
+
+EXTRA_DIST = regex.c regex-gnu.h
+subdir = lib
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+
+libzebra_a_AR = $(AR) cru
+am_libzebra_a_OBJECTS = version.$(OBJEXT) network.$(OBJEXT) \
+	pid_output.$(OBJEXT) getopt.$(OBJEXT) getopt1.$(OBJEXT) \
+	daemon.$(OBJEXT) print_version.$(OBJEXT) checksum.$(OBJEXT) \
+	vector.$(OBJEXT) linklist.$(OBJEXT) vty.$(OBJEXT) \
+	command.$(OBJEXT) sockunion.$(OBJEXT) prefix.$(OBJEXT) \
+	thread.$(OBJEXT) if.$(OBJEXT) memory.$(OBJEXT) buffer.$(OBJEXT) \
+	table.$(OBJEXT) hash.$(OBJEXT) filter.$(OBJEXT) \
+	routemap.$(OBJEXT) distribute.$(OBJEXT) stream.$(OBJEXT) \
+	str.$(OBJEXT) log.$(OBJEXT) plist.$(OBJEXT) zclient.$(OBJEXT) \
+	sockopt.$(OBJEXT) smux.$(OBJEXT) md5.$(OBJEXT) \
+	if_rmap.$(OBJEXT) keychain.$(OBJEXT)
+libzebra_a_OBJECTS = $(am_libzebra_a_OBJECTS)
+
+DEFAULT_INCLUDES =  -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/buffer.Po ./$(DEPDIR)/checksum.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/command.Po ./$(DEPDIR)/daemon.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/distribute.Po ./$(DEPDIR)/filter.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/getopt.Po ./$(DEPDIR)/getopt1.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/hash.Po ./$(DEPDIR)/if.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/if_rmap.Po ./$(DEPDIR)/keychain.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/linklist.Po ./$(DEPDIR)/log.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/md5.Po ./$(DEPDIR)/memory.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/network.Po ./$(DEPDIR)/pid_output.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/plist.Po ./$(DEPDIR)/prefix.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/print_version.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/routemap.Po ./$(DEPDIR)/smux.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/sockopt.Po ./$(DEPDIR)/sockunion.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/str.Po ./$(DEPDIR)/stream.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/table.Po ./$(DEPDIR)/thread.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/vector.Po ./$(DEPDIR)/version.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/vty.Po ./$(DEPDIR)/zclient.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 = $(libzebra_a_SOURCES)
+HEADERS = $(noinst_HEADERS)
+
+DIST_COMMON = $(noinst_HEADERS) ChangeLog Makefile.am Makefile.in
+SOURCES = $(libzebra_a_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  lib/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)
+libzebra.a: $(libzebra_a_OBJECTS) $(libzebra_a_DEPENDENCIES) 
+	-rm -f libzebra.a
+	$(libzebra_a_AR) libzebra.a $(libzebra_a_OBJECTS) $(libzebra_a_LIBADD)
+	$(RANLIB) libzebra.a
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/checksum.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/command.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/daemon.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/distribute.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt1.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/if.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/if_rmap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keychain.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/linklist.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memory.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/network.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pid_output.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plist.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prefix.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print_version.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/routemap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smux.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sockopt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sockunion.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/table.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vector.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vty.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zclient.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:
+
+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) $(HEADERS)
+
+installdirs:
+
+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 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-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
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-noinstLIBRARIES 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-strip 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
+
+
+version.c: Makefile
+	echo '' >version.c
+	echo 'char *host_name = "$(host_alias)";' >>version.c
+# 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/lib/buffer.c b/lib/buffer.c
new file mode 100644
index 0000000..de51ee3
--- /dev/null
+++ b/lib/buffer.c
@@ -0,0 +1,568 @@
+/*
+ * Buffering of output and input. 
+ * Copyright (C) 1998 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. 
+ */
+
+#include <zebra.h>
+
+#include "memory.h"
+#include "buffer.h"
+
+/* Make buffer data. */
+struct buffer_data *
+buffer_data_new (size_t size)
+{
+  struct buffer_data *d;
+
+  d = XMALLOC (MTYPE_BUFFER_DATA, sizeof (struct buffer_data));
+  memset (d, 0, sizeof (struct buffer_data));
+  d->data = XMALLOC (MTYPE_BUFFER_DATA, size);
+
+  return d;
+}
+
+void
+buffer_data_free (struct buffer_data *d)
+{
+  if (d->data)
+    XFREE (MTYPE_BUFFER_DATA, d->data);
+  XFREE (MTYPE_BUFFER_DATA, d);
+}
+
+/* Make new buffer. */
+struct buffer *
+buffer_new (size_t size)
+{
+  struct buffer *b;
+
+  b = XMALLOC (MTYPE_BUFFER, sizeof (struct buffer));
+  memset (b, 0, sizeof (struct buffer));
+
+  b->size = size;
+
+  return b;
+}
+
+/* Free buffer. */
+void
+buffer_free (struct buffer *b)
+{
+  struct buffer_data *d;
+  struct buffer_data *next;
+
+  d = b->head;
+  while (d)
+    {
+      next = d->next;
+      buffer_data_free (d);
+      d = next;
+    }
+
+  d = b->unused_head;
+  while (d)
+    {
+      next = d->next;
+      buffer_data_free (d);
+      d = next;
+    }
+  
+  XFREE (MTYPE_BUFFER, b);
+}
+
+/* Make string clone. */
+char *
+buffer_getstr (struct buffer *b)
+{
+  return strdup ((char *)b->head->data);
+}
+
+/* Return 1 if buffer is empty. */
+int
+buffer_empty (struct buffer *b)
+{
+  if (b->tail == NULL || b->tail->cp == b->tail->sp)
+    return 1;
+  else
+    return 0;
+}
+
+/* Clear and free all allocated data. */
+void
+buffer_reset (struct buffer *b)
+{
+  struct buffer_data *data;
+  struct buffer_data *next;
+  
+  for (data = b->head; data; data = next)
+    {
+      next = data->next;
+      buffer_data_free (data);
+    }
+  b->head = b->tail = NULL;
+  b->alloc = 0;
+  b->length = 0;
+}
+
+/* Add buffer_data to the end of buffer. */
+void
+buffer_add (struct buffer *b)
+{
+  struct buffer_data *d;
+
+  d = buffer_data_new (b->size);
+
+  if (b->tail == NULL)
+    {
+      d->prev = NULL;
+      d->next = NULL;
+      b->head = d;
+      b->tail = d;
+    }
+  else
+    {
+      d->prev = b->tail;
+      d->next = NULL;
+
+      b->tail->next = d;
+      b->tail = d;
+    }
+
+  b->alloc++;
+}
+
+/* Write data to buffer. */
+int
+buffer_write (struct buffer *b, u_char *ptr, size_t size)
+{
+  struct buffer_data *data;
+
+  data = b->tail;
+  b->length += size;
+
+  /* We use even last one byte of data buffer. */
+  while (size)    
+    {
+      /* If there is no data buffer add it. */
+      if (data == NULL || data->cp == b->size)
+	{
+	  buffer_add (b);
+	  data = b->tail;
+	}
+
+      /* Last data. */
+      if (size <= (b->size - data->cp))
+	{
+	  memcpy ((data->data + data->cp), ptr, size);
+
+	  data->cp += size;
+	  size = 0;
+	}
+      else
+	{
+	  memcpy ((data->data + data->cp), ptr, (b->size - data->cp));
+
+	  size -= (b->size - data->cp);
+	  ptr += (b->size - data->cp);
+
+	  data->cp = b->size;
+	}
+    }
+  return 1;
+}
+
+/* Insert character into the buffer. */
+int
+buffer_putc (struct buffer *b, u_char c)
+{
+  buffer_write (b, &c, 1);
+  return 1;
+}
+
+/* Insert word (2 octets) into ther buffer. */
+int
+buffer_putw (struct buffer *b, u_short c)
+{
+  buffer_write (b, (char *)&c, 2);
+  return 1;
+}
+
+/* Put string to the buffer. */
+int
+buffer_putstr (struct buffer *b, u_char *c)
+{
+  size_t size;
+
+  size = strlen ((char *)c);
+  buffer_write (b, c, size);
+  return 1;
+}
+
+/* Flush specified size to the fd. */
+void
+buffer_flush (struct buffer *b, int fd, size_t size)
+{
+  int iov_index;
+  struct iovec *iovec;
+  struct buffer_data *data;
+  struct buffer_data *out;
+  struct buffer_data *next;
+
+  iovec = malloc (sizeof (struct iovec) * b->alloc);
+  iov_index = 0;
+
+  for (data = b->head; data; data = data->next)
+    {
+      iovec[iov_index].iov_base = (char *)(data->data + data->sp);
+
+      if (size <= (data->cp - data->sp))
+	{
+	  iovec[iov_index++].iov_len = size;
+	  data->sp += size;
+	  if (data->sp == data->cp)
+	    data = data->next;
+	  break;
+	}
+      else
+	{
+	  iovec[iov_index++].iov_len = data->cp - data->sp;
+	  size -= data->cp - data->sp;
+	  data->sp = data->cp;
+	}
+    }
+
+  /* Write buffer to the fd. */
+  writev (fd, iovec, iov_index);
+
+  /* Free printed buffer data. */
+  for (out = b->head; out && out != data; out = next)
+    {
+      next = out->next;
+      if (next)
+	next->prev = NULL;
+      else
+	b->tail = next;
+      b->head = next;
+
+      buffer_data_free (out);
+      b->alloc--;
+    }
+
+  free (iovec);
+}
+
+/* Flush all buffer to the fd. */
+int
+buffer_flush_all (struct buffer *b, int fd)
+{
+  int ret;
+  struct buffer_data *d;
+  int iov_index;
+  struct iovec *iovec;
+
+  if (buffer_empty (b))
+    return 0;
+
+  iovec = malloc (sizeof (struct iovec) * b->alloc);
+  iov_index = 0;
+
+  for (d = b->head; d; d = d->next)
+    {
+      iovec[iov_index].iov_base = (char *)(d->data + d->sp);
+      iovec[iov_index].iov_len = d->cp - d->sp;
+      iov_index++;
+    }
+  ret = writev (fd, iovec, iov_index);
+
+  free (iovec);
+
+  buffer_reset (b);
+
+  return ret;
+}
+
+/* Flush all buffer to the fd. */
+int
+buffer_flush_vty_all (struct buffer *b, int fd, int erase_flag,
+		      int no_more_flag)
+{
+  int nbytes;
+  int iov_index;
+  struct iovec *iov;
+  struct iovec small_iov[3];
+  char more[] = " --More-- ";
+  char erase[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+		   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+		   0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
+  struct buffer_data *data;
+  struct buffer_data *out;
+  struct buffer_data *next;
+
+  /* For erase and more data add two to b's buffer_data count.*/
+  if (b->alloc == 1)
+    iov = small_iov;
+  else
+    iov = XCALLOC (MTYPE_TMP, sizeof (struct iovec) * (b->alloc + 2));
+
+  data = b->head;
+  iov_index = 0;
+
+  /* Previously print out is performed. */
+  if (erase_flag)
+    {
+      iov[iov_index].iov_base = erase;
+      iov[iov_index].iov_len = sizeof erase;
+      iov_index++;
+    }
+
+  /* Output data. */
+  for (data = b->head; data; data = data->next)
+    {
+      iov[iov_index].iov_base = (char *)(data->data + data->sp);
+      iov[iov_index].iov_len = data->cp - data->sp;
+      iov_index++;
+    }
+
+  /* In case of `more' display need. */
+  if (! buffer_empty (b) && !no_more_flag)
+    {
+      iov[iov_index].iov_base = more;
+      iov[iov_index].iov_len = sizeof more;
+      iov_index++;
+    }
+
+  /* We use write or writev*/
+  nbytes = writev (fd, iov, iov_index);
+
+  /* Error treatment. */
+  if (nbytes < 0)
+    {
+      if (errno == EINTR)
+	;
+      if (errno == EWOULDBLOCK)
+	;
+    }
+
+  /* Free printed buffer data. */
+  for (out = b->head; out && out != data; out = next)
+    {
+      next = out->next;
+      if (next)
+	next->prev = NULL;
+      else
+	b->tail = next;
+      b->head = next;
+
+      buffer_data_free (out);
+      b->alloc--;
+    }
+
+  if (iov != small_iov)
+    XFREE (MTYPE_TMP, iov);
+
+  return nbytes;
+}
+
+/* Flush buffer to the file descriptor.  Mainly used from vty
+   interface. */
+int
+buffer_flush_vty (struct buffer *b, int fd, int size, 
+		  int erase_flag, int no_more_flag)
+{
+  int nbytes;
+  int iov_index;
+  struct iovec *iov;
+  struct iovec small_iov[3];
+  char more[] = " --More-- ";
+  char erase[] = { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
+		   ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+		   0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
+  struct buffer_data *data;
+  struct buffer_data *out;
+  struct buffer_data *next;
+
+#ifdef  IOV_MAX
+  int iov_size;
+  int total_size;
+  struct iovec *c_iov;
+  int c_nbytes;
+#endif /* IOV_MAX */
+
+  /* For erase and more data add two to b's buffer_data count.*/
+  if (b->alloc == 1)
+    iov = small_iov;
+  else
+    iov = XCALLOC (MTYPE_TMP, sizeof (struct iovec) * (b->alloc + 2));
+
+  data = b->head;
+  iov_index = 0;
+
+  /* Previously print out is performed. */
+  if (erase_flag)
+    {
+      iov[iov_index].iov_base = erase;
+      iov[iov_index].iov_len = sizeof erase;
+      iov_index++;
+    }
+
+  /* Output data. */
+  for (data = b->head; data; data = data->next)
+    {
+      iov[iov_index].iov_base = (char *)(data->data + data->sp);
+
+      if (size <= (data->cp - data->sp))
+	{
+	  iov[iov_index++].iov_len = size;
+	  data->sp += size;
+	  if (data->sp == data->cp)
+	    data = data->next;
+	  break;
+	}
+      else
+	{
+	  iov[iov_index++].iov_len = data->cp - data->sp;
+	  size -= (data->cp - data->sp);
+	  data->sp = data->cp;
+	}
+    }
+
+  /* In case of `more' display need. */
+  if (!buffer_empty (b) && !no_more_flag)
+    {
+      iov[iov_index].iov_base = more;
+      iov[iov_index].iov_len = sizeof more;
+      iov_index++;
+    }
+
+  /* We use write or writev*/
+
+#ifdef IOV_MAX
+  /* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g.
+     example: Solaris2.6 are defined IOV_MAX size at 16.     */
+  c_iov = iov;
+  total_size = iov_index;
+  nbytes = 0;
+
+  while( total_size > 0 )
+    {
+       /* initialize write vector size at once */
+       iov_size = ( total_size > IOV_MAX ) ? IOV_MAX : total_size;
+
+       c_nbytes = writev (fd, c_iov, iov_size );
+
+       if( c_nbytes < 0 )
+         {
+           if(errno == EINTR)
+             ;
+             ;
+           if(errno == EWOULDBLOCK)
+             ;
+             ;
+           nbytes = c_nbytes;
+           break;
+
+         }
+
+        nbytes += c_nbytes;
+
+       /* move pointer io-vector */
+       c_iov += iov_size;
+       total_size -= iov_size;
+    }
+#else  /* IOV_MAX */
+   nbytes = writev (fd, iov, iov_index);
+
+  /* Error treatment. */
+  if (nbytes < 0)
+    {
+      if (errno == EINTR)
+	;
+      if (errno == EWOULDBLOCK)
+	;
+    }
+#endif /* IOV_MAX */
+
+  /* Free printed buffer data. */
+  for (out = b->head; out && out != data; out = next)
+    {
+      next = out->next;
+      if (next)
+	next->prev = NULL;
+      else
+	b->tail = next;
+      b->head = next;
+
+      buffer_data_free (out);
+      b->alloc--;
+    }
+
+  if (iov != small_iov)
+    XFREE (MTYPE_TMP, iov);
+
+  return nbytes;
+}
+
+/* Calculate size of outputs then flush buffer to the file
+   descriptor. */
+int
+buffer_flush_window (struct buffer *b, int fd, int width, int height, 
+		     int erase, int no_more)
+{
+  unsigned long cp;
+  unsigned long size;
+  int lp;
+  int lineno;
+  struct buffer_data *data;
+
+  if (height >= 2)
+    height--;
+
+  /* We have to calculate how many bytes should be written. */
+  lp = 0;
+  lineno = 0;
+  size = 0;
+  
+  for (data = b->head; data; data = data->next)
+    {
+      cp = data->sp;
+
+      while (cp < data->cp)
+	{
+	  if (data->data[cp] == '\n' || lp == width)
+	    {
+	      lineno++;
+	      if (lineno == height)
+		{
+		  cp++;
+		  size++;
+		  goto flush;
+		}
+	      lp = 0;
+	    }
+	  cp++;
+	  lp++;
+	  size++;
+	}
+    }
+
+  /* Write data to the file descriptor. */
+ flush:
+
+  return buffer_flush_vty (b, fd, size, erase, no_more);
+}
diff --git a/lib/buffer.h b/lib/buffer.h
new file mode 100644
index 0000000..7449aa7
--- /dev/null
+++ b/lib/buffer.h
@@ -0,0 +1,77 @@
+/*
+ * Buffering to output and input. 
+ * Copyright (C) 1998 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 _ZEBRA_BUFFER_H
+#define _ZEBRA_BUFFER_H
+
+/* Buffer master. */
+struct buffer
+{
+  /* Data list. */
+  struct buffer_data *head;
+  struct buffer_data *tail;
+
+  /* Current allocated data. */
+  unsigned long alloc;
+
+  /* Total length of buffer. */
+  unsigned long size;
+
+  /* For allocation. */
+  struct buffer_data *unused_head;
+  struct buffer_data *unused_tail;
+
+  /* Current total length of this buffer. */
+  unsigned long length;
+};
+
+/* Data container. */
+struct buffer_data
+{
+  struct buffer *parent;
+  struct buffer_data *next;
+  struct buffer_data *prev;
+
+  /* Acctual data stream. */
+  unsigned char *data;
+
+  /* Current pointer. */
+  unsigned long cp;
+
+  /* Start pointer. */
+  unsigned long sp;
+};
+
+/* Buffer prototypes. */
+struct buffer *buffer_new (size_t);
+int buffer_write (struct buffer *, u_char *, size_t);
+void buffer_free (struct buffer *);
+char *buffer_getstr (struct buffer *);
+int buffer_putc (struct buffer *, u_char);
+int buffer_putstr (struct buffer *, u_char *);
+void buffer_reset (struct buffer *);
+int buffer_flush_all (struct buffer *, int);
+int buffer_flush_vty_all (struct buffer *, int, int, int);
+int buffer_flush_window (struct buffer *, int, int, int, int, int);
+int buffer_empty (struct buffer *);
+
+#endif /* _ZEBRA_BUFFER_H */
diff --git a/lib/checksum.c b/lib/checksum.c
new file mode 100644
index 0000000..6a29cba
--- /dev/null
+++ b/lib/checksum.c
@@ -0,0 +1,47 @@
+/*
+ * Checksum routine for Internet Protocol family headers (C Version).
+ *
+ * Refer to "Computing the Internet Checksum" by R. Braden, D. Borman and
+ * C. Partridge, Computer Communication Review, Vol. 19, No. 2, April 1989,
+ * pp. 86-101, for additional details on computing this checksum.
+ */
+
+#include <zebra.h>
+
+int				/* return checksum in low-order 16 bits */
+in_cksum(ptr, nbytes)
+register u_short	*ptr;
+register int		nbytes;
+{
+	register long		sum;		/* assumes long == 32 bits */
+	u_short			oddbyte;
+	register u_short	answer;		/* assumes u_short == 16 bits */
+
+	/*
+	 * Our algorithm is simple, using a 32-bit accumulator (sum),
+	 * we add sequential 16-bit words to it, and at the end, fold back
+	 * all the carry bits from the top 16 bits into the lower 16 bits.
+	 */
+
+	sum = 0;
+	while (nbytes > 1)  {
+		sum += *ptr++;
+		nbytes -= 2;
+	}
+
+				/* mop up an odd byte, if necessary */
+	if (nbytes == 1) {
+		oddbyte = 0;		/* make sure top half is zero */
+		*((u_char *) &oddbyte) = *(u_char *)ptr;   /* one byte only */
+		sum += oddbyte;
+	}
+
+	/*
+	 * Add back carry outs from top 16 bits to low 16 bits.
+	 */
+
+	sum  = (sum >> 16) + (sum & 0xffff);	/* add high-16 to low-16 */
+	sum += (sum >> 16);			/* add carry */
+	answer = ~sum;		/* ones-complement, then truncate to 16 bits */
+	return(answer);
+}
diff --git a/lib/command.c b/lib/command.c
new file mode 100644
index 0000000..8cbecce
--- /dev/null
+++ b/lib/command.c
@@ -0,0 +1,2981 @@
+/* Command interpreter routine for virtual terminal [aka TeletYpe]
+   Copyright (C) 1997, 98, 99 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.  */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "memory.h"
+#include "log.h"
+#include "version.h"
+
+/* Command vector which includes some level of command lists. Normally
+   each daemon maintains each own cmdvec. */
+vector cmdvec;
+
+/* Host information structure. */
+struct host host;
+
+/* Default motd string. */
+char *default_motd = 
+"\r\n\
+Hello, this is zebra (version " ZEBRA_VERSION ").\r\n\
+Copyright 1996-2002 Kunihiro Ishiguro.\r\n\
+\r\n";
+
+/* Standard command node structures. */
+struct cmd_node auth_node =
+{
+  AUTH_NODE,
+  "Password: ",
+};
+
+struct cmd_node view_node =
+{
+  VIEW_NODE,
+  "%s> ",
+};
+
+struct cmd_node auth_enable_node =
+{
+  AUTH_ENABLE_NODE,
+  "Password: ",
+};
+
+struct cmd_node enable_node =
+{
+  ENABLE_NODE,
+  "%s# ",
+};
+
+struct cmd_node config_node =
+{
+  CONFIG_NODE,
+  "%s(config)# ",
+  1
+};
+
+/* Utility function to concatenate argv argument into a single string
+   with inserting ' ' character between each argument.  */
+char *
+argv_concat (char **argv, int argc, int shift)
+{
+  int i;
+  int len;
+  int index;
+  char *str;
+
+  str = NULL;
+  index = 0;
+
+  for (i = shift; i < argc; i++)
+    {
+      len = strlen (argv[i]);
+
+      if (i == shift)
+	{
+	  str = XSTRDUP (MTYPE_TMP, argv[i]);
+	  index = len;
+	}
+      else
+	{
+	  str = XREALLOC (MTYPE_TMP, str, (index + len + 2));
+	  str[index++] = ' ';
+	  memcpy (str + index, argv[i], len);
+	  index += len;
+	  str[index] = '\0';
+	}
+    }
+  return str;
+}
+
+/* Install top node of command vector. */
+void
+install_node (struct cmd_node *node, 
+	      int (*func) (struct vty *))
+{
+  vector_set_index (cmdvec, node->node, node);
+  node->func = func;
+  node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
+}
+
+/* Compare two command's string.  Used in sort_node (). */
+int
+cmp_node (const void *p, const void *q)
+{
+  struct cmd_element *a = *(struct cmd_element **)p;
+  struct cmd_element *b = *(struct cmd_element **)q;
+
+  return strcmp (a->string, b->string);
+}
+
+int
+cmp_desc (const void *p, const void *q)
+{
+  struct desc *a = *(struct desc **)p;
+  struct desc *b = *(struct desc **)q;
+
+  return strcmp (a->cmd, b->cmd);
+}
+
+/* Sort each node's command element according to command string. */
+void
+sort_node ()
+{
+  int i, j;
+  struct cmd_node *cnode;
+  vector descvec;
+  struct cmd_element *cmd_element;
+
+  for (i = 0; i < vector_max (cmdvec); i++) 
+    if ((cnode = vector_slot (cmdvec, i)) != NULL)
+      {	
+	vector cmd_vector = cnode->cmd_vector;
+	qsort (cmd_vector->index, cmd_vector->max, sizeof (void *), cmp_node);
+
+	for (j = 0; j < vector_max (cmd_vector); j++)
+	  if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
+	    {
+	      descvec = vector_slot (cmd_element->strvec,
+				     vector_max (cmd_element->strvec) - 1);
+	      qsort (descvec->index, descvec->max, sizeof (void *), cmp_desc);
+	    }
+      }
+}
+
+/* Breaking up string into each command piece. I assume given
+   character is separated by a space character. Return value is a
+   vector which includes char ** data element. */
+vector
+cmd_make_strvec (char *string)
+{
+  char *cp, *start, *token;
+  int strlen;
+  vector strvec;
+  
+  if (string == NULL)
+    return NULL;
+  
+  cp = string;
+
+  /* Skip white spaces. */
+  while (isspace ((int) *cp) && *cp != '\0')
+    cp++;
+
+  /* Return if there is only white spaces */
+  if (*cp == '\0')
+    return NULL;
+
+  if (*cp == '!' || *cp == '#')
+    return NULL;
+
+  /* Prepare return vector. */
+  strvec = vector_init (VECTOR_MIN_SIZE);
+
+  /* Copy each command piece and set into vector. */
+  while (1) 
+    {
+      start = cp;
+      while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
+	     *cp != '\0')
+	cp++;
+      strlen = cp - start;
+      token = XMALLOC (MTYPE_STRVEC, strlen + 1);
+      memcpy (token, start, strlen);
+      *(token + strlen) = '\0';
+      vector_set (strvec, token);
+
+      while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
+	     *cp != '\0')
+	cp++;
+
+      if (*cp == '\0')
+	return strvec;
+    }
+}
+
+/* Free allocated string vector. */
+void
+cmd_free_strvec (vector v)
+{
+  int i;
+  char *cp;
+
+  if (!v)
+    return;
+
+  for (i = 0; i < vector_max (v); i++)
+    if ((cp = vector_slot (v, i)) != NULL)
+      XFREE (MTYPE_STRVEC, cp);
+
+  vector_free (v);
+}
+
+/* Fetch next description.  Used in cmd_make_descvec(). */
+char *
+cmd_desc_str (char **string)
+{
+  char *cp, *start, *token;
+  int strlen;
+  
+  cp = *string;
+
+  if (cp == NULL)
+    return NULL;
+
+  /* Skip white spaces. */
+  while (isspace ((int) *cp) && *cp != '\0')
+    cp++;
+
+  /* Return if there is only white spaces */
+  if (*cp == '\0')
+    return NULL;
+
+  start = cp;
+
+  while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
+    cp++;
+
+  strlen = cp - start;
+  token = XMALLOC (MTYPE_STRVEC, strlen + 1);
+  memcpy (token, start, strlen);
+  *(token + strlen) = '\0';
+
+  *string = cp;
+
+  return token;
+}
+
+/* New string vector. */
+vector
+cmd_make_descvec (char *string, char *descstr)
+{
+  int multiple = 0;
+  char *sp;
+  char *token;
+  int len;
+  char *cp;
+  char *dp;
+  vector allvec;
+  vector strvec = NULL;
+  struct desc *desc;
+
+  cp = string;
+  dp = descstr;
+
+  if (cp == NULL)
+    return NULL;
+
+  allvec = vector_init (VECTOR_MIN_SIZE);
+
+  while (1)
+    {
+      while (isspace ((int) *cp) && *cp != '\0')
+	cp++;
+
+      if (*cp == '(')
+	{
+	  multiple = 1;
+	  cp++;
+	}
+      if (*cp == ')')
+	{
+	  multiple = 0;
+	  cp++;
+	}
+      if (*cp == '|')
+	{
+	  if (! multiple)
+	    {
+	      fprintf (stderr, "Command parse error!: %s\n", string);
+	      exit (1);
+	    }
+	  cp++;
+	}
+      
+      while (isspace ((int) *cp) && *cp != '\0')
+	cp++;
+
+      if (*cp == '(')
+	{
+	  multiple = 1;
+	  cp++;
+	}
+
+      if (*cp == '\0') 
+	return allvec;
+
+      sp = cp;
+
+      while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0')
+	cp++;
+
+      len = cp - sp;
+
+      token = XMALLOC (MTYPE_STRVEC, len + 1);
+      memcpy (token, sp, len);
+      *(token + len) = '\0';
+
+      desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));
+      desc->cmd = token;
+      desc->str = cmd_desc_str (&dp);
+
+      if (multiple)
+	{
+	  if (multiple == 1)
+	    {
+	      strvec = vector_init (VECTOR_MIN_SIZE);
+	      vector_set (allvec, strvec);
+	    }
+	  multiple++;
+	}
+      else
+	{
+	  strvec = vector_init (VECTOR_MIN_SIZE);
+	  vector_set (allvec, strvec);
+	}
+      vector_set (strvec, desc);
+    }
+}
+
+/* Count mandantory string vector size.  This is to determine inputed
+   command has enough command length. */
+int
+cmd_cmdsize (vector strvec)
+{
+  int i;
+  char *str;
+  int size = 0;
+  vector descvec;
+
+  for (i = 0; i < vector_max (strvec); i++)
+    {
+      descvec = vector_slot (strvec, i);
+
+      if (vector_max (descvec) == 1)
+	{
+	  struct desc *desc = vector_slot (descvec, 0);
+
+	  str = desc->cmd;
+	  
+	  if (str == NULL || CMD_OPTION (str))
+	    return size;
+	  else
+	    size++;
+	}
+      else
+	size++;
+    }
+  return size;
+}
+
+/* Return prompt character of specified node. */
+char *
+cmd_prompt (enum node_type node)
+{
+  struct cmd_node *cnode;
+
+  cnode = vector_slot (cmdvec, node);
+  return cnode->prompt;
+}
+
+/* Install a command into a node. */
+void
+install_element (enum node_type ntype, struct cmd_element *cmd)
+{
+  struct cmd_node *cnode;
+
+  cnode = vector_slot (cmdvec, ntype);
+
+  if (cnode == NULL) 
+    {
+      fprintf (stderr, "Command node %d doesn't exist, please check it\n",
+	       ntype);
+      exit (1);
+    }
+
+  vector_set (cnode->cmd_vector, cmd);
+
+  cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
+  cmd->cmdsize = cmd_cmdsize (cmd->strvec);
+}
+
+static unsigned char itoa64[] =	
+"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+void
+to64(char *s, long v, int n)
+{
+  while (--n >= 0) 
+    {
+      *s++ = itoa64[v&0x3f];
+      v >>= 6;
+    }
+}
+
+char *zencrypt (char *passwd)
+{
+  char salt[6];
+  struct timeval tv;
+  char *crypt (const char *, const char *);
+
+  gettimeofday(&tv,0);
+  
+  to64(&salt[0], random(), 3);
+  to64(&salt[3], tv.tv_usec, 3);
+  salt[5] = '\0';
+
+  return crypt (passwd, salt);
+}
+
+/* This function write configuration of this host. */
+int
+config_write_host (struct vty *vty)
+{
+  if (host.name)
+    vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
+
+  if (host.encrypt)
+    {
+      if (host.password_encrypt)
+        vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE); 
+      if (host.enable_encrypt)
+        vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE); 
+    }
+  else
+    {
+      if (host.password)
+        vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
+      if (host.enable)
+        vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
+    }
+
+  if (host.logfile)
+    vty_out (vty, "log file %s%s", host.logfile, VTY_NEWLINE);
+
+  if (host.log_stdout)
+    vty_out (vty, "log stdout%s", VTY_NEWLINE);
+
+  if (host.log_syslog)
+    vty_out (vty, "log syslog%s", VTY_NEWLINE);
+
+  if (zlog_default->maskpri != LOG_DEBUG)
+    vty_out (vty, "log trap %s%s", zlog_priority[zlog_default->maskpri], VTY_NEWLINE);
+
+  if (zlog_default->record_priority == 1)
+    vty_out (vty, "log record-priority%s", VTY_NEWLINE);
+
+  if (host.advanced)
+    vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
+
+  if (host.encrypt)
+    vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
+
+  if (host.lines >= 0)
+    vty_out (vty, "service terminal-length %d%s", host.lines,
+	     VTY_NEWLINE);
+
+  if (! host.motd)
+    vty_out (vty, "no banner motd%s", VTY_NEWLINE);
+
+  return 1;
+}
+
+/* Utility function for getting command vector. */
+vector
+cmd_node_vector (vector v, enum node_type ntype)
+{
+  struct cmd_node *cnode = vector_slot (v, ntype);
+  return cnode->cmd_vector;
+}
+
+/* Filter command vector by symbol */
+int
+cmd_filter_by_symbol (char *command, char *symbol)
+{
+  int i, lim;
+
+  if (strcmp (symbol, "IPV4_ADDRESS") == 0)
+    {
+      i = 0;
+      lim = strlen (command);
+      while (i < lim)
+	{
+	  if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
+	    return 1;
+	  i++;
+	}
+      return 0;
+    }
+  if (strcmp (symbol, "STRING") == 0)
+    {
+      i = 0;
+      lim = strlen (command);
+      while (i < lim)
+	{
+	  if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
+	    return 1;
+	  i++;
+	}
+      return 0;
+    }
+  if (strcmp (symbol, "IFNAME") == 0)
+    {
+      i = 0;
+      lim = strlen (command);
+      while (i < lim)
+	{
+	  if (! isalnum ((int) command[i]))
+	    return 1;
+	  i++;
+	}
+      return 0;
+    }
+  return 0;
+}
+
+/* Completion match types. */
+enum match_type 
+{
+  no_match,
+  extend_match,
+  ipv4_prefix_match,
+  ipv4_match,
+  ipv6_prefix_match,
+  ipv6_match,
+  range_match,
+  vararg_match,
+  partly_match,
+  exact_match 
+};
+
+enum match_type
+cmd_ipv4_match (char *str)
+{
+  char *sp;
+  int dots = 0, nums = 0;
+  char buf[4];
+
+  if (str == NULL)
+    return partly_match;
+
+  for (;;)
+    {
+      memset (buf, 0, sizeof (buf));
+      sp = str;
+      while (*str != '\0')
+	{
+	  if (*str == '.')
+	    {
+	      if (dots >= 3)
+		return no_match;
+
+	      if (*(str + 1) == '.')
+		return no_match;
+
+	      if (*(str + 1) == '\0')
+		return partly_match;
+
+	      dots++;
+	      break;
+	    }
+	  if (!isdigit ((int) *str))
+	    return no_match;
+
+	  str++;
+	}
+
+      if (str - sp > 3)
+	return no_match;
+
+      strncpy (buf, sp, str - sp);
+      if (atoi (buf) > 255)
+	return no_match;
+
+      nums++;
+
+      if (*str == '\0')
+	break;
+
+      str++;
+    }
+
+  if (nums < 4)
+    return partly_match;
+
+  return exact_match;
+}
+
+enum match_type
+cmd_ipv4_prefix_match (char *str)
+{
+  char *sp;
+  int dots = 0;
+  char buf[4];
+
+  if (str == NULL)
+    return partly_match;
+
+  for (;;)
+    {
+      memset (buf, 0, sizeof (buf));
+      sp = str;
+      while (*str != '\0' && *str != '/')
+	{
+	  if (*str == '.')
+	    {
+	      if (dots == 3)
+		return no_match;
+
+	      if (*(str + 1) == '.' || *(str + 1) == '/')
+		return no_match;
+
+	      if (*(str + 1) == '\0')
+		return partly_match;
+
+	      dots++;
+	      break;
+	    }
+
+	  if (!isdigit ((int) *str))
+	    return no_match;
+
+	  str++;
+	}
+
+      if (str - sp > 3)
+	return no_match;
+
+      strncpy (buf, sp, str - sp);
+      if (atoi (buf) > 255)
+	return no_match;
+
+      if (dots == 3)
+	{
+	  if (*str == '/')
+	    {
+	      if (*(str + 1) == '\0')
+		return partly_match;
+
+	      str++;
+	      break;
+	    }
+	  else if (*str == '\0')
+	    return partly_match;
+	}
+
+      if (*str == '\0')
+	return partly_match;
+
+      str++;
+    }
+
+  sp = str;
+  while (*str != '\0')
+    {
+      if (!isdigit ((int) *str))
+	return no_match;
+
+      str++;
+    }
+
+  if (atoi (sp) > 32)
+    return no_match;
+
+  return exact_match;
+}
+
+#define IPV6_ADDR_STR		"0123456789abcdefABCDEF:.%"
+#define IPV6_PREFIX_STR		"0123456789abcdefABCDEF:.%/"
+#define STATE_START		1
+#define STATE_COLON		2
+#define STATE_DOUBLE		3
+#define STATE_ADDR		4
+#define STATE_DOT               5
+#define STATE_SLASH		6
+#define STATE_MASK		7
+
+enum match_type
+cmd_ipv6_match (char *str)
+{
+  int state = STATE_START;
+  int colons = 0, nums = 0, double_colon = 0;
+  char *sp = NULL;
+
+  if (str == NULL)
+    return partly_match;
+
+  if (strspn (str, IPV6_ADDR_STR) != strlen (str))
+    return no_match;
+
+  while (*str != '\0')
+    {
+      switch (state)
+	{
+	case STATE_START:
+	  if (*str == ':')
+	    {
+	      if (*(str + 1) != ':' && *(str + 1) != '\0')
+		return no_match;
+     	      colons--;
+	      state = STATE_COLON;
+	    }
+	  else
+	    {
+	      sp = str;
+	      state = STATE_ADDR;
+	    }
+
+	  continue;
+	case STATE_COLON:
+	  colons++;
+	  if (*(str + 1) == ':')
+	    state = STATE_DOUBLE;
+	  else
+	    {
+	      sp = str + 1;
+	      state = STATE_ADDR;
+	    }
+	  break;
+	case STATE_DOUBLE:
+	  if (double_colon)
+	    return no_match;
+
+	  if (*(str + 1) == ':')
+	    return no_match;
+	  else
+	    {
+	      if (*(str + 1) != '\0')
+		colons++;
+	      sp = str + 1;
+	      state = STATE_ADDR;
+	    }
+
+	  double_colon++;
+	  nums++;
+	  break;
+	case STATE_ADDR:
+	  if (*(str + 1) == ':' || *(str + 1) == '\0')
+	    {
+	      if (str - sp > 3)
+		return no_match;
+
+	      nums++;
+	      state = STATE_COLON;
+	    }
+	  if (*(str + 1) == '.')
+	    state = STATE_DOT;
+	  break;
+	case STATE_DOT:
+	  state = STATE_ADDR;
+	  break;
+	default:
+	  break;
+	}
+
+      if (nums > 8)
+	return no_match;
+
+      if (colons > 7)
+	return no_match;
+
+      str++;
+    }
+
+#if 0
+  if (nums < 11)
+    return partly_match;
+#endif /* 0 */
+
+  return exact_match;
+}
+
+enum match_type
+cmd_ipv6_prefix_match (char *str)
+{
+  int state = STATE_START;
+  int colons = 0, nums = 0, double_colon = 0;
+  int mask;
+  char *sp = NULL;
+  char *endptr = NULL;
+
+  if (str == NULL)
+    return partly_match;
+
+  if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
+    return no_match;
+
+  while (*str != '\0' && state != STATE_MASK)
+    {
+      switch (state)
+	{
+	case STATE_START:
+	  if (*str == ':')
+	    {
+	      if (*(str + 1) != ':' && *(str + 1) != '\0')
+		return no_match;
+	      colons--;
+	      state = STATE_COLON;
+	    }
+	  else
+	    {
+	      sp = str;
+	      state = STATE_ADDR;
+	    }
+
+	  continue;
+	case STATE_COLON:
+	  colons++;
+	  if (*(str + 1) == '/')
+	    return no_match;
+	  else if (*(str + 1) == ':')
+	    state = STATE_DOUBLE;
+	  else
+	    {
+	      sp = str + 1;
+	      state = STATE_ADDR;
+	    }
+	  break;
+	case STATE_DOUBLE:
+	  if (double_colon)
+	    return no_match;
+
+	  if (*(str + 1) == ':')
+	    return no_match;
+	  else
+	    {
+	      if (*(str + 1) != '\0' && *(str + 1) != '/')
+		colons++;
+	      sp = str + 1;
+
+	      if (*(str + 1) == '/')
+		state = STATE_SLASH;
+	      else
+		state = STATE_ADDR;
+	    }
+
+	  double_colon++;
+	  nums += 1;
+	  break;
+	case STATE_ADDR:
+	  if (*(str + 1) == ':' || *(str + 1) == '.'
+	      || *(str + 1) == '\0' || *(str + 1) == '/')
+	    {
+	      if (str - sp > 3)
+		return no_match;
+
+	      for (; sp <= str; sp++)
+		if (*sp == '/')
+		  return no_match;
+
+	      nums++;
+
+	      if (*(str + 1) == ':')
+		state = STATE_COLON;
+	      else if (*(str + 1) == '.')
+		state = STATE_DOT;
+	      else if (*(str + 1) == '/')
+		state = STATE_SLASH;
+	    }
+	  break;
+	case STATE_DOT:
+	  state = STATE_ADDR;
+	  break;
+	case STATE_SLASH:
+	  if (*(str + 1) == '\0')
+	    return partly_match;
+
+	  state = STATE_MASK;
+	  break;
+	default:
+	  break;
+	}
+
+      if (nums > 11)
+	return no_match;
+
+      if (colons > 7)
+	return no_match;
+
+      str++;
+    }
+
+  if (state < STATE_MASK)
+    return partly_match;
+
+  mask = strtol (str, &endptr, 10);
+  if (*endptr != '\0')
+    return no_match;
+
+  if (mask < 0 || mask > 128)
+    return no_match;
+  
+/* I don't know why mask < 13 makes command match partly.
+   Forgive me to make this comments. I Want to set static default route
+   because of lack of function to originate default in ospf6d; sorry
+       yasu
+  if (mask < 13)
+    return partly_match;
+*/
+
+  return exact_match;
+}
+
+#define DECIMAL_STRLEN_MAX 10
+
+int
+cmd_range_match (char *range, char *str)
+{
+  char *p;
+  char buf[DECIMAL_STRLEN_MAX + 1];
+  char *endptr = NULL;
+  unsigned long min, max, val;
+
+  if (str == NULL)
+    return 1;
+
+  val = strtoul (str, &endptr, 10);
+  if (*endptr != '\0')
+    return 0;
+
+  range++;
+  p = strchr (range, '-');
+  if (p == NULL)
+    return 0;
+  if (p - range > DECIMAL_STRLEN_MAX)
+    return 0;
+  strncpy (buf, range, p - range);
+  buf[p - range] = '\0';
+  min = strtoul (buf, &endptr, 10);
+  if (*endptr != '\0')
+    return 0;
+
+  range = p + 1;
+  p = strchr (range, '>');
+  if (p == NULL)
+    return 0;
+  if (p - range > DECIMAL_STRLEN_MAX)
+    return 0;
+  strncpy (buf, range, p - range);
+  buf[p - range] = '\0';
+  max = strtoul (buf, &endptr, 10);
+  if (*endptr != '\0')
+    return 0;
+
+  if (val < min || val > max)
+    return 0;
+
+  return 1;
+}
+
+/* Make completion match and return match type flag. */
+enum match_type
+cmd_filter_by_completion (char *command, vector v, int index)
+{
+  int i;
+  char *str;
+  struct cmd_element *cmd_element;
+  enum match_type match_type;
+  vector descvec;
+  struct desc *desc;
+  
+  match_type = no_match;
+
+  /* If command and cmd_element string does not match set NULL to vector */
+  for (i = 0; i < vector_max (v); i++) 
+    if ((cmd_element = vector_slot (v, i)) != NULL)
+      {
+	if (index >= vector_max (cmd_element->strvec))
+	  vector_slot (v, i) = NULL;
+	else
+	  {
+	    int j;
+	    int matched = 0;
+
+	    descvec = vector_slot (cmd_element->strvec, index);
+	    
+	    for (j = 0; j < vector_max (descvec); j++)
+	      {
+		desc = vector_slot (descvec, j);
+		str = desc->cmd;
+
+		if (CMD_VARARG (str))
+		  {
+		    if (match_type < vararg_match)
+		      match_type = vararg_match;
+		    matched++;
+		  }
+		else if (CMD_RANGE (str))
+		  {
+		    if (cmd_range_match (str, command))
+		      {
+			if (match_type < range_match)
+			  match_type = range_match;
+
+			matched++;
+		      }
+		  }
+		else if (CMD_IPV6 (str))
+		  {
+		    if (cmd_ipv6_match (command))
+		      {
+			if (match_type < ipv6_match)
+			  match_type = ipv6_match;
+
+			matched++;
+		      }
+		  }
+		else if (CMD_IPV6_PREFIX (str))
+		  {
+		    if (cmd_ipv6_prefix_match (command))
+		      {
+			if (match_type < ipv6_prefix_match)
+			  match_type = ipv6_prefix_match;
+
+			matched++;
+		      }
+		  }
+		else if (CMD_IPV4 (str))
+		  {
+		    if (cmd_ipv4_match (command))
+		      {
+			if (match_type < ipv4_match)
+			  match_type = ipv4_match;
+
+			matched++;
+		      }
+		  }
+		else if (CMD_IPV4_PREFIX (str))
+		  {
+		    if (cmd_ipv4_prefix_match (command))
+		      {
+			if (match_type < ipv4_prefix_match)
+			  match_type = ipv4_prefix_match;
+			matched++;
+		      }
+		  }
+		else
+		/* Check is this point's argument optional ? */
+		if (CMD_OPTION (str) || CMD_VARIABLE (str))
+		  {
+		    if (match_type < extend_match)
+		      match_type = extend_match;
+		    matched++;
+		  }
+		else if (strncmp (command, str, strlen (command)) == 0)
+		  {
+		    if (strcmp (command, str) == 0) 
+		      match_type = exact_match;
+		    else
+		      {
+			if (match_type < partly_match)
+			  match_type = partly_match;
+		      }
+		    matched++;
+		  }
+	      }
+	    if (! matched)
+	      vector_slot (v, i) = NULL;
+	  }
+      }
+  return match_type;
+}
+
+/* Filter vector by command character with index. */
+enum match_type
+cmd_filter_by_string (char *command, vector v, int index)
+{
+  int i;
+  char *str;
+  struct cmd_element *cmd_element;
+  enum match_type match_type;
+  vector descvec;
+  struct desc *desc;
+  
+  match_type = no_match;
+
+  /* If command and cmd_element string does not match set NULL to vector */
+  for (i = 0; i < vector_max (v); i++) 
+    if ((cmd_element = vector_slot (v, i)) != NULL)
+      {
+	/* If given index is bigger than max string vector of command,
+           set NULL*/
+	if (index >= vector_max (cmd_element->strvec))
+	  vector_slot (v, i) = NULL;
+	else 
+	  {
+	    int j;
+	    int matched = 0;
+
+	    descvec = vector_slot (cmd_element->strvec, index);
+
+	    for (j = 0; j < vector_max (descvec); j++)
+	      {
+		desc = vector_slot (descvec, j);
+		str = desc->cmd;
+
+		if (CMD_VARARG (str))
+		  {
+		    if (match_type < vararg_match)
+		      match_type = vararg_match;
+		    matched++;
+		  }
+		else if (CMD_RANGE (str))
+		  {
+		    if (cmd_range_match (str, command))
+		      {
+			if (match_type < range_match)
+			  match_type = range_match;
+			matched++;
+		      }
+		  }
+		else if (CMD_IPV6 (str))
+		  {
+		    if (cmd_ipv6_match (command) == exact_match)
+		      {
+			if (match_type < ipv6_match)
+			  match_type = ipv6_match;
+			matched++;
+		      }
+		  }
+		else if (CMD_IPV6_PREFIX (str))
+		  {
+		    if (cmd_ipv6_prefix_match (command) == exact_match)
+		      {
+			if (match_type < ipv6_prefix_match)
+			  match_type = ipv6_prefix_match;
+			matched++;
+		      }
+		  }
+		else if (CMD_IPV4 (str))
+		  {
+		    if (cmd_ipv4_match (command) == exact_match)
+		      {
+			if (match_type < ipv4_match)
+			  match_type = ipv4_match;
+			matched++;
+		      }
+		  }
+		else if (CMD_IPV4_PREFIX (str))
+		  {
+		    if (cmd_ipv4_prefix_match (command) == exact_match)
+		      {
+			if (match_type < ipv4_prefix_match)
+			  match_type = ipv4_prefix_match;
+			matched++;
+		      }
+		  }
+		else if (CMD_OPTION (str) || CMD_VARIABLE (str))
+		  {
+		    if (match_type < extend_match)
+		      match_type = extend_match;
+		    matched++;
+		  }
+		else
+		  {		  
+		    if (strcmp (command, str) == 0)
+		      {
+			match_type = exact_match;
+			matched++;
+		      }
+		  }
+	      }
+	    if (! matched)
+	      vector_slot (v, i) = NULL;
+	  }
+      }
+  return match_type;
+}
+
+/* Check ambiguous match */
+int
+is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
+{
+  int i;
+  int j;
+  char *str = NULL;
+  struct cmd_element *cmd_element;
+  char *matched = NULL;
+  vector descvec;
+  struct desc *desc;
+  
+  for (i = 0; i < vector_max (v); i++) 
+    if ((cmd_element = vector_slot (v, i)) != NULL)
+      {
+	int match = 0;
+
+	descvec = vector_slot (cmd_element->strvec, index);
+
+	for (j = 0; j < vector_max (descvec); j++)
+	  {
+	    enum match_type ret;
+
+	    desc = vector_slot (descvec, j);
+	    str = desc->cmd;
+
+	    switch (type)
+	      {
+	      case exact_match:
+		if (! (CMD_OPTION (str) || CMD_VARIABLE (str))
+		    && strcmp (command, str) == 0)
+		  match++;
+		break;
+	      case partly_match:
+		if (! (CMD_OPTION (str) || CMD_VARIABLE (str))
+		    && strncmp (command, str, strlen (command)) == 0)
+		  {
+		    if (matched && strcmp (matched, str) != 0)
+		      return 1;	/* There is ambiguous match. */
+		    else
+		      matched = str;
+		    match++;
+		  }
+		break;
+	      case range_match:
+		if (cmd_range_match (str, command))
+		  {
+		    if (matched && strcmp (matched, str) != 0)
+		      return 1;
+		    else
+		      matched = str;
+		    match++;
+		  }
+		break;
+ 	      case ipv6_match:
+		if (CMD_IPV6 (str))
+		  match++;
+		break;
+	      case ipv6_prefix_match:
+		if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
+		  {
+		    if (ret == partly_match)
+		      return 2; /* There is incomplete match. */
+
+		    match++;
+		  }
+		break;
+	      case ipv4_match:
+		if (CMD_IPV4 (str))
+		  match++;
+		break;
+	      case ipv4_prefix_match:
+		if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
+		  {
+		    if (ret == partly_match)
+		      return 2; /* There is incomplete match. */
+
+		    match++;
+		  }
+		break;
+	      case extend_match:
+		if (CMD_OPTION (str) || CMD_VARIABLE (str))
+		  match++;
+		break;
+	      case no_match:
+	      default:
+		break;
+	      }
+	  }
+	if (! match)
+	  vector_slot (v, i) = NULL;
+      }
+  return 0;
+}
+
+/* If src matches dst return dst string, otherwise return NULL */
+char *
+cmd_entry_function (char *src, char *dst)
+{
+  /* Skip variable arguments. */
+  if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
+      CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
+    return NULL;
+
+  /* In case of 'command \t', given src is NULL string. */
+  if (src == NULL)
+    return dst;
+
+  /* Matched with input string. */
+  if (strncmp (src, dst, strlen (src)) == 0)
+    return dst;
+
+  return NULL;
+}
+
+/* If src matches dst return dst string, otherwise return NULL */
+/* This version will return the dst string always if it is
+   CMD_VARIABLE for '?' key processing */
+char *
+cmd_entry_function_desc (char *src, char *dst)
+{
+  if (CMD_VARARG (dst))
+    return dst;
+
+  if (CMD_RANGE (dst))
+    {
+      if (cmd_range_match (dst, src))
+	return dst;
+      else
+	return NULL;
+    }
+
+  if (CMD_IPV6 (dst))
+    {
+      if (cmd_ipv6_match (src))
+	return dst;
+      else
+	return NULL;
+    }
+
+  if (CMD_IPV6_PREFIX (dst))
+    {
+      if (cmd_ipv6_prefix_match (src))
+	return dst;
+      else
+	return NULL;
+    }
+
+  if (CMD_IPV4 (dst))
+    {
+      if (cmd_ipv4_match (src))
+	return dst;
+      else
+	return NULL;
+    }
+
+  if (CMD_IPV4_PREFIX (dst))
+    {
+      if (cmd_ipv4_prefix_match (src))
+	return dst;
+      else
+	return NULL;
+    }
+
+  /* Optional or variable commands always match on '?' */
+  if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
+    return dst;
+
+  /* In case of 'command \t', given src is NULL string. */
+  if (src == NULL)
+    return dst;
+
+  if (strncmp (src, dst, strlen (src)) == 0)
+    return dst;
+  else
+    return NULL;
+}
+
+/* Check same string element existence.  If it isn't there return
+    1. */
+int
+cmd_unique_string (vector v, char *str)
+{
+  int i;
+  char *match;
+
+  for (i = 0; i < vector_max (v); i++)
+    if ((match = vector_slot (v, i)) != NULL)
+      if (strcmp (match, str) == 0)
+	return 0;
+  return 1;
+}
+
+/* Compare string to description vector.  If there is same string
+   return 1 else return 0. */
+int
+desc_unique_string (vector v, char *str)
+{
+  int i;
+  struct desc *desc;
+
+  for (i = 0; i < vector_max (v); i++)
+    if ((desc = vector_slot (v, i)) != NULL)
+      if (strcmp (desc->cmd, str) == 0)
+	return 1;
+  return 0;
+}
+
+/* '?' describe command support. */
+vector
+cmd_describe_command (vector vline, struct vty *vty, int *status)
+{
+  int i;
+  vector cmd_vector;
+#define INIT_MATCHVEC_SIZE 10
+  vector matchvec;
+  struct cmd_element *cmd_element;
+  int index;
+  static struct desc desc_cr = { "<cr>", "" };
+
+  /* Set index. */
+  index = vector_max (vline) - 1;
+
+  /* Make copy vector of current node's command vector. */
+  cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+
+  /* Prepare match vector */
+  matchvec = vector_init (INIT_MATCHVEC_SIZE);
+
+  /* Filter commands. */
+  for (i = 0; i < index; i++)
+    {
+      enum match_type match;
+      char *command;
+      int ret;
+
+      command = vector_slot (vline, i);
+
+      match = cmd_filter_by_completion (command, cmd_vector, i);
+
+      if (match == vararg_match)
+	{
+	  struct cmd_element *cmd_element;
+	  vector descvec;
+	  int j, k;
+
+	  for (j = 0; j < vector_max (cmd_vector); j++)
+	    if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
+	      {
+		descvec = vector_slot (cmd_element->strvec,
+				       vector_max (cmd_element->strvec) - 1);
+		for (k = 0; k < vector_max (descvec); k++)
+		  {
+		    struct desc *desc = vector_slot (descvec, k);
+		    vector_set (matchvec, desc);
+		  }
+	      }
+
+	  vector_set (matchvec, &desc_cr);
+
+	  vector_free (cmd_vector);
+
+	  return matchvec;
+	}
+
+      if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
+	{
+	  vector_free (cmd_vector);
+	  *status = CMD_ERR_AMBIGUOUS;
+	  return NULL;
+	}
+      else if (ret == 2)
+	{
+	  vector_free (cmd_vector);
+	  *status = CMD_ERR_NO_MATCH;
+	  return NULL;
+	}
+    }
+
+  /* Prepare match vector */
+  /*  matchvec = vector_init (INIT_MATCHVEC_SIZE); */
+
+  /* Make description vector. */
+  for (i = 0; i < vector_max (cmd_vector); i++)
+    if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
+      {
+	char *string = NULL;
+	vector strvec = cmd_element->strvec;
+
+	if (index > vector_max (strvec))
+	  vector_slot (cmd_vector, i) = NULL;
+	else
+	  {
+	    /* Check is command is completed. */
+	    if (index == vector_max (strvec))
+	      {
+		string = "<cr>";
+		if (! desc_unique_string (matchvec, string))
+		  vector_set (matchvec, &desc_cr);
+	      }
+	    else
+	      {
+		int j;
+		vector descvec = vector_slot (strvec, index);
+		struct desc *desc;
+
+		for (j = 0; j < vector_max (descvec); j++)
+		  {
+		    desc = vector_slot (descvec, j);
+		    string = cmd_entry_function_desc (vector_slot (vline, index), desc->cmd);
+		    if (string)
+		      {
+			/* Uniqueness check */
+			if (! desc_unique_string (matchvec, string))
+			  vector_set (matchvec, desc);
+		      }
+		  }
+	      }
+	  }
+      }
+  vector_free (cmd_vector);
+
+  if (vector_slot (matchvec, 0) == NULL)
+    {
+      vector_free (matchvec);
+      *status= CMD_ERR_NO_MATCH;
+    }
+  else
+    *status = CMD_SUCCESS;
+
+  return matchvec;
+}
+
+/* Check LCD of matched command. */
+int
+cmd_lcd (char **matched)
+{
+  int i;
+  int j;
+  int lcd = -1;
+  char *s1, *s2;
+  char c1, c2;
+
+  if (matched[0] == NULL || matched[1] == NULL)
+    return 0;
+
+  for (i = 1; matched[i] != NULL; i++)
+    {
+      s1 = matched[i - 1];
+      s2 = matched[i];
+
+      for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
+	if (c1 != c2)
+	  break;
+
+      if (lcd < 0)
+	lcd = j;
+      else
+	{
+	  if (lcd > j)
+	    lcd = j;
+	}
+    }
+  return lcd;
+}
+
+/* Command line completion support. */
+char **
+cmd_complete_command (vector vline, struct vty *vty, int *status)
+{
+  int i;
+  vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+#define INIT_MATCHVEC_SIZE 10
+  vector matchvec;
+  struct cmd_element *cmd_element;
+  int index = vector_max (vline) - 1;
+  char **match_str;
+  struct desc *desc;
+  vector descvec;
+  char *command;
+  int lcd;
+
+  /* First, filter by preceeding command string */
+  for (i = 0; i < index; i++)
+    {
+      enum match_type match;
+      int ret;
+
+      command = vector_slot (vline, i);
+
+      /* First try completion match, if there is exactly match return 1 */
+      match = cmd_filter_by_completion (command, cmd_vector, i);
+
+      /* If there is exact match then filter ambiguous match else check
+	 ambiguousness. */
+      if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
+	{
+	  vector_free (cmd_vector);
+	  *status = CMD_ERR_AMBIGUOUS;
+	  return NULL;
+	}
+      /*
+	else if (ret == 2)
+	{
+	  vector_free (cmd_vector);
+	  *status = CMD_ERR_NO_MATCH;
+	  return NULL;
+	}
+      */
+    }
+
+  /* Prepare match vector. */
+  matchvec = vector_init (INIT_MATCHVEC_SIZE);
+
+  /* Now we got into completion */
+  for (i = 0; i < vector_max (cmd_vector); i++)
+    if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
+      {
+	char *string;
+	vector strvec = cmd_element->strvec;
+	
+	/* Check field length */
+	if (index >= vector_max (strvec))
+	  vector_slot (cmd_vector, i) = NULL;
+	else 
+	  {
+	    int j;
+
+	    descvec = vector_slot (strvec, index);
+	    for (j = 0; j < vector_max (descvec); j++)
+	      {
+		desc = vector_slot (descvec, j);
+
+		if ((string = cmd_entry_function (vector_slot (vline, index),
+						  desc->cmd)))
+		  if (cmd_unique_string (matchvec, string))
+		    vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
+	      }
+	  }
+      }
+
+  /* We don't need cmd_vector any more. */
+  vector_free (cmd_vector);
+
+  /* No matched command */
+  if (vector_slot (matchvec, 0) == NULL)
+    {
+      vector_free (matchvec);
+
+      /* In case of 'command \t' pattern.  Do you need '?' command at
+         the end of the line. */
+      if (vector_slot (vline, index) == '\0')
+	*status = CMD_ERR_NOTHING_TODO;
+      else
+	*status = CMD_ERR_NO_MATCH;
+      return NULL;
+    }
+
+  /* Only one matched */
+  if (vector_slot (matchvec, 1) == NULL)
+    {
+      match_str = (char **) matchvec->index;
+      vector_only_wrapper_free (matchvec);
+      *status = CMD_COMPLETE_FULL_MATCH;
+      return match_str;
+    }
+  /* Make it sure last element is NULL. */
+  vector_set (matchvec, NULL);
+
+  /* Check LCD of matched strings. */
+  if (vector_slot (vline, index) != NULL)
+    {
+      lcd = cmd_lcd ((char **) matchvec->index);
+
+      if (lcd)
+	{
+	  int len = strlen (vector_slot (vline, index));
+	  
+	  if (len < lcd)
+	    {
+	      char *lcdstr;
+	      
+	      lcdstr = XMALLOC (MTYPE_TMP, lcd + 1);
+	      memcpy (lcdstr, matchvec->index[0], lcd);
+	      lcdstr[lcd] = '\0';
+
+	      /* match_str = (char **) &lcdstr; */
+
+	      /* Free matchvec. */
+	      for (i = 0; i < vector_max (matchvec); i++)
+		{
+		  if (vector_slot (matchvec, i))
+		    XFREE (MTYPE_TMP, vector_slot (matchvec, i));
+		}
+	      vector_free (matchvec);
+
+      	      /* Make new matchvec. */
+	      matchvec = vector_init (INIT_MATCHVEC_SIZE);
+	      vector_set (matchvec, lcdstr);
+	      match_str = (char **) matchvec->index;
+	      vector_only_wrapper_free (matchvec);
+
+	      *status = CMD_COMPLETE_MATCH;
+	      return match_str;
+	    }
+	}
+    }
+
+  match_str = (char **) matchvec->index;
+  vector_only_wrapper_free (matchvec);
+  *status = CMD_COMPLETE_LIST_MATCH;
+  return match_str;
+}
+
+/* Execute command by argument vline vector. */
+int
+cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd)
+{
+  int i;
+  int index;
+  vector cmd_vector;
+  struct cmd_element *cmd_element;
+  struct cmd_element *matched_element;
+  unsigned int matched_count, incomplete_count;
+  int argc;
+  char *argv[CMD_ARGC_MAX];
+  enum match_type match = 0;
+  int varflag;
+  char *command;
+
+  /* Make copy of command elements. */
+  cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+
+  for (index = 0; index < vector_max (vline); index++) 
+    {
+      int ret;
+
+      command = vector_slot (vline, index);
+
+      match = cmd_filter_by_completion (command, cmd_vector, index);
+
+      if (match == vararg_match)
+	break;
+
+      ret = is_cmd_ambiguous (command, cmd_vector, index, match);
+
+      if (ret == 1)
+	{
+	  vector_free (cmd_vector);
+	  return CMD_ERR_AMBIGUOUS;
+	}
+      else if (ret == 2)
+	{
+	  vector_free (cmd_vector);
+	  return CMD_ERR_NO_MATCH;
+	}
+    }
+
+  /* Check matched count. */
+  matched_element = NULL;
+  matched_count = 0;
+  incomplete_count = 0;
+
+  for (i = 0; i < vector_max (cmd_vector); i++) 
+    if (vector_slot (cmd_vector,i) != NULL)
+      {
+	cmd_element = vector_slot (cmd_vector,i);
+
+	if (match == vararg_match || index >= cmd_element->cmdsize)
+	  {
+	    matched_element = cmd_element;
+#if 0
+	    printf ("DEBUG: %s\n", cmd_element->string);
+#endif
+	    matched_count++;
+	  }
+	else
+	  {
+	    incomplete_count++;
+	  }
+      }
+  
+  /* Finish of using cmd_vector. */
+  vector_free (cmd_vector);
+
+  /* To execute command, matched_count must be 1.*/
+  if (matched_count == 0) 
+    {
+      if (incomplete_count)
+	return CMD_ERR_INCOMPLETE;
+      else
+	return CMD_ERR_NO_MATCH;
+    }
+
+  if (matched_count > 1) 
+    return CMD_ERR_AMBIGUOUS;
+
+  /* Argument treatment */
+  varflag = 0;
+  argc = 0;
+
+  for (i = 0; i < vector_max (vline); i++)
+    {
+      if (varflag)
+	argv[argc++] = vector_slot (vline, i);
+      else
+	{	  
+	  vector descvec = vector_slot (matched_element->strvec, i);
+
+	  if (vector_max (descvec) == 1)
+	    {
+	      struct desc *desc = vector_slot (descvec, 0);
+	      char *str = desc->cmd;
+
+	      if (CMD_VARARG (str))
+		varflag = 1;
+
+	      if (varflag || CMD_VARIABLE (str) || CMD_OPTION (str))
+		argv[argc++] = vector_slot (vline, i);
+	    }
+	  else
+	    argv[argc++] = vector_slot (vline, i);
+	}
+
+      if (argc >= CMD_ARGC_MAX)
+	return CMD_ERR_EXEED_ARGC_MAX;
+    }
+
+  /* For vtysh execution. */
+  if (cmd)
+    *cmd = matched_element;
+
+  if (matched_element->daemon)
+    return CMD_SUCCESS_DAEMON;
+
+  /* Execute matched command. */
+  return (*matched_element->func) (matched_element, vty, argc, argv);
+}
+
+/* Execute command by argument readline. */
+int
+cmd_execute_command_strict (vector vline, struct vty *vty, 
+			    struct cmd_element **cmd)
+{
+  int i;
+  int index;
+  vector cmd_vector;
+  struct cmd_element *cmd_element;
+  struct cmd_element *matched_element;
+  unsigned int matched_count, incomplete_count;
+  int argc;
+  char *argv[CMD_ARGC_MAX];
+  int varflag;
+  enum match_type match = 0;
+  char *command;
+
+  /* Make copy of command element */
+  cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
+
+  for (index = 0; index < vector_max (vline); index++) 
+    {
+      int ret;
+
+      command = vector_slot (vline, index);
+
+      match = cmd_filter_by_string (vector_slot (vline, index), 
+				    cmd_vector, index);
+
+      /* If command meets '.VARARG' then finish matching. */
+      if (match == vararg_match)
+	break;
+
+      ret = is_cmd_ambiguous (command, cmd_vector, index, match);
+      if (ret == 1)
+	{
+	  vector_free (cmd_vector);
+	  return CMD_ERR_AMBIGUOUS;
+	}
+      if (ret == 2)
+	{
+	  vector_free (cmd_vector);
+	  return CMD_ERR_NO_MATCH;
+	}
+    }
+
+  /* Check matched count. */
+  matched_element = NULL;
+  matched_count = 0;
+  incomplete_count = 0;
+  for (i = 0; i < vector_max (cmd_vector); i++) 
+    if (vector_slot (cmd_vector,i) != NULL)
+      {
+	cmd_element = vector_slot (cmd_vector,i);
+
+	if (match == vararg_match || index >= cmd_element->cmdsize)
+	  {
+	    matched_element = cmd_element;
+	    matched_count++;
+	  }
+	else
+	  incomplete_count++;
+      }
+  
+  /* Finish of using cmd_vector. */
+  vector_free (cmd_vector);
+
+  /* To execute command, matched_count must be 1.*/
+  if (matched_count == 0) 
+    {
+      if (incomplete_count)
+	return CMD_ERR_INCOMPLETE;
+      else
+	return CMD_ERR_NO_MATCH;
+    }
+
+  if (matched_count > 1) 
+    return CMD_ERR_AMBIGUOUS;
+
+  /* Argument treatment */
+  varflag = 0;
+  argc = 0;
+
+  for (i = 0; i < vector_max (vline); i++)
+    {
+      if (varflag)
+	argv[argc++] = vector_slot (vline, i);
+      else
+	{	  
+	  vector descvec = vector_slot (matched_element->strvec, i);
+
+	  if (vector_max (descvec) == 1)
+	    {
+	      struct desc *desc = vector_slot (descvec, 0);
+	      char *str = desc->cmd;
+
+	      if (CMD_VARARG (str))
+		varflag = 1;
+	  
+	      if (varflag || CMD_VARIABLE (str) || CMD_OPTION (str))
+		argv[argc++] = vector_slot (vline, i);
+	    }
+	  else
+	    argv[argc++] = vector_slot (vline, i);
+	}
+
+      if (argc >= CMD_ARGC_MAX)
+	return CMD_ERR_EXEED_ARGC_MAX;
+    }
+
+  /* For vtysh execution. */
+  if (cmd)
+    *cmd = matched_element;
+
+  if (matched_element->daemon)
+    return CMD_SUCCESS_DAEMON;
+
+  /* Now execute matched command */
+  return (*matched_element->func) (matched_element, vty, argc, argv);
+}
+
+/* Configration make from file. */
+int
+config_from_file (struct vty *vty, FILE *fp)
+{
+  int ret;
+  vector vline;
+
+  while (fgets (vty->buf, VTY_BUFSIZ, fp))
+    {
+      vline = cmd_make_strvec (vty->buf);
+
+      /* In case of comment line */
+      if (vline == NULL)
+	continue;
+      /* Execute configuration command : this is strict match */
+      ret = cmd_execute_command_strict (vline, vty, NULL);
+
+      /* Try again with setting node to CONFIG_NODE */
+      if (ret != CMD_SUCCESS && ret != CMD_WARNING)
+	{
+	  if (vty->node == KEYCHAIN_KEY_NODE)
+	    {
+	      vty->node = KEYCHAIN_NODE;
+
+	      ret = cmd_execute_command_strict (vline, vty, NULL);
+
+	      if (ret != CMD_SUCCESS && ret != CMD_WARNING)
+		{
+		  vty->node = CONFIG_NODE;
+		  ret = cmd_execute_command_strict (vline, vty, NULL);
+		}
+	    }
+	  else
+	    {
+	      vty->node = CONFIG_NODE;
+	      ret = cmd_execute_command_strict (vline, vty, NULL);
+	    }
+	}	  
+
+      cmd_free_strvec (vline);
+
+      if (ret != CMD_SUCCESS && ret != CMD_WARNING)
+	return ret;
+    }
+  return CMD_SUCCESS;
+}
+
+/* Configration from terminal */
+DEFUN (config_terminal,
+       config_terminal_cmd,
+       "configure terminal",
+       "Configuration from vty interface\n"
+       "Configuration terminal\n")
+{
+  if (vty_config_lock (vty))
+    vty->node = CONFIG_NODE;
+  else
+    {
+      vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}
+
+/* Enable command */
+DEFUN (enable, 
+       config_enable_cmd,
+       "enable",
+       "Turn on privileged mode command\n")
+{
+  /* If enable password is NULL, change to ENABLE_NODE */
+  if ((host.enable == NULL && host.enable_encrypt == NULL) ||
+      vty->type == VTY_SHELL_SERV)
+    vty->node = ENABLE_NODE;
+  else
+    vty->node = AUTH_ENABLE_NODE;
+
+  return CMD_SUCCESS;
+}
+
+/* Disable command */
+DEFUN (disable, 
+       config_disable_cmd,
+       "disable",
+       "Turn off privileged mode command\n")
+{
+  if (vty->node == ENABLE_NODE)
+    vty->node = VIEW_NODE;
+  return CMD_SUCCESS;
+}
+
+/* Down vty node level. */
+DEFUN (config_exit,
+       config_exit_cmd,
+       "exit",
+       "Exit current mode and down to previous mode\n")
+{
+  switch (vty->node)
+    {
+    case VIEW_NODE:
+    case ENABLE_NODE:
+      if (vty_shell (vty))
+	exit (0);
+      else
+	vty->status = VTY_CLOSE;
+      break;
+    case CONFIG_NODE:
+      vty->node = ENABLE_NODE;
+      vty_config_unlock (vty);
+      break;
+    case INTERFACE_NODE:
+    case ZEBRA_NODE:
+    case BGP_NODE:
+    case RIP_NODE:
+    case RIPNG_NODE:
+    case OSPF_NODE:
+    case OSPF6_NODE:
+    case KEYCHAIN_NODE:
+    case MASC_NODE:
+    case RMAP_NODE:
+    case VTY_NODE:
+      vty->node = CONFIG_NODE;
+      break;
+    case BGP_VPNV4_NODE:
+    case BGP_IPV4_NODE:
+    case BGP_IPV4M_NODE:
+    case BGP_IPV6_NODE:
+      vty->node = BGP_NODE;
+      break;
+    case KEYCHAIN_KEY_NODE:
+      vty->node = KEYCHAIN_NODE;
+      break;
+    default:
+      break;
+    }
+  return CMD_SUCCESS;
+}
+
+/* quit is alias of exit. */
+ALIAS (config_exit,
+       config_quit_cmd,
+       "quit",
+       "Exit current mode and down to previous mode\n")
+       
+/* End of configuration. */
+DEFUN (config_end,
+       config_end_cmd,
+       "end",
+       "End current mode and change to enable mode.")
+{
+  switch (vty->node)
+    {
+    case VIEW_NODE:
+    case ENABLE_NODE:
+      /* Nothing to do. */
+      break;
+    case CONFIG_NODE:
+    case INTERFACE_NODE:
+    case ZEBRA_NODE:
+    case RIP_NODE:
+    case RIPNG_NODE:
+    case BGP_NODE:
+    case BGP_VPNV4_NODE:
+    case BGP_IPV4_NODE:
+    case BGP_IPV4M_NODE:
+    case BGP_IPV6_NODE:
+    case RMAP_NODE:
+    case OSPF_NODE:
+    case OSPF6_NODE:
+    case KEYCHAIN_NODE:
+    case KEYCHAIN_KEY_NODE:
+    case MASC_NODE:
+    case VTY_NODE:
+      vty_config_unlock (vty);
+      vty->node = ENABLE_NODE;
+      break;
+    default:
+      break;
+    }
+  return CMD_SUCCESS;
+}
+
+/* Show version. */
+DEFUN (show_version,
+       show_version_cmd,
+       "show version",
+       SHOW_STR
+       "Displays zebra version\n")
+{
+  vty_out (vty, "Zebra %s (%s).%s", ZEBRA_VERSION,
+	   host_name,
+	   VTY_NEWLINE);
+  vty_out (vty, "Copyright 1996-2002, Kunihiro Ishiguro.%s", VTY_NEWLINE);
+
+  return CMD_SUCCESS;
+}
+
+/* Help display function for all node. */
+DEFUN (config_help,
+       config_help_cmd,
+       "help",
+       "Description of the interactive help system\n")
+{
+  vty_out (vty, 
+	   "Zebra VTY provides advanced help feature.  When you need help,%s\
+anytime at the command line please press '?'.%s\
+%s\
+If nothing matches, the help list will be empty and you must backup%s\
+ until entering a '?' shows the available options.%s\
+Two styles of help are provided:%s\
+1. Full help is available when you are ready to enter a%s\
+command argument (e.g. 'show ?') and describes each possible%s\
+argument.%s\
+2. Partial help is provided when an abbreviated argument is entered%s\
+   and you want to know what arguments match the input%s\
+   (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
+	   VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
+	   VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+  return CMD_SUCCESS;
+}
+
+/* Help display function for all node. */
+DEFUN (config_list,
+       config_list_cmd,
+       "list",
+       "Print command list\n")
+{
+  int i;
+  struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
+  struct cmd_element *cmd;
+
+  for (i = 0; i < vector_max (cnode->cmd_vector); i++)
+    if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL)
+      vty_out (vty, "  %s%s", cmd->string,
+	       VTY_NEWLINE);
+  return CMD_SUCCESS;
+}
+
+/* Write current configuration into file. */
+DEFUN (config_write_file, 
+       config_write_file_cmd,
+       "write file",  
+       "Write running configuration to memory, network, or terminal\n"
+       "Write to configuration file\n")
+{
+  int i;
+  int fd;
+  struct cmd_node *node;
+  char *config_file;
+  char *config_file_tmp = NULL;
+  char *config_file_sav = NULL;
+  struct vty *file_vty;
+
+  /* Check and see if we are operating under vtysh configuration */
+  if (host.config == NULL)
+    {
+      vty_out (vty, "Can't save to configuration file, using vtysh.%s",
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Get filename. */
+  config_file = host.config;
+  
+  config_file_sav = malloc (strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
+  strcpy (config_file_sav, config_file);
+  strcat (config_file_sav, CONF_BACKUP_EXT);
+
+
+  config_file_tmp = malloc (strlen (config_file) + 8);
+  sprintf (config_file_tmp, "%s.XXXXXX", config_file);
+  
+  /* Open file to configuration write. */
+  fd = mkstemp (config_file_tmp);
+  if (fd < 0)
+    {
+      vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
+	       VTY_NEWLINE);
+      free (config_file_tmp);
+      free (config_file_sav);
+      return CMD_WARNING;
+    }
+  
+  /* Make vty for configuration file. */
+  file_vty = vty_new ();
+  file_vty->fd = fd;
+  file_vty->type = VTY_FILE;
+
+  /* Config file header print. */
+  vty_out (file_vty, "!\n! Zebra configuration saved from vty\n!   ");
+  vty_time_print (file_vty, 1);
+  vty_out (file_vty, "!\n");
+
+  for (i = 0; i < vector_max (cmdvec); i++)
+    if ((node = vector_slot (cmdvec, i)) && node->func)
+      {
+	if ((*node->func) (file_vty))
+	  vty_out (file_vty, "!\n");
+      }
+  vty_close (file_vty);
+
+  if (unlink (config_file_sav) != 0)
+    if (errno != ENOENT)
+      {
+	vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
+		 VTY_NEWLINE);
+	free (config_file_sav);
+	free (config_file_tmp);
+	unlink (config_file_tmp);	
+	return CMD_WARNING;
+      }
+  if (link (config_file, config_file_sav) != 0)
+    {
+      vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
+	        VTY_NEWLINE);
+      free (config_file_sav);
+      free (config_file_tmp);
+      unlink (config_file_tmp);
+      return CMD_WARNING;
+    }
+  sync ();
+  if (unlink (config_file) != 0)
+    {
+      vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
+	        VTY_NEWLINE);
+      free (config_file_sav);
+      free (config_file_tmp);
+      unlink (config_file_tmp);
+      return CMD_WARNING;      
+    }
+  if (link (config_file_tmp, config_file) != 0)
+    {
+      vty_out (vty, "Can't save configuration file %s.%s", config_file,
+	       VTY_NEWLINE);
+      free (config_file_sav);
+      free (config_file_tmp);
+      unlink (config_file_tmp);
+      return CMD_WARNING;      
+    }
+  unlink (config_file_tmp);
+  sync ();
+  
+  free (config_file_sav);
+  free (config_file_tmp);
+  vty_out (vty, "Configuration saved to %s%s", config_file,
+	   VTY_NEWLINE);
+  return CMD_SUCCESS;
+}
+
+ALIAS (config_write_file, 
+       config_write_cmd,
+       "write",  
+       "Write running configuration to memory, network, or terminal\n")
+
+ALIAS (config_write_file, 
+       config_write_memory_cmd,
+       "write memory",  
+       "Write running configuration to memory, network, or terminal\n"
+       "Write configuration to the file (same as write file)\n")
+
+ALIAS (config_write_file, 
+       copy_runningconfig_startupconfig_cmd,
+       "copy running-config startup-config",  
+       "Copy configuration\n"
+       "Copy running config to... \n"
+       "Copy running config to startup config (same as write file)\n")
+
+/* Write current configuration into the terminal. */
+DEFUN (config_write_terminal,
+       config_write_terminal_cmd,
+       "write terminal",
+       "Write running configuration to memory, network, or terminal\n"
+       "Write to terminal\n")
+{
+  int i;
+  struct cmd_node *node;
+
+  if (vty->type == VTY_SHELL_SERV)
+    {
+      for (i = 0; i < vector_max (cmdvec); i++)
+	if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
+	  {
+	    if ((*node->func) (vty))
+	      vty_out (vty, "!%s", VTY_NEWLINE);
+	  }
+    }
+  else
+    {
+      vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
+	       VTY_NEWLINE);
+      vty_out (vty, "!%s", VTY_NEWLINE);
+
+      for (i = 0; i < vector_max (cmdvec); i++)
+	if ((node = vector_slot (cmdvec, i)) && node->func)
+	  {
+	    if ((*node->func) (vty))
+	      vty_out (vty, "!%s", VTY_NEWLINE);
+	  }
+      vty_out (vty, "end%s",VTY_NEWLINE);
+    }
+  return CMD_SUCCESS;
+}
+
+/* Write current configuration into the terminal. */
+ALIAS (config_write_terminal,
+       show_running_config_cmd,
+       "show running-config",
+       SHOW_STR
+       "running configuration\n")
+
+/* Write startup configuration into the terminal. */
+DEFUN (show_startup_config,
+       show_startup_config_cmd,
+       "show startup-config",
+       SHOW_STR
+       "Contentes of startup configuration\n")
+{
+  char buf[BUFSIZ];
+  FILE *confp;
+
+  confp = fopen (host.config, "r");
+  if (confp == NULL)
+    {
+      vty_out (vty, "Can't open configuration file [%s]%s",
+	       host.config, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  while (fgets (buf, BUFSIZ, confp))
+    {
+      char *cp = buf;
+
+      while (*cp != '\r' && *cp != '\n' && *cp != '\0')
+	cp++;
+      *cp = '\0';
+
+      vty_out (vty, "%s%s", buf, VTY_NEWLINE);
+    }
+
+  fclose (confp);
+
+  return CMD_SUCCESS;
+}
+
+/* Hostname configuration */
+DEFUN (config_hostname, 
+       hostname_cmd,
+       "hostname WORD",
+       "Set system's network name\n"
+       "This system's network name\n")
+{
+  if (!isalpha((int) *argv[0]))
+    {
+      vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (host.name)
+    XFREE (0, host.name);
+    
+  host.name = strdup (argv[0]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (config_no_hostname, 
+       no_hostname_cmd,
+       "no hostname [HOSTNAME]",
+       NO_STR
+       "Reset system's network name\n"
+       "Host name of this router\n")
+{
+  if (host.name)
+    XFREE (0, host.name);
+  host.name = NULL;
+  return CMD_SUCCESS;
+}
+
+/* VTY interface password set. */
+DEFUN (config_password, password_cmd,
+       "password (8|) WORD",
+       "Assign the terminal connection password\n"
+       "Specifies a HIDDEN password will follow\n"
+       "dummy string \n"
+       "The HIDDEN line password string\n")
+{
+  /* Argument check. */
+  if (argc == 0)
+    {
+      vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (argc == 2)
+    {
+      if (*argv[0] == '8')
+	{
+	  if (host.password)
+	    XFREE (0, host.password);
+	  host.password = NULL;
+	  if (host.password_encrypt)
+	    XFREE (0, host.password_encrypt);
+	  host.password_encrypt = XSTRDUP (0, strdup (argv[1]));
+	  return CMD_SUCCESS;
+	}
+      else
+	{
+	  vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+
+  if (!isalnum ((int) *argv[0]))
+    {
+      vty_out (vty, 
+	       "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (host.password)
+    XFREE (0, host.password);
+  host.password = NULL;
+
+  if (host.encrypt)
+    {
+      if (host.password_encrypt)
+	XFREE (0, host.password_encrypt);
+      host.password_encrypt = XSTRDUP (0, zencrypt (argv[0]));
+    }
+  else
+    host.password = XSTRDUP (0, argv[0]);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (config_password, password_text_cmd,
+       "password LINE",
+       "Assign the terminal connection password\n"
+       "The UNENCRYPTED (cleartext) line password\n")
+
+/* VTY enable password set. */
+DEFUN (config_enable_password, enable_password_cmd,
+       "enable password (8|) WORD",
+       "Modify enable password parameters\n"
+       "Assign the privileged level password\n"
+       "Specifies a HIDDEN password will follow\n"
+       "dummy string \n"
+       "The HIDDEN 'enable' password string\n")
+{
+  /* Argument check. */
+  if (argc == 0)
+    {
+      vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Crypt type is specified. */
+  if (argc == 2)
+    {
+      if (*argv[0] == '8')
+	{
+	  if (host.enable)
+	    XFREE (0, host.enable);
+	  host.enable = NULL;
+
+	  if (host.enable_encrypt)
+	    XFREE (0, host.enable_encrypt);
+	  host.enable_encrypt = XSTRDUP (0, argv[1]);
+
+	  return CMD_SUCCESS;
+	}
+      else
+	{
+	  vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+
+  if (!isalnum ((int) *argv[0]))
+    {
+      vty_out (vty, 
+	       "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (host.enable)
+    XFREE (0, host.enable);
+  host.enable = NULL;
+
+  /* Plain password input. */
+  if (host.encrypt)
+    {
+      if (host.enable_encrypt)
+	XFREE (0, host.enable_encrypt);
+      host.enable_encrypt = XSTRDUP (0, zencrypt (argv[0]));
+    }
+  else
+    host.enable = XSTRDUP (0, argv[0]);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (config_enable_password,
+       enable_password_text_cmd,
+       "enable password LINE",
+       "Modify enable password parameters\n"
+       "Assign the privileged level password\n"
+       "The UNENCRYPTED (cleartext) 'enable' password\n")
+
+/* VTY enable password delete. */
+DEFUN (no_config_enable_password, no_enable_password_cmd,
+       "no enable password",
+       NO_STR
+       "Modify enable password parameters\n"
+       "Assign the privileged level password\n")
+{
+  if (host.enable)
+    XFREE (0, host.enable);
+  host.enable = NULL;
+
+  if (host.enable_encrypt)
+    XFREE (0, host.enable_encrypt);
+  host.enable_encrypt = NULL;
+
+  return CMD_SUCCESS;
+}
+	
+DEFUN (service_password_encrypt,
+       service_password_encrypt_cmd,
+       "service password-encryption",
+       "Set up miscellaneous service\n"
+       "Enable encrypted passwords\n")
+{
+  if (host.encrypt)
+    return CMD_SUCCESS;
+
+  host.encrypt = 1;
+
+  if (host.password)
+    {
+      if (host.password_encrypt)
+	XFREE (0, host.password_encrypt);
+      host.password_encrypt = XSTRDUP (0, zencrypt (host.password));
+    }
+  if (host.enable)
+    {
+      if (host.enable_encrypt)
+	XFREE (0, host.enable_encrypt);
+      host.enable_encrypt = XSTRDUP (0, zencrypt (host.enable));
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_service_password_encrypt,
+       no_service_password_encrypt_cmd,
+       "no service password-encryption",
+       NO_STR
+       "Set up miscellaneous service\n"
+       "Enable encrypted passwords\n")
+{
+  if (! host.encrypt)
+    return CMD_SUCCESS;
+
+  host.encrypt = 0;
+
+  if (host.password_encrypt)
+    XFREE (0, host.password_encrypt);
+  host.password_encrypt = NULL;
+
+  if (host.enable_encrypt)
+    XFREE (0, host.enable_encrypt);
+  host.enable_encrypt = NULL;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (config_terminal_length, config_terminal_length_cmd,
+       "terminal length <0-512>",
+       "Set terminal line parameters\n"
+       "Set number of lines on a screen\n"
+       "Number of lines on screen (0 for no pausing)\n")
+{
+  int lines;
+  char *endptr = NULL;
+
+  lines = strtol (argv[0], &endptr, 10);
+  if (lines < 0 || lines > 512 || *endptr != '\0')
+    {
+      vty_out (vty, "length is malformed%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  vty->lines = lines;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
+       "terminal no length",
+       "Set terminal line parameters\n"
+       NO_STR
+       "Set number of lines on a screen\n")
+{
+  vty->lines = -1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (service_terminal_length, service_terminal_length_cmd,
+       "service terminal-length <0-512>",
+       "Set up miscellaneous service\n"
+       "System wide terminal length configuration\n"
+       "Number of lines of VTY (0 means no line control)\n")
+{
+  int lines;
+  char *endptr = NULL;
+
+  lines = strtol (argv[0], &endptr, 10);
+  if (lines < 0 || lines > 512 || *endptr != '\0')
+    {
+      vty_out (vty, "length is malformed%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  host.lines = lines;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
+       "no service terminal-length [<0-512>]",
+       NO_STR
+       "Set up miscellaneous service\n"
+       "System wide terminal length configuration\n"
+       "Number of lines of VTY (0 means no line control)\n")
+{
+  host.lines = -1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (config_log_stdout,
+       config_log_stdout_cmd,
+       "log stdout",
+       "Logging control\n"
+       "Logging goes to stdout\n")
+{
+  zlog_set_flag (NULL, ZLOG_STDOUT);
+  host.log_stdout = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_config_log_stdout,
+       no_config_log_stdout_cmd,
+       "no log stdout",
+       NO_STR
+       "Logging control\n"
+       "Cancel logging to stdout\n")
+{
+  zlog_reset_flag (NULL, ZLOG_STDOUT);
+  host.log_stdout = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (config_log_file,
+       config_log_file_cmd,
+       "log file FILENAME",
+       "Logging control\n"
+       "Logging to file\n"
+       "Logging filename\n")
+{
+  int ret;
+  char *cwd;
+  char *fullpath;
+
+  /* Path detection. */
+  if (! IS_DIRECTORY_SEP (*argv[0]))
+    {
+      cwd = getcwd (NULL, MAXPATHLEN);
+      fullpath = XMALLOC (MTYPE_TMP,
+			  strlen (cwd) + strlen (argv[0]) + 2);
+      sprintf (fullpath, "%s/%s", cwd, argv[0]);
+    }
+  else
+    fullpath = argv[0];
+
+  ret = zlog_set_file (NULL, ZLOG_FILE, fullpath);
+
+  if (!ret)
+    {
+      vty_out (vty, "can't open logfile %s\n", argv[0]);
+      return CMD_WARNING;
+    }
+
+  if (host.logfile)
+    XFREE (MTYPE_TMP, host.logfile);
+
+  host.logfile = strdup (argv[0]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_config_log_file,
+       no_config_log_file_cmd,
+       "no log file [FILENAME]",
+       NO_STR
+       "Logging control\n"
+       "Cancel logging to file\n"
+       "Logging file name\n")
+{
+  zlog_reset_file (NULL);
+
+  if (host.logfile)
+    XFREE (MTYPE_TMP, host.logfile);
+
+  host.logfile = NULL;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (config_log_syslog,
+       config_log_syslog_cmd,
+       "log syslog",
+       "Logging control\n"
+       "Logging goes to syslog\n")
+{
+  zlog_set_flag (NULL, ZLOG_SYSLOG);
+  host.log_syslog = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_config_log_syslog,
+       no_config_log_syslog_cmd,
+       "no log syslog",
+       NO_STR
+       "Logging control\n"
+       "Cancel logging to syslog\n")
+{
+  zlog_reset_flag (NULL, ZLOG_SYSLOG);
+  host.log_syslog = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (config_log_trap,
+       config_log_trap_cmd,
+       "log trap (emergencies|alerts|critical|errors|warnings|notifications|informational|debugging)",
+       "Logging control\n"
+       "Limit logging to specifed level\n")
+{
+  int new_level ;
+  
+  for ( new_level = 0 ; zlog_priority [new_level] != NULL ; new_level ++ )
+    {
+    if ( strcmp ( argv[0], zlog_priority [new_level] ) == 0 )
+      /* found new logging level */
+      {
+      zlog_default->maskpri = new_level;
+      return CMD_SUCCESS;
+      }
+    }
+  return CMD_ERR_NO_MATCH;
+}
+
+DEFUN (no_config_log_trap,
+       no_config_log_trap_cmd,
+       "no log trap",
+       NO_STR
+       "Logging control\n"
+       "Permit all logging information\n")
+{
+  zlog_default->maskpri = LOG_DEBUG;
+  return CMD_SUCCESS;
+}
+
+DEFUN (config_log_record_priority,
+       config_log_record_priority_cmd,
+       "log record-priority",
+       "Logging control\n"
+       "Log the priority of the message within the message\n")
+{
+  zlog_default->record_priority = 1 ;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_config_log_record_priority,
+       no_config_log_record_priority_cmd,
+       "no log record-priority",
+       NO_STR
+       "Logging control\n"
+       "Do not log the priority of the message within the message\n")
+{
+  zlog_default->record_priority = 0 ;
+  return CMD_SUCCESS;
+}
+
+
+DEFUN (banner_motd_default,
+       banner_motd_default_cmd,
+       "banner motd default",
+       "Set banner string\n"
+       "Strings for motd\n"
+       "Default string\n")
+{
+  host.motd = default_motd;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_banner_motd,
+       no_banner_motd_cmd,
+       "no banner motd",
+       NO_STR
+       "Set banner string\n"
+       "Strings for motd\n")
+{
+  host.motd = NULL;
+  return CMD_SUCCESS;
+}
+
+/* Set config filename.  Called from vty.c */
+void
+host_config_set (char *filename)
+{
+  host.config = strdup (filename);
+}
+
+void
+install_default (enum node_type node)
+{
+  install_element (node, &config_exit_cmd);
+  install_element (node, &config_quit_cmd);
+  install_element (node, &config_end_cmd);
+  install_element (node, &config_help_cmd);
+  install_element (node, &config_list_cmd);
+
+  install_element (node, &config_write_terminal_cmd);
+  install_element (node, &config_write_file_cmd);
+  install_element (node, &config_write_memory_cmd);
+  install_element (node, &config_write_cmd);
+  install_element (node, &show_running_config_cmd);
+}
+
+/* Initialize command interface. Install basic nodes and commands. */
+void
+cmd_init (int terminal)
+{
+  /* Allocate initial top vector of commands. */
+  cmdvec = vector_init (VECTOR_MIN_SIZE);
+
+  /* Default host value settings. */
+  host.name = NULL;
+  host.password = NULL;
+  host.enable = NULL;
+  host.logfile = NULL;
+  host.config = NULL;
+  host.lines = -1;
+  host.motd = default_motd;
+
+  /* Install top nodes. */
+  install_node (&view_node, NULL);
+  install_node (&enable_node, NULL);
+  install_node (&auth_node, NULL);
+  install_node (&auth_enable_node, NULL);
+  install_node (&config_node, config_write_host);
+
+  /* Each node's basic commands. */
+  install_element (VIEW_NODE, &show_version_cmd);
+  if (terminal)
+    {
+      install_element (VIEW_NODE, &config_list_cmd);
+      install_element (VIEW_NODE, &config_exit_cmd);
+      install_element (VIEW_NODE, &config_quit_cmd);
+      install_element (VIEW_NODE, &config_help_cmd);
+      install_element (VIEW_NODE, &config_enable_cmd);
+      install_element (VIEW_NODE, &config_terminal_length_cmd);
+      install_element (VIEW_NODE, &config_terminal_no_length_cmd);
+    }
+
+  if (terminal)
+    {
+      install_default (ENABLE_NODE);
+      install_element (ENABLE_NODE, &config_disable_cmd);
+      install_element (ENABLE_NODE, &config_terminal_cmd);
+      install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
+    }
+  install_element (ENABLE_NODE, &show_startup_config_cmd);
+  install_element (ENABLE_NODE, &show_version_cmd);
+  install_element (ENABLE_NODE, &config_terminal_length_cmd);
+  install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
+
+  if (terminal)
+    install_default (CONFIG_NODE);
+  install_element (CONFIG_NODE, &hostname_cmd);
+  install_element (CONFIG_NODE, &no_hostname_cmd);
+  install_element (CONFIG_NODE, &password_cmd);
+  install_element (CONFIG_NODE, &password_text_cmd);
+  install_element (CONFIG_NODE, &enable_password_cmd);
+  install_element (CONFIG_NODE, &enable_password_text_cmd);
+  install_element (CONFIG_NODE, &no_enable_password_cmd);
+  if (terminal)
+    {
+      install_element (CONFIG_NODE, &config_log_stdout_cmd);
+      install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
+      install_element (CONFIG_NODE, &config_log_file_cmd);
+      install_element (CONFIG_NODE, &no_config_log_file_cmd);
+      install_element (CONFIG_NODE, &config_log_syslog_cmd);
+      install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
+      install_element (CONFIG_NODE, &config_log_trap_cmd);
+      install_element (CONFIG_NODE, &no_config_log_trap_cmd);
+      install_element (CONFIG_NODE, &config_log_record_priority_cmd);
+      install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
+      install_element (CONFIG_NODE, &service_password_encrypt_cmd);
+      install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
+      install_element (CONFIG_NODE, &banner_motd_default_cmd);
+      install_element (CONFIG_NODE, &no_banner_motd_cmd);
+      install_element (CONFIG_NODE, &service_terminal_length_cmd);
+      install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
+    }
+
+  srand(time(NULL));
+}
diff --git a/lib/command.h b/lib/command.h
new file mode 100644
index 0000000..3009b26
--- /dev/null
+++ b/lib/command.h
@@ -0,0 +1,308 @@
+/*
+ * Zebra configuration command interface routine
+ * Copyright (C) 1997, 98 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 _ZEBRA_COMMAND_H
+#define _ZEBRA_COMMAND_H
+
+#include "vector.h"
+#include "vty.h"
+
+/* Host configuration variable */
+struct host
+{
+  /* Host name of this router. */
+  char *name;
+
+  /* Password for vty interface. */
+  char *password;
+  char *password_encrypt;
+
+  /* Enable password */
+  char *enable;
+  char *enable_encrypt;
+
+  /* System wide terminal lines. */
+  int lines;
+
+  /* Log filename. */
+  char *logfile;
+
+  /* Log stdout. */
+  u_char log_stdout;
+
+  /* Log syslog. */
+  u_char log_syslog;
+  
+  /* config file name of this host */
+  char *config;
+
+  /* Flags for services */
+  int advanced;
+  int encrypt;
+
+  /* Banner configuration. */
+  char *motd;
+};
+
+/* There are some command levels which called from command node. */
+enum node_type 
+{
+  AUTH_NODE,			/* Authentication mode of vty interface. */
+  VIEW_NODE,			/* View node. Default mode of vty interface. */
+  AUTH_ENABLE_NODE,		/* Authentication mode for change enable. */
+  ENABLE_NODE,			/* Enable node. */
+  CONFIG_NODE,			/* Config node. Default mode of config file. */
+  DEBUG_NODE,			/* Debug node. */
+  AAA_NODE,			/* AAA node. */
+  KEYCHAIN_NODE,		/* Key-chain node. */
+  KEYCHAIN_KEY_NODE,		/* Key-chain key node. */
+  INTERFACE_NODE,		/* Interface mode node. */
+  ZEBRA_NODE,			/* zebra connection node. */
+  TABLE_NODE,			/* rtm_table selection node. */
+  RIP_NODE,			/* RIP protocol mode node. */ 
+  RIPNG_NODE,			/* RIPng protocol mode node. */
+  BGP_NODE,			/* BGP protocol mode which includes BGP4+ */
+  BGP_VPNV4_NODE,		/* BGP MPLS-VPN PE exchange. */
+  BGP_IPV4_NODE,		/* BGP IPv4 unicast address family.  */
+  BGP_IPV4M_NODE,		/* BGP IPv4 multicast address family.  */
+  BGP_IPV6_NODE,		/* BGP IPv6 address family */
+  OSPF_NODE,			/* OSPF protocol mode */
+  OSPF6_NODE,			/* OSPF protocol for IPv6 mode */
+  MASC_NODE,			/* MASC for multicast.  */
+  IRDP_NODE,			/* ICMP Router Discovery Protocol mode. */ 
+  IP_NODE,			/* Static ip route node. */
+  ACCESS_NODE,			/* Access list node. */
+  PREFIX_NODE,			/* Prefix list node. */
+  ACCESS_IPV6_NODE,		/* Access list node. */
+  PREFIX_IPV6_NODE,		/* Prefix list node. */
+  AS_LIST_NODE,			/* AS list node. */
+  COMMUNITY_LIST_NODE,		/* Community list node. */
+  RMAP_NODE,			/* Route map node. */
+  SMUX_NODE,			/* SNMP configuration node. */
+  DUMP_NODE,			/* Packet dump node. */
+  FORWARDING_NODE,		/* IP forwarding node. */
+  VTY_NODE			/* Vty node. */
+};
+
+/* Node which has some commands and prompt string and configuration
+   function pointer . */
+struct cmd_node 
+{
+  /* Node index. */
+  enum node_type node;		
+
+  /* Prompt character at vty interface. */
+  char *prompt;			
+
+  /* Is this node's configuration goes to vtysh ? */
+  int vtysh;
+  
+  /* Node's configuration write function */
+  int (*func) (struct vty *);
+
+  /* Vector of this node's command list. */
+  vector cmd_vector;	
+};
+
+/* Structure of command element. */
+struct cmd_element 
+{
+  char *string;			/* Command specification by string. */
+  int (*func) (struct cmd_element *, struct vty *, int, char **);
+  char *doc;			/* Documentation of this command. */
+  int daemon;                   /* Daemon to which this command belong. */
+  vector strvec;		/* Pointing out each description vector. */
+  int cmdsize;			/* Command index count. */
+  char *config;			/* Configuration string */
+  vector subconfig;		/* Sub configuration string */
+};
+
+/* Command description structure. */
+struct desc
+{
+  char *cmd;			/* Command string. */
+  char *str;			/* Command's description. */
+};
+
+/* Return value of the commands. */
+#define CMD_SUCCESS              0
+#define CMD_WARNING              1
+#define CMD_ERR_NO_MATCH         2
+#define CMD_ERR_AMBIGUOUS        3
+#define CMD_ERR_INCOMPLETE       4
+#define CMD_ERR_EXEED_ARGC_MAX   5
+#define CMD_ERR_NOTHING_TODO     6
+#define CMD_COMPLETE_FULL_MATCH  7
+#define CMD_COMPLETE_MATCH       8
+#define CMD_COMPLETE_LIST_MATCH  9
+#define CMD_SUCCESS_DAEMON      10
+
+/* Argc max counts. */
+#define CMD_ARGC_MAX   25
+
+/* Turn off these macros when uisng cpp with extract.pl */
+#ifndef VTYSH_EXTRACT_PL  
+
+/* DEFUN for vty command interafce. Little bit hacky ;-). */
+#define DEFUN(funcname, cmdname, cmdstr, helpstr) \
+  int funcname (struct cmd_element *, struct vty *, int, char **); \
+  struct cmd_element cmdname = \
+  { \
+    cmdstr, \
+    funcname, \
+    helpstr \
+  }; \
+  int funcname \
+  (struct cmd_element *self, struct vty *vty, int argc, char **argv)
+
+/* DEFUN_NOSH for commands that vtysh should ignore */
+#define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) \
+  DEFUN(funcname, cmdname, cmdstr, helpstr)
+
+/* DEFSH for vtysh. */
+#define DEFSH(daemon, cmdname, cmdstr, helpstr) \
+  struct cmd_element cmdname = \
+  { \
+    cmdstr, \
+    NULL, \
+    helpstr, \
+    daemon \
+  }; \
+
+/* DEFUN + DEFSH */
+#define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \
+  int funcname (struct cmd_element *, struct vty *, int, char **); \
+  struct cmd_element cmdname = \
+  { \
+    cmdstr, \
+    funcname, \
+    helpstr, \
+    daemon \
+  }; \
+  int funcname \
+  (struct cmd_element *self, struct vty *vty, int argc, char **argv)
+
+/* ALIAS macro which define existing command's alias. */
+#define ALIAS(funcname, cmdname, cmdstr, helpstr) \
+  struct cmd_element cmdname = \
+  { \
+    cmdstr, \
+    funcname, \
+    helpstr \
+  };
+
+#endif /* VTYSH_EXTRACT_PL */
+
+/* Some macroes */
+#define CMD_OPTION(S)   ((S[0]) == '[')
+#define CMD_VARIABLE(S) (((S[0]) >= 'A' && (S[0]) <= 'Z') || ((S[0]) == '<'))
+#define CMD_VARARG(S)   ((S[0]) == '.')
+#define CMD_RANGE(S)	((S[0] == '<'))
+
+#define CMD_IPV4(S)	   ((strcmp ((S), "A.B.C.D") == 0))
+#define CMD_IPV4_PREFIX(S) ((strcmp ((S), "A.B.C.D/M") == 0))
+#define CMD_IPV6(S)        ((strcmp ((S), "X:X::X:X") == 0))
+#define CMD_IPV6_PREFIX(S) ((strcmp ((S), "X:X::X:X/M") == 0))
+
+/* Common descriptions. */
+#define SHOW_STR "Show running system information\n"
+#define IP_STR "IP information\n"
+#define IPV6_STR "IPv6 information\n"
+#define NO_STR "Negate a command or set its defaults\n"
+#define CLEAR_STR "Reset functions\n"
+#define RIP_STR "RIP information\n"
+#define BGP_STR "BGP information\n"
+#define OSPF_STR "OSPF information\n"
+#define NEIGHBOR_STR "Specify neighbor router\n"
+#define DEBUG_STR "Debugging functions (see also 'undebug')\n"
+#define UNDEBUG_STR "Disable debugging functions (see also 'debug')\n"
+#define ROUTER_STR "Enable a routing process\n"
+#define AS_STR "AS number\n"
+#define MBGP_STR "MBGP information\n"
+#define MATCH_STR "Match values from routing table\n"
+#define SET_STR "Set values in destination routing protocol\n"
+#define OUT_STR "Filter outgoing routing updates\n"
+#define IN_STR  "Filter incoming routing updates\n"
+#define V4NOTATION_STR "specify by IPv4 address notation(e.g. 0.0.0.0)\n"
+#define OSPF6_NUMBER_STR "Specify by number\n"
+#define INTERFACE_STR "Interface infomation\n"
+#define IFNAME_STR "Interface name(e.g. ep0)\n"
+#define IP6_STR "IPv6 Information\n"
+#define OSPF6_STR "Open Shortest Path First (OSPF) for IPv6\n"
+#define OSPF6_ROUTER_STR "Enable a routing process\n"
+#define OSPF6_INSTANCE_STR "<1-65535> Instance ID\n"
+#define SECONDS_STR "<1-65535> Seconds\n"
+#define ROUTE_STR "Routing Table\n"
+#define PREFIX_LIST_STR "Build a prefix list\n"
+#define OSPF6_DUMP_TYPE_LIST \
+"(neighbor|interface|area|lsa|zebra|config|dbex|spf|route|lsdb|redistribute|hook|asbr|prefix|abr)"
+
+#define CONF_BACKUP_EXT ".sav"
+
+/* IPv4 only machine should not accept IPv6 address for peer's IP
+   address.  So we replace VTY command string like below. */
+#ifdef HAVE_IPV6
+#define NEIGHBOR_CMD       "neighbor (A.B.C.D|X:X::X:X) "
+#define NO_NEIGHBOR_CMD    "no neighbor (A.B.C.D|X:X::X:X) "
+#define NEIGHBOR_ADDR_STR  "Neighbor address\nIPv6 address\n"
+#define NEIGHBOR_CMD2      "neighbor (A.B.C.D|X:X::X:X|WORD) "
+#define NO_NEIGHBOR_CMD2   "no neighbor (A.B.C.D|X:X::X:X|WORD) "
+#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n"
+#else
+#define NEIGHBOR_CMD       "neighbor A.B.C.D "
+#define NO_NEIGHBOR_CMD    "no neighbor A.B.C.D "
+#define NEIGHBOR_ADDR_STR  "Neighbor address\n"
+#define NEIGHBOR_CMD2      "neighbor (A.B.C.D|WORD) "
+#define NO_NEIGHBOR_CMD2   "no neighbor (A.B.C.D|WORD) "
+#define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor tag\n"
+#endif /* HAVE_IPV6 */
+
+/* Prototypes. */
+void install_node (struct cmd_node *, int (*) (struct vty *));
+void install_default (enum node_type);
+void install_element (enum node_type, struct cmd_element *);
+void sort_node ();
+
+char *argv_concat (char **, int, int);
+vector cmd_make_strvec (char *);
+void cmd_free_strvec (vector);
+vector cmd_describe_command ();
+char **cmd_complete_command ();
+char *cmd_prompt (enum node_type);
+int config_from_file (struct vty *, FILE *);
+int cmd_execute_command (vector, struct vty *, struct cmd_element **);
+int cmd_execute_command_strict (vector, struct vty *, struct cmd_element **);
+void config_replace_string (struct cmd_element *, char *, ...);
+void cmd_init (int);
+
+/* Export typical functions. */
+extern struct cmd_element config_end_cmd;
+extern struct cmd_element config_exit_cmd;
+extern struct cmd_element config_quit_cmd;
+extern struct cmd_element config_help_cmd;
+extern struct cmd_element config_list_cmd;
+int config_exit (struct cmd_element *, struct vty *, int, char **);
+int config_help (struct cmd_element *, struct vty *, int, char **);
+char *host_config_file ();
+void host_config_set (char *);
+
+#endif /* _ZEBRA_COMMAND_H */
diff --git a/lib/daemon.c b/lib/daemon.c
new file mode 100644
index 0000000..dfd26b3
--- /dev/null
+++ b/lib/daemon.c
@@ -0,0 +1,80 @@
+/*
+ * Daemonize routine
+ * Copyright (C) 1997, 1999 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.
+ */
+
+#include <zebra.h>
+
+#ifndef HAVE_DAEMON
+
+/* Daemonize myself. */
+int
+daemon (int nochdir, int noclose)
+{
+  pid_t pid;
+
+  pid = fork ();
+
+  /* In case of fork is error. */
+  if (pid < 0)
+    {
+      perror ("fork");
+      return -1;
+    }
+
+  /* In case of this is parent process. */
+  if (pid != 0)
+    exit (0);
+
+  /* Become session leader and get pid. */
+  pid = setsid();
+
+  if (pid < -1)
+    {
+      perror ("setsid");
+      return -1;
+    }
+
+  /* Change directory to root. */
+  if (! nochdir)
+    chdir ("/");
+
+  /* File descriptor close. */
+  if (! noclose)
+    {
+      int fd;
+
+      fd = open ("/dev/null", O_RDWR, 0);
+      if (fd != -1)
+	{
+	  dup2 (fd, STDIN_FILENO);
+	  dup2 (fd, STDOUT_FILENO);
+	  dup2 (fd, STDERR_FILENO);
+	  if (fd > 2)
+	    close (fd);
+	}
+    }
+
+  umask (0027);
+
+  return 0;
+}
+
+#endif /* HAVE_DAEMON */
diff --git a/lib/distribute.c b/lib/distribute.c
new file mode 100644
index 0000000..d5893a5
--- /dev/null
+++ b/lib/distribute.c
@@ -0,0 +1,709 @@
+/* Distribute list functions
+ * Copyright (C) 1998, 1999 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.
+ */
+
+#include <zebra.h>
+
+#include "hash.h"
+#include "if.h"
+#include "filter.h"
+#include "command.h"
+#include "distribute.h"
+#include "memory.h"
+
+/* Hash of distribute list. */
+struct hash *disthash;
+
+/* Hook functions. */
+void (*distribute_add_hook) (struct distribute *);
+void (*distribute_delete_hook) (struct distribute *);
+
+struct distribute *
+distribute_new ()
+{
+  struct distribute *new;
+
+  new = XMALLOC (MTYPE_DISTRIBUTE, sizeof (struct distribute));
+  memset (new, 0, sizeof (struct distribute));
+
+  return new;
+}
+
+/* Free distribute object. */
+void
+distribute_free (struct distribute *dist)
+{
+  if (dist->ifname)
+    free (dist->ifname);
+
+  if (dist->list[DISTRIBUTE_IN])
+    free (dist->list[DISTRIBUTE_IN]);
+  if (dist->list[DISTRIBUTE_OUT])
+    free (dist->list[DISTRIBUTE_OUT]);
+
+  if (dist->prefix[DISTRIBUTE_IN])
+    free (dist->prefix[DISTRIBUTE_IN]);
+  if (dist->prefix[DISTRIBUTE_OUT])
+    free (dist->prefix[DISTRIBUTE_OUT]);
+
+  XFREE (MTYPE_DISTRIBUTE, dist);
+}
+
+/* Lookup interface's distribute list. */
+struct distribute *
+distribute_lookup (char *ifname)
+{
+  struct distribute key;
+  struct distribute *dist;
+
+  key.ifname = ifname;
+
+  dist = hash_lookup (disthash, &key);
+  
+  return dist;
+}
+
+void
+distribute_list_add_hook (void (*func) (struct distribute *))
+{
+  distribute_add_hook = func;
+}
+
+void
+distribute_list_delete_hook (void (*func) (struct distribute *))
+{
+  distribute_delete_hook = func;
+}
+
+void *
+distribute_hash_alloc (struct distribute *arg)
+{
+  struct distribute *dist;
+
+  dist = distribute_new ();
+  if (arg->ifname)
+    dist->ifname = strdup (arg->ifname);
+  else
+    dist->ifname = NULL;
+  return dist;
+}
+
+/* Make new distribute list and push into hash. */
+struct distribute *
+distribute_get (char *ifname)
+{
+  struct distribute key;
+
+  key.ifname = ifname;
+
+  return hash_get (disthash, &key, distribute_hash_alloc);
+}
+
+unsigned int
+distribute_hash_make (struct distribute *dist)
+{
+  unsigned int key;
+  int i;
+
+  key = 0;
+  if (dist->ifname)
+    for (i = 0; i < strlen (dist->ifname); i++)
+      key += dist->ifname[i];
+
+  return key;
+}
+
+/* If two distribute-list have same value then return 1 else return
+   0. This function is used by hash package. */
+int
+distribute_cmp (struct distribute *dist1, struct distribute *dist2)
+{
+  if (dist1->ifname && dist2->ifname)
+    if (strcmp (dist1->ifname, dist2->ifname) == 0)
+      return 1;
+  if (! dist1->ifname && ! dist2->ifname)
+    return 1;
+  return 0;
+}
+
+/* Set access-list name to the distribute list. */
+struct distribute *
+distribute_list_set (char *ifname, enum distribute_type type, char *alist_name)
+{
+  struct distribute *dist;
+
+  dist = distribute_get (ifname);
+
+  if (type == DISTRIBUTE_IN)
+    {
+      if (dist->list[DISTRIBUTE_IN])
+	free (dist->list[DISTRIBUTE_IN]);
+      dist->list[DISTRIBUTE_IN] = strdup (alist_name);
+    }
+  if (type == DISTRIBUTE_OUT)
+    {
+      if (dist->list[DISTRIBUTE_OUT])
+	free (dist->list[DISTRIBUTE_OUT]);
+      dist->list[DISTRIBUTE_OUT] = strdup (alist_name);
+    }
+
+  /* Apply this distribute-list to the interface. */
+  (*distribute_add_hook) (dist);
+  
+  return dist;
+}
+
+/* Unset distribute-list.  If matched distribute-list exist then
+   return 1. */
+int
+distribute_list_unset (char *ifname, enum distribute_type type, 
+		       char *alist_name)
+{
+  struct distribute *dist;
+
+  dist = distribute_lookup (ifname);
+  if (!dist)
+    return 0;
+
+  if (type == DISTRIBUTE_IN)
+    {
+      if (!dist->list[DISTRIBUTE_IN])
+	return 0;
+      if (strcmp (dist->list[DISTRIBUTE_IN], alist_name) != 0)
+	return 0;
+
+      free (dist->list[DISTRIBUTE_IN]);
+      dist->list[DISTRIBUTE_IN] = NULL;      
+    }
+
+  if (type == DISTRIBUTE_OUT)
+    {
+      if (!dist->list[DISTRIBUTE_OUT])
+	return 0;
+      if (strcmp (dist->list[DISTRIBUTE_OUT], alist_name) != 0)
+	return 0;
+
+      free (dist->list[DISTRIBUTE_OUT]);
+      dist->list[DISTRIBUTE_OUT] = NULL;      
+    }
+
+  /* Apply this distribute-list to the interface. */
+  (*distribute_delete_hook) (dist);
+
+  /* If both out and in is NULL then free distribute list. */
+  if (dist->list[DISTRIBUTE_IN] == NULL &&
+      dist->list[DISTRIBUTE_OUT] == NULL &&
+      dist->prefix[DISTRIBUTE_IN] == NULL &&
+      dist->prefix[DISTRIBUTE_OUT] == NULL)
+    {
+      hash_release (disthash, dist);
+      distribute_free (dist);
+    }
+
+  return 1;
+}
+
+/* Set access-list name to the distribute list. */
+struct distribute *
+distribute_list_prefix_set (char *ifname, enum distribute_type type,
+			    char *plist_name)
+{
+  struct distribute *dist;
+
+  dist = distribute_get (ifname);
+
+  if (type == DISTRIBUTE_IN)
+    {
+      if (dist->prefix[DISTRIBUTE_IN])
+	free (dist->prefix[DISTRIBUTE_IN]);
+      dist->prefix[DISTRIBUTE_IN] = strdup (plist_name);
+    }
+  if (type == DISTRIBUTE_OUT)
+    {
+      if (dist->prefix[DISTRIBUTE_OUT])
+	free (dist->prefix[DISTRIBUTE_OUT]);
+      dist->prefix[DISTRIBUTE_OUT] = strdup (plist_name);
+    }
+
+  /* Apply this distribute-list to the interface. */
+  (*distribute_add_hook) (dist);
+  
+  return dist;
+}
+
+/* Unset distribute-list.  If matched distribute-list exist then
+   return 1. */
+int
+distribute_list_prefix_unset (char *ifname, enum distribute_type type,
+			      char *plist_name)
+{
+  struct distribute *dist;
+
+  dist = distribute_lookup (ifname);
+  if (!dist)
+    return 0;
+
+  if (type == DISTRIBUTE_IN)
+    {
+      if (!dist->prefix[DISTRIBUTE_IN])
+	return 0;
+      if (strcmp (dist->prefix[DISTRIBUTE_IN], plist_name) != 0)
+	return 0;
+
+      free (dist->prefix[DISTRIBUTE_IN]);
+      dist->prefix[DISTRIBUTE_IN] = NULL;      
+    }
+
+  if (type == DISTRIBUTE_OUT)
+    {
+      if (!dist->prefix[DISTRIBUTE_OUT])
+	return 0;
+      if (strcmp (dist->prefix[DISTRIBUTE_OUT], plist_name) != 0)
+	return 0;
+
+      free (dist->prefix[DISTRIBUTE_OUT]);
+      dist->prefix[DISTRIBUTE_OUT] = NULL;      
+    }
+
+  /* Apply this distribute-list to the interface. */
+  (*distribute_delete_hook) (dist);
+
+  /* If both out and in is NULL then free distribute list. */
+  if (dist->list[DISTRIBUTE_IN] == NULL &&
+      dist->list[DISTRIBUTE_OUT] == NULL &&
+      dist->prefix[DISTRIBUTE_IN] == NULL &&
+      dist->prefix[DISTRIBUTE_OUT] == NULL)
+    {
+      hash_release (disthash, dist);
+      distribute_free (dist);
+    }
+
+  return 1;
+}
+
+DEFUN (distribute_list_all,
+       distribute_list_all_cmd,
+       "distribute-list WORD (in|out)",
+       "Filter networks in routing updates\n"
+       "Access-list name\n"
+       "Filter incoming routing updates\n"
+       "Filter outgoing routing updates\n")
+{
+  enum distribute_type type;
+  struct distribute *dist;
+
+  /* Check of distribute list type. */
+  if (strncmp (argv[1], "i", 1) == 0)
+    type = DISTRIBUTE_IN;
+  else if (strncmp (argv[1], "o", 1) == 0)
+    type = DISTRIBUTE_OUT;
+  else
+    {
+      vty_out (vty, "distribute list direction must be [in|out]%s",
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Get interface name corresponding distribute list. */
+  dist = distribute_list_set (NULL, type, argv[0]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_distribute_list_all,
+       no_distribute_list_all_cmd,
+       "no distribute-list WORD (in|out)",
+       NO_STR
+       "Filter networks in routing updates\n"
+       "Access-list name\n"
+       "Filter incoming routing updates\n"
+       "Filter outgoing routing updates\n")
+{
+  int ret;
+  enum distribute_type type;
+
+  /* Check of distribute list type. */
+  if (strncmp (argv[1], "i", 1) == 0)
+    type = DISTRIBUTE_IN;
+  else if (strncmp (argv[1], "o", 1) == 0)
+    type = DISTRIBUTE_OUT;
+  else
+    {
+      vty_out (vty, "distribute list direction must be [in|out]%s",
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = distribute_list_unset (NULL, type, argv[0]);
+  if (! ret)
+    {
+      vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (distribute_list,
+       distribute_list_cmd,
+       "distribute-list WORD (in|out) WORD",
+       "Filter networks in routing updates\n"
+       "Access-list name\n"
+       "Filter incoming routing updates\n"
+       "Filter outgoing routing updates\n"
+       "Interface name\n")
+{
+  enum distribute_type type;
+  struct distribute *dist;
+
+  /* Check of distribute list type. */
+  if (strncmp (argv[1], "i", 1) == 0)
+    type = DISTRIBUTE_IN;
+  else if (strncmp (argv[1], "o", 1) == 0)
+    type = DISTRIBUTE_OUT;
+  else
+    {
+      vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Get interface name corresponding distribute list. */
+  dist = distribute_list_set (argv[2], type, argv[0]);
+
+  return CMD_SUCCESS;
+}       
+
+DEFUN (no_districute_list, no_distribute_list_cmd,
+       "no distribute-list WORD (in|out) WORD",
+       NO_STR
+       "Filter networks in routing updates\n"
+       "Access-list name\n"
+       "Filter incoming routing updates\n"
+       "Filter outgoing routing updates\n"
+       "Interface name\n")
+{
+  int ret;
+  enum distribute_type type;
+
+  /* Check of distribute list type. */
+  if (strncmp (argv[1], "i", 1) == 0)
+    type = DISTRIBUTE_IN;
+  else if (strncmp (argv[1], "o", 1) == 0)
+    type = DISTRIBUTE_OUT;
+  else
+    {
+      vty_out (vty, "distribute list direction must be [in|out]%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = distribute_list_unset (argv[2], type, argv[0]);
+  if (! ret)
+    {
+      vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}       
+
+DEFUN (districute_list_prefix_all,
+       distribute_list_prefix_all_cmd,
+       "distribute-list prefix WORD (in|out)",
+       "Filter networks in routing updates\n"
+       "Filter prefixes in routing updates\n"
+       "Name of an IP prefix-list\n"
+       "Filter incoming routing updates\n"
+       "Filter outgoing routing updates\n")
+{
+  enum distribute_type type;
+  struct distribute *dist;
+
+  /* Check of distribute list type. */
+  if (strncmp (argv[1], "i", 1) == 0)
+    type = DISTRIBUTE_IN;
+  else if (strncmp (argv[1], "o", 1) == 0)
+    type = DISTRIBUTE_OUT;
+  else
+    {
+      vty_out (vty, "distribute list direction must be [in|out]%s", 
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Get interface name corresponding distribute list. */
+  dist = distribute_list_prefix_set (NULL, type, argv[0]);
+
+  return CMD_SUCCESS;
+}       
+
+DEFUN (no_districute_list_prefix_all,
+       no_distribute_list_prefix_all_cmd,
+       "no distribute-list prefix WORD (in|out)",
+       NO_STR
+       "Filter networks in routing updates\n"
+       "Filter prefixes in routing updates\n"
+       "Name of an IP prefix-list\n"
+       "Filter incoming routing updates\n"
+       "Filter outgoing routing updates\n")
+{
+  int ret;
+  enum distribute_type type;
+
+  /* Check of distribute list type. */
+  if (strncmp (argv[1], "i", 1) == 0)
+    type = DISTRIBUTE_IN;
+  else if (strncmp (argv[1], "o", 1) == 0)
+    type = DISTRIBUTE_OUT;
+  else
+    {
+      vty_out (vty, "distribute list direction must be [in|out]%s", 
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = distribute_list_prefix_unset (NULL, type, argv[0]);
+  if (! ret)
+    {
+      vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}       
+
+DEFUN (districute_list_prefix, distribute_list_prefix_cmd,
+       "distribute-list prefix WORD (in|out) WORD",
+       "Filter networks in routing updates\n"
+       "Filter prefixes in routing updates\n"
+       "Name of an IP prefix-list\n"
+       "Filter incoming routing updates\n"
+       "Filter outgoing routing updates\n"
+       "Interface name\n")
+{
+  enum distribute_type type;
+  struct distribute *dist;
+
+  /* Check of distribute list type. */
+  if (strncmp (argv[1], "i", 1) == 0)
+    type = DISTRIBUTE_IN;
+  else if (strncmp (argv[1], "o", 1) == 0)
+    type = DISTRIBUTE_OUT;
+  else
+    {
+      vty_out (vty, "distribute list direction must be [in|out]%s", 
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Get interface name corresponding distribute list. */
+  dist = distribute_list_prefix_set (argv[2], type, argv[0]);
+
+  return CMD_SUCCESS;
+}       
+
+DEFUN (no_districute_list_prefix, no_distribute_list_prefix_cmd,
+       "no distribute-list prefix WORD (in|out) WORD",
+       NO_STR
+       "Filter networks in routing updates\n"
+       "Filter prefixes in routing updates\n"
+       "Name of an IP prefix-list\n"
+       "Filter incoming routing updates\n"
+       "Filter outgoing routing updates\n"
+       "Interface name\n")
+{
+  int ret;
+  enum distribute_type type;
+
+  /* Check of distribute list type. */
+  if (strncmp (argv[1], "i", 1) == 0)
+    type = DISTRIBUTE_IN;
+  else if (strncmp (argv[1], "o", 1) == 0)
+    type = DISTRIBUTE_OUT;
+  else
+    {
+      vty_out (vty, "distribute list direction must be [in|out]%s", 
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = distribute_list_prefix_unset (argv[2], type, argv[0]);
+  if (! ret)
+    {
+      vty_out (vty, "distribute list doesn't exist%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}       
+
+int
+config_show_distribute (struct vty *vty)
+{
+  int i;
+  struct hash_backet *mp;
+  struct distribute *dist;
+
+  /* Output filter configuration. */
+  dist = distribute_lookup (NULL);
+  if (dist && (dist->list[DISTRIBUTE_OUT] || dist->prefix[DISTRIBUTE_OUT]))
+    {
+      vty_out (vty, "  Outgoing update filter list for all interface is");
+      if (dist->list[DISTRIBUTE_OUT])
+	vty_out (vty, " %s", dist->list[DISTRIBUTE_OUT]);
+      if (dist->prefix[DISTRIBUTE_OUT])
+	vty_out (vty, "%s (prefix-list) %s",
+		 dist->list[DISTRIBUTE_OUT] ? "," : "",
+		 dist->prefix[DISTRIBUTE_OUT]);
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+  else
+    vty_out (vty, "  Outgoing update filter list for all interface is not set%s", VTY_NEWLINE);
+
+  for (i = 0; i < disthash->size; i++)
+    for (mp = disthash->index[i]; mp; mp = mp->next)
+      {
+	dist = mp->data;
+	if (dist->ifname)
+	  if (dist->list[DISTRIBUTE_OUT] || dist->prefix[DISTRIBUTE_OUT])
+	    {
+	      vty_out (vty, "    %s filtered by", dist->ifname);
+	      if (dist->list[DISTRIBUTE_OUT])
+		vty_out (vty, " %s", dist->list[DISTRIBUTE_OUT]);
+	      if (dist->prefix[DISTRIBUTE_OUT])
+		vty_out (vty, "%s (prefix-list) %s",
+			 dist->list[DISTRIBUTE_OUT] ? "," : "",
+			 dist->prefix[DISTRIBUTE_OUT]);
+	      vty_out (vty, "%s", VTY_NEWLINE);
+	    }
+      }
+
+
+  /* Input filter configuration. */
+  dist = distribute_lookup (NULL);
+  if (dist && (dist->list[DISTRIBUTE_IN] || dist->prefix[DISTRIBUTE_IN]))
+    {
+      vty_out (vty, "  Incoming update filter list for all interface is");
+      if (dist->list[DISTRIBUTE_IN])
+	vty_out (vty, " %s", dist->list[DISTRIBUTE_IN]);
+      if (dist->prefix[DISTRIBUTE_IN])
+	vty_out (vty, "%s (prefix-list) %s",
+		 dist->list[DISTRIBUTE_IN] ? "," : "",
+		 dist->prefix[DISTRIBUTE_IN]);
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+  else
+    vty_out (vty, "  Incoming update filter list for all interface is not set%s", VTY_NEWLINE);
+
+  for (i = 0; i < disthash->size; i++)
+    for (mp = disthash->index[i]; mp; mp = mp->next)
+      {
+	dist = mp->data;
+	if (dist->ifname)
+	  if (dist->list[DISTRIBUTE_IN] || dist->prefix[DISTRIBUTE_IN])
+	    {
+	      vty_out (vty, "    %s filtered by", dist->ifname);
+	      if (dist->list[DISTRIBUTE_IN])
+		vty_out (vty, " %s", dist->list[DISTRIBUTE_IN]);
+	      if (dist->prefix[DISTRIBUTE_IN])
+		vty_out (vty, "%s (prefix-list) %s",
+			 dist->list[DISTRIBUTE_IN] ? "," : "",
+			 dist->prefix[DISTRIBUTE_IN]);
+	      vty_out (vty, "%s", VTY_NEWLINE);
+	    }
+      }
+  return 0;
+}
+
+/* Configuration write function. */
+int
+config_write_distribute (struct vty *vty)
+{
+  int i;
+  struct hash_backet *mp;
+  int write = 0;
+
+  for (i = 0; i < disthash->size; i++)
+    for (mp = disthash->index[i]; mp; mp = mp->next)
+      {
+	struct distribute *dist;
+
+	dist = mp->data;
+
+	if (dist->list[DISTRIBUTE_IN])
+	  {
+	    vty_out (vty, " distribute-list %s in %s%s", 
+		     dist->list[DISTRIBUTE_IN],
+		     dist->ifname ? dist->ifname : "",
+		     VTY_NEWLINE);
+	    write++;
+	  }
+
+	if (dist->list[DISTRIBUTE_OUT])
+	  {
+	    vty_out (vty, " distribute-list %s out %s%s", 
+
+		     dist->list[DISTRIBUTE_OUT],
+		     dist->ifname ? dist->ifname : "",
+		     VTY_NEWLINE);
+	    write++;
+	  }
+
+	if (dist->prefix[DISTRIBUTE_IN])
+	  {
+	    vty_out (vty, " distribute-list prefix %s in %s%s",
+		     dist->prefix[DISTRIBUTE_IN],
+		     dist->ifname ? dist->ifname : "",
+		     VTY_NEWLINE);
+	    write++;
+	  }
+
+	if (dist->prefix[DISTRIBUTE_OUT])
+	  {
+	    vty_out (vty, " distribute-list prefix %s out %s%s",
+		     dist->prefix[DISTRIBUTE_OUT],
+		     dist->ifname ? dist->ifname : "",
+		     VTY_NEWLINE);
+	    write++;
+	  }
+      }
+  return write;
+}
+
+/* Clear all distribute list. */
+void
+distribute_list_reset ()
+{
+  hash_clean (disthash, (void (*) (void *)) distribute_free);
+}
+
+/* Initialize distribute list related hash. */
+void
+distribute_list_init (int node)
+{
+  disthash = hash_create (distribute_hash_make, distribute_cmp);
+
+  install_element (node, &distribute_list_all_cmd);
+  install_element (node, &no_distribute_list_all_cmd);
+
+  install_element (node, &distribute_list_cmd);
+  install_element (node, &no_distribute_list_cmd);
+
+  install_element (node, &distribute_list_prefix_all_cmd);
+  install_element (node, &no_distribute_list_prefix_all_cmd);
+
+  install_element (node, &distribute_list_prefix_cmd);
+  install_element (node, &no_distribute_list_prefix_cmd);
+}
diff --git a/lib/distribute.h b/lib/distribute.h
new file mode 100644
index 0000000..330126b
--- /dev/null
+++ b/lib/distribute.h
@@ -0,0 +1,57 @@
+/* Distribute list functions header
+ * Copyright (C) 1999 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 _ZEBRA_DISTRIBUTE_H
+#define _ZEBRA_DISTRIBUTE_H
+
+/* Disctirubte list types. */
+enum distribute_type
+{
+  DISTRIBUTE_IN,
+  DISTRIBUTE_OUT,
+  DISTRIBUTE_MAX
+};
+
+struct distribute
+{
+  /* Name of the interface. */
+  char *ifname;
+
+  /* Filter name of `in' and `out' */
+  char *list[DISTRIBUTE_MAX];
+
+  /* prefix-list name of `in' and `out' */
+  char *prefix[DISTRIBUTE_MAX];
+};
+
+/* Prototypes for distribute-list. */
+void distribute_list_init (int);
+void distribute_list_reset (void);
+void distribute_list_add_hook (void (*) (struct distribute *));
+void distribute_list_delete_hook (void (*) (struct distribute *));
+struct distribute *distribute_lookup (char *);
+int config_write_distribute (struct vty *);
+int config_show_distribute (struct vty *);
+
+enum filter_type distribute_apply_in (struct interface *, struct prefix *);
+enum filter_type distribute_apply_out (struct interface *, struct prefix *);
+
+#endif /* _ZEBRA_DISTRIBUTE_H */
diff --git a/lib/filter.c b/lib/filter.c
new file mode 100644
index 0000000..a483ce2
--- /dev/null
+++ b/lib/filter.c
@@ -0,0 +1,2058 @@
+/* Route filtering function.
+ * Copyright (C) 1998, 1999 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.
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "filter.h"
+#include "memory.h"
+#include "command.h"
+#include "sockunion.h"
+#include "buffer.h"
+
+struct filter_cisco
+{
+  /* Cisco access-list */
+  int extended;
+  struct in_addr addr;
+  struct in_addr addr_mask;
+  struct in_addr mask;
+  struct in_addr mask_mask;
+};
+
+struct filter_zebra
+{
+  /* If this filter is "exact" match then this flag is set. */
+  int exact;
+
+  /* Prefix information. */
+  struct prefix prefix;
+};
+
+/* Filter element of access list */
+struct filter
+{
+  /* For doubly linked list. */
+  struct filter *next;
+  struct filter *prev;
+
+  /* Filter type information. */
+  enum filter_type type;
+
+  /* Cisco access-list */
+  int cisco;
+
+  union
+    {
+      struct filter_cisco cfilter;
+      struct filter_zebra zfilter;
+    } u;
+};
+
+/* List of access_list. */
+struct access_list_list
+{
+  struct access_list *head;
+  struct access_list *tail;
+};
+
+/* Master structure of access_list. */
+struct access_master
+{
+  /* List of access_list which name is number. */
+  struct access_list_list num;
+
+  /* List of access_list which name is string. */
+  struct access_list_list str;
+
+  /* Hook function which is executed when new access_list is added. */
+  void (*add_hook) ();
+
+  /* Hook function which is executed when access_list is deleted. */
+  void (*delete_hook) ();
+};
+
+/* Static structure for IPv4 access_list's master. */
+static struct access_master access_master_ipv4 = 
+{ 
+  {NULL, NULL},
+  {NULL, NULL},
+  NULL,
+  NULL,
+};
+
+#ifdef HAVE_IPV6
+/* Static structure for IPv6 access_list's master. */
+static struct access_master access_master_ipv6 = 
+{ 
+  {NULL, NULL},
+  {NULL, NULL},
+  NULL,
+  NULL,
+};
+#endif /* HAVE_IPV6 */
+
+struct access_master *
+access_master_get (afi_t afi)
+{
+  if (afi == AFI_IP)
+    return &access_master_ipv4;
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    return &access_master_ipv6;
+#endif /* HAVE_IPV6 */
+  return NULL;
+}
+
+/* Allocate new filter structure. */
+struct filter *
+filter_new ()
+{
+  return (struct filter *) XCALLOC (MTYPE_ACCESS_FILTER,
+				    sizeof (struct filter));
+}
+
+void
+filter_free (struct filter *filter)
+{
+  XFREE (MTYPE_ACCESS_FILTER, filter);
+}
+
+/* Return string of filter_type. */
+static char *
+filter_type_str (struct filter *filter)
+{
+  switch (filter->type)
+    {
+    case FILTER_PERMIT:
+      return "permit";
+      break;
+    case FILTER_DENY:
+      return "deny";
+      break;
+    case FILTER_DYNAMIC:
+      return "dynamic";
+      break;
+    default:
+      return "";
+      break;
+    }
+}
+
+/* If filter match to the prefix then return 1. */
+static int
+filter_match_cisco (struct filter *mfilter, struct prefix *p)
+{
+  struct filter_cisco *filter;
+  struct in_addr mask;
+  u_int32_t check_addr;
+  u_int32_t check_mask;
+
+  filter = &mfilter->u.cfilter;
+  check_addr = p->u.prefix4.s_addr & ~filter->addr_mask.s_addr;
+
+  if (filter->extended)
+    {
+      masklen2ip (p->prefixlen, &mask);
+      check_mask = mask.s_addr & ~filter->mask_mask.s_addr;
+
+      if (memcmp (&check_addr, &filter->addr.s_addr, 4) == 0
+          && memcmp (&check_mask, &filter->mask.s_addr, 4) == 0)
+	return 1;
+    }
+  else if (memcmp (&check_addr, &filter->addr.s_addr, 4) == 0)
+    return 1;
+
+  return 0;
+}
+
+/* If filter match to the prefix then return 1. */
+static int
+filter_match_zebra (struct filter *mfilter, struct prefix *p)
+{
+  struct filter_zebra *filter;
+
+  filter = &mfilter->u.zfilter;
+
+  if (filter->prefix.family == p->family)
+    {
+      if (filter->exact)
+	{
+	  if (filter->prefix.prefixlen == p->prefixlen)
+	    return prefix_match (&filter->prefix, p);
+	  else
+	    return 0;
+	}
+      else
+	return prefix_match (&filter->prefix, p);
+    }
+  else
+    return 0;
+}
+
+/* Allocate new access list structure. */
+struct access_list *
+access_list_new ()
+{
+  return (struct access_list *) XCALLOC (MTYPE_ACCESS_LIST,
+					 sizeof (struct access_list));
+}
+
+/* Free allocated access_list. */
+void
+access_list_free (struct access_list *access)
+{
+  XFREE (MTYPE_ACCESS_LIST, access);
+}
+
+/* Delete access_list from access_master and free it. */
+void
+access_list_delete (struct access_list *access)
+{
+  struct filter *filter;
+  struct filter *next;
+  struct access_list_list *list;
+  struct access_master *master;
+
+  for (filter = access->head; filter; filter = next)
+    {
+      next = filter->next;
+      filter_free (filter);
+    }
+
+  master = access->master;
+
+  if (access->type == ACCESS_TYPE_NUMBER)
+    list = &master->num;
+  else
+    list = &master->str;
+
+  if (access->next)
+    access->next->prev = access->prev;
+  else
+    list->tail = access->prev;
+
+  if (access->prev)
+    access->prev->next = access->next;
+  else
+    list->head = access->next;
+
+  if (access->name)
+    XFREE (MTYPE_ACCESS_LIST_STR, access->name);
+
+  if (access->remark)
+    XFREE (MTYPE_TMP, access->remark);
+
+  access_list_free (access);
+}
+
+/* Insert new access list to list of access_list.  Each acceess_list
+   is sorted by the name. */
+struct access_list *
+access_list_insert (afi_t afi, char *name)
+{
+  int i;
+  long number;
+  struct access_list *access;
+  struct access_list *point;
+  struct access_list_list *alist;
+  struct access_master *master;
+
+  master = access_master_get (afi);
+  if (master == NULL)
+    return NULL;
+
+  /* Allocate new access_list and copy given name. */
+  access = access_list_new ();
+  access->name = XSTRDUP (MTYPE_ACCESS_LIST_STR, name);
+  access->master = master;
+
+  /* If name is made by all digit character.  We treat it as
+     number. */
+  for (number = 0, i = 0; i < strlen (name); i++)
+    {
+      if (isdigit ((int) name[i]))
+	number = (number * 10) + (name[i] - '0');
+      else
+	break;
+    }
+
+  /* In case of name is all digit character */
+  if (i == strlen (name))
+    {
+      access->type = ACCESS_TYPE_NUMBER;
+
+      /* Set access_list to number list. */
+      alist = &master->num;
+
+      for (point = alist->head; point; point = point->next)
+	if (atol (point->name) >= number)
+	  break;
+    }
+  else
+    {
+      access->type = ACCESS_TYPE_STRING;
+
+      /* Set access_list to string list. */
+      alist = &master->str;
+  
+      /* Set point to insertion point. */
+      for (point = alist->head; point; point = point->next)
+	if (strcmp (point->name, name) >= 0)
+	  break;
+    }
+
+  /* In case of this is the first element of master. */
+  if (alist->head == NULL)
+    {
+      alist->head = alist->tail = access;
+      return access;
+    }
+
+  /* In case of insertion is made at the tail of access_list. */
+  if (point == NULL)
+    {
+      access->prev = alist->tail;
+      alist->tail->next = access;
+      alist->tail = access;
+      return access;
+    }
+
+  /* In case of insertion is made at the head of access_list. */
+  if (point == alist->head)
+    {
+      access->next = alist->head;
+      alist->head->prev = access;
+      alist->head = access;
+      return access;
+    }
+
+  /* Insertion is made at middle of the access_list. */
+  access->next = point;
+  access->prev = point->prev;
+
+  if (point->prev)
+    point->prev->next = access;
+  point->prev = access;
+
+  return access;
+}
+
+/* Lookup access_list from list of access_list by name. */
+struct access_list *
+access_list_lookup (afi_t afi, char *name)
+{
+  struct access_list *access;
+  struct access_master *master;
+
+  if (name == NULL)
+    return NULL;
+
+  master = access_master_get (afi);
+  if (master == NULL)
+    return NULL;
+
+  for (access = master->num.head; access; access = access->next)
+    if (strcmp (access->name, name) == 0)
+      return access;
+
+  for (access = master->str.head; access; access = access->next)
+    if (strcmp (access->name, name) == 0)
+      return access;
+
+  return NULL;
+}
+
+/* Get access list from list of access_list.  If there isn't matched
+   access_list create new one and return it. */
+struct access_list *
+access_list_get (afi_t afi, char *name)
+{
+  struct access_list *access;
+
+  access = access_list_lookup (afi, name);
+  if (access == NULL)
+    access = access_list_insert (afi, name);
+  return access;
+}
+
+/* Apply access list to object (which should be struct prefix *). */
+enum filter_type
+access_list_apply (struct access_list *access, void *object)
+{
+  struct filter *filter;
+  struct prefix *p;
+
+  p = (struct prefix *) object;
+
+  if (access == NULL)
+    return FILTER_DENY;
+
+  for (filter = access->head; filter; filter = filter->next)
+    {
+      if (filter->cisco)
+	{
+	  if (filter_match_cisco (filter, p))
+	    return filter->type;
+	}
+      else
+	{
+	  if (filter_match_zebra (filter, p))
+	    return filter->type;
+	}
+    }
+
+  return FILTER_DENY;
+}
+
+/* Add hook function. */
+void
+access_list_add_hook (void (*func) (struct access_list *access))
+{
+  access_master_ipv4.add_hook = func;
+#ifdef HAVE_IPV6
+  access_master_ipv6.add_hook = func;
+#endif /* HAVE_IPV6 */
+}
+
+/* Delete hook function. */
+void
+access_list_delete_hook (void (*func) (struct access_list *access))
+{
+  access_master_ipv4.delete_hook = func;
+#ifdef HAVE_IPV6
+  access_master_ipv6.delete_hook = func;
+#endif /* HAVE_IPV6 */
+}
+
+/* Add new filter to the end of specified access_list. */
+void
+access_list_filter_add (struct access_list *access, struct filter *filter)
+{
+  filter->next = NULL;
+  filter->prev = access->tail;
+
+  if (access->tail)
+    access->tail->next = filter;
+  else
+    access->head = filter;
+  access->tail = filter;
+
+  /* Run hook function. */
+  if (access->master->add_hook)
+    (*access->master->add_hook) (access);
+}
+
+/* If access_list has no filter then return 1. */
+static int
+access_list_empty (struct access_list *access)
+{
+  if (access->head == NULL && access->tail == NULL)
+    return 1;
+  else
+    return 0;
+}
+
+/* Delete filter from specified access_list.  If there is hook
+   function execute it. */
+void
+access_list_filter_delete (struct access_list *access, struct filter *filter)
+{
+  struct access_master *master;
+
+  master = access->master;
+
+  if (filter->next)
+    filter->next->prev = filter->prev;
+  else
+    access->tail = filter->prev;
+
+  if (filter->prev)
+    filter->prev->next = filter->next;
+  else
+    access->head = filter->next;
+
+  filter_free (filter);
+
+  /* If access_list becomes empty delete it from access_master. */
+  if (access_list_empty (access))
+    access_list_delete (access);
+
+  /* Run hook function. */
+  if (master->delete_hook)
+    (*master->delete_hook) (access);
+}
+
+/*
+  deny    Specify packets to reject
+  permit  Specify packets to forward
+  dynamic ?
+*/
+
+/*
+  Hostname or A.B.C.D  Address to match
+  any                  Any source host
+  host                 A single host address
+*/
+
+struct filter *
+filter_lookup_cisco (struct access_list *access, struct filter *mnew)
+{
+  struct filter *mfilter;
+  struct filter_cisco *filter;
+  struct filter_cisco *new;
+
+  new = &mnew->u.cfilter;
+
+  for (mfilter = access->head; mfilter; mfilter = mfilter->next)
+    {
+      filter = &mfilter->u.cfilter;
+
+      if (filter->extended)
+	{
+	  if (mfilter->type == mnew->type
+	      && filter->addr.s_addr == new->addr.s_addr
+	      && filter->addr_mask.s_addr == new->addr_mask.s_addr
+	      && filter->mask.s_addr == new->mask.s_addr
+	      && filter->mask_mask.s_addr == new->mask_mask.s_addr)
+	    return mfilter;
+	}
+      else
+	{
+	  if (mfilter->type == mnew->type
+	      && filter->addr.s_addr == new->addr.s_addr
+	      && filter->addr_mask.s_addr == new->addr_mask.s_addr)
+	    return mfilter;
+	}
+    }
+
+  return NULL;
+}
+
+struct filter *
+filter_lookup_zebra (struct access_list *access, struct filter *mnew)
+{
+  struct filter *mfilter;
+  struct filter_zebra *filter;
+  struct filter_zebra *new;
+
+  new = &mnew->u.zfilter;
+
+  for (mfilter = access->head; mfilter; mfilter = mfilter->next)
+    {
+      filter = &mfilter->u.zfilter;
+
+      if (filter->exact == new->exact
+	  && mfilter->type == mnew->type
+	  && prefix_same (&filter->prefix, &new->prefix))
+	return mfilter;
+    }
+  return NULL;
+}
+
+int
+vty_access_list_remark_unset (struct vty *vty, afi_t afi, char *name)
+{
+  struct access_list *access;
+
+  access = access_list_lookup (afi, name);
+  if (! access)
+    {
+      vty_out (vty, "%% access-list %s doesn't exist%s", name,
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (access->remark)
+    {
+      XFREE (MTYPE_TMP, access->remark);
+      access->remark = NULL;
+    }
+
+  if (access->head == NULL && access->tail == NULL && access->remark == NULL)
+    access_list_delete (access);
+
+  return CMD_SUCCESS;
+}
+
+int
+filter_set_cisco (struct vty *vty, char *name_str, char *type_str,
+		  char *addr_str, char *addr_mask_str,
+		  char *mask_str, char *mask_mask_str,
+		  int extended, int set)
+{
+  int ret;
+  enum filter_type type;
+  struct filter *mfilter;
+  struct filter_cisco *filter;
+  struct access_list *access;
+  struct in_addr addr;
+  struct in_addr addr_mask;
+  struct in_addr mask;
+  struct in_addr mask_mask;
+
+  /* Check of filter type. */
+  if (strncmp (type_str, "p", 1) == 0)
+    type = FILTER_PERMIT;
+  else if (strncmp (type_str, "d", 1) == 0)
+    type = FILTER_DENY;
+  else
+    {
+      vty_out (vty, "%% filter type must be permit or deny%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = inet_aton (addr_str, &addr);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%%Inconsistent address and mask%s",
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = inet_aton (addr_mask_str, &addr_mask);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%%Inconsistent address and mask%s",
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (extended)
+    {
+      ret = inet_aton (mask_str, &mask);
+      if (ret <= 0)
+	{
+	  vty_out (vty, "%%Inconsistent address and mask%s",
+		   VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+
+      ret = inet_aton (mask_mask_str, &mask_mask);
+      if (ret <= 0)
+	{
+	  vty_out (vty, "%%Inconsistent address and mask%s",
+		   VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+
+  mfilter = filter_new();
+  mfilter->type = type;
+  mfilter->cisco = 1;
+  filter = &mfilter->u.cfilter;
+  filter->extended = extended;
+  filter->addr.s_addr = addr.s_addr & ~addr_mask.s_addr;
+  filter->addr_mask.s_addr = addr_mask.s_addr;
+
+  if (extended)
+    {
+      filter->mask.s_addr = mask.s_addr & ~mask_mask.s_addr;
+      filter->mask_mask.s_addr = mask_mask.s_addr;
+    }
+
+  /* Install new filter to the access_list. */
+  access = access_list_get (AFI_IP, name_str);
+
+  if (set)
+    {
+      if (filter_lookup_cisco (access, mfilter))
+	filter_free (mfilter);
+      else
+	access_list_filter_add (access, mfilter);
+    }
+  else
+    {
+      struct filter *delete_filter;
+
+      delete_filter = filter_lookup_cisco (access, mfilter);
+      if (delete_filter)
+	access_list_filter_delete (access, delete_filter);
+
+      filter_free (mfilter);
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* Standard access-list */
+DEFUN (access_list_standard,
+       access_list_standard_cmd,
+       "access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D A.B.C.D",
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Address to match\n"
+       "Wildcard bits\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2], argv[3],
+			   NULL, NULL, 0, 1);
+}
+
+DEFUN (access_list_standard_nomask,
+       access_list_standard_nomask_cmd,
+       "access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D",
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Address to match\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2], "0.0.0.0",
+			   NULL, NULL, 0, 1);
+}
+
+DEFUN (access_list_standard_host,
+       access_list_standard_host_cmd,
+       "access-list (<1-99>|<1300-1999>) (deny|permit) host A.B.C.D",
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "A single host address\n"
+       "Address to match\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2], "0.0.0.0",
+			   NULL, NULL, 0, 1);
+}
+
+DEFUN (access_list_standard_any,
+       access_list_standard_any_cmd,
+       "access-list (<1-99>|<1300-1999>) (deny|permit) any",
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any source host\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+			   "255.255.255.255", NULL, NULL, 0, 1);
+}
+
+DEFUN (no_access_list_standard,
+       no_access_list_standard_cmd,
+       "no access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D A.B.C.D",
+       NO_STR
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Address to match\n"
+       "Wildcard bits\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2], argv[3],
+			   NULL, NULL, 0, 0);
+}
+
+DEFUN (no_access_list_standard_nomask,
+       no_access_list_standard_nomask_cmd,
+       "no access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D",
+       NO_STR
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Address to match\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2], "0.0.0.0",
+			   NULL, NULL, 0, 0);
+}
+
+DEFUN (no_access_list_standard_host,
+       no_access_list_standard_host_cmd,
+       "no access-list (<1-99>|<1300-1999>) (deny|permit) host A.B.C.D",
+       NO_STR
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "A single host address\n"
+       "Address to match\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2], "0.0.0.0",
+			   NULL, NULL, 0, 0);
+}
+
+DEFUN (no_access_list_standard_any,
+       no_access_list_standard_any_cmd,
+       "no access-list (<1-99>|<1300-1999>) (deny|permit) any",
+       NO_STR
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP standard access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any source host\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+			   "255.255.255.255", NULL, NULL, 0, 0);
+}
+
+/* Extended access-list */
+DEFUN (access_list_extended,
+       access_list_extended_cmd,
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D",
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Source address\n"
+       "Source wildcard bits\n"
+       "Destination address\n"
+       "Destination Wildcard bits\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+			   argv[3], argv[4], argv[5], 1 ,1);
+}
+
+DEFUN (access_list_extended_mask_any,
+       access_list_extended_mask_any_cmd,
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D any",
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Source address\n"
+       "Source wildcard bits\n"
+       "Any destination host\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+			   argv[3], "0.0.0.0",
+			   "255.255.255.255", 1, 1);
+}
+
+DEFUN (access_list_extended_any_mask,
+       access_list_extended_any_mask_cmd,
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip any A.B.C.D A.B.C.D",
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Any source host\n"
+       "Destination address\n"
+       "Destination Wildcard bits\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+			   "255.255.255.255", argv[2],
+			   argv[3], 1, 1);
+}
+
+DEFUN (access_list_extended_any_any,
+       access_list_extended_any_any_cmd,
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip any any",
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Any source host\n"
+       "Any destination host\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+			   "255.255.255.255", "0.0.0.0",
+			   "255.255.255.255", 1, 1);
+}
+
+DEFUN (access_list_extended_mask_host,
+       access_list_extended_mask_host_cmd,
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D host A.B.C.D",
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Source address\n"
+       "Source wildcard bits\n"
+       "A single destination host\n"
+       "Destination address\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+			   argv[3], argv[4],
+			   "0.0.0.0", 1, 1);
+}
+
+DEFUN (access_list_extended_host_mask,
+       access_list_extended_host_mask_cmd,
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D A.B.C.D A.B.C.D",
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "A single source host\n"
+       "Source address\n"
+       "Destination address\n"
+       "Destination Wildcard bits\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+			   "0.0.0.0", argv[3],
+			   argv[4], 1, 1);
+}
+
+DEFUN (access_list_extended_host_host,
+       access_list_extended_host_host_cmd,
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D host A.B.C.D",
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "A single source host\n"
+       "Source address\n"
+       "A single destination host\n"
+       "Destination address\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+			   "0.0.0.0", argv[3],
+			   "0.0.0.0", 1, 1);
+}
+
+DEFUN (access_list_extended_any_host,
+       access_list_extended_any_host_cmd,
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip any host A.B.C.D",
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Any source host\n"
+       "A single destination host\n"
+       "Destination address\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+			   "255.255.255.255", argv[2],
+			   "0.0.0.0", 1, 1);
+}
+
+DEFUN (access_list_extended_host_any,
+       access_list_extended_host_any_cmd,
+       "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D any",
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "A single source host\n"
+       "Source address\n"
+       "Any destination host\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+			   "0.0.0.0", "0.0.0.0",
+			   "255.255.255.255", 1, 1);
+}
+
+DEFUN (no_access_list_extended,
+       no_access_list_extended_cmd,
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D",
+       NO_STR
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Source address\n"
+       "Source wildcard bits\n"
+       "Destination address\n"
+       "Destination Wildcard bits\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+			   argv[3], argv[4], argv[5], 1, 0);
+}
+
+DEFUN (no_access_list_extended_mask_any,
+       no_access_list_extended_mask_any_cmd,
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D any",
+       NO_STR
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Source address\n"
+       "Source wildcard bits\n"
+       "Any destination host\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+			   argv[3], "0.0.0.0",
+			   "255.255.255.255", 1, 0);
+}
+
+DEFUN (no_access_list_extended_any_mask,
+       no_access_list_extended_any_mask_cmd,
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any A.B.C.D A.B.C.D",
+       NO_STR
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Any source host\n"
+       "Destination address\n"
+       "Destination Wildcard bits\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+			   "255.255.255.255", argv[2],
+			   argv[3], 1, 0);
+}
+
+DEFUN (no_access_list_extended_any_any,
+       no_access_list_extended_any_any_cmd,
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any any",
+       NO_STR
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Any source host\n"
+       "Any destination host\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+			   "255.255.255.255", "0.0.0.0",
+			   "255.255.255.255", 1, 0);
+}
+
+DEFUN (no_access_list_extended_mask_host,
+       no_access_list_extended_mask_host_cmd,
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D host A.B.C.D",
+       NO_STR
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Source address\n"
+       "Source wildcard bits\n"
+       "A single destination host\n"
+       "Destination address\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+			   argv[3], argv[4],
+			   "0.0.0.0", 1, 0);
+}
+
+DEFUN (no_access_list_extended_host_mask,
+       no_access_list_extended_host_mask_cmd,
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D A.B.C.D A.B.C.D",
+       NO_STR
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "A single source host\n"
+       "Source address\n"
+       "Destination address\n"
+       "Destination Wildcard bits\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+			   "0.0.0.0", argv[3],
+			   argv[4], 1, 0);
+}
+
+DEFUN (no_access_list_extended_host_host,
+       no_access_list_extended_host_host_cmd,
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D host A.B.C.D",
+       NO_STR
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "A single source host\n"
+       "Source address\n"
+       "A single destination host\n"
+       "Destination address\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+			   "0.0.0.0", argv[3],
+			   "0.0.0.0", 1, 0);
+}
+
+DEFUN (no_access_list_extended_any_host,
+       no_access_list_extended_any_host_cmd,
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any host A.B.C.D",
+       NO_STR
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "Any source host\n"
+       "A single destination host\n"
+       "Destination address\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], "0.0.0.0",
+			   "255.255.255.255", argv[2],
+			   "0.0.0.0", 1, 0);
+}
+
+DEFUN (no_access_list_extended_host_any,
+       no_access_list_extended_host_any_cmd,
+       "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D any",
+       NO_STR
+       "Add an access list entry\n"
+       "IP extended access list\n"
+       "IP extended access list (expanded range)\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any Internet Protocol\n"
+       "A single source host\n"
+       "Source address\n"
+       "Any destination host\n")
+{
+  return filter_set_cisco (vty, argv[0], argv[1], argv[2],
+			   "0.0.0.0", "0.0.0.0",
+			   "255.255.255.255", 1, 0);
+}
+
+int
+filter_set_zebra (struct vty *vty, char *name_str, char *type_str,
+		  afi_t afi, char *prefix_str, int exact, int set)
+{
+  int ret;
+  enum filter_type type;
+  struct filter *mfilter;
+  struct filter_zebra *filter;
+  struct access_list *access;
+  struct prefix p;
+
+  /* Check of filter type. */
+  if (strncmp (type_str, "p", 1) == 0)
+    type = FILTER_PERMIT;
+  else if (strncmp (type_str, "d", 1) == 0)
+    type = FILTER_DENY;
+  else
+    {
+      vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Check string format of prefix and prefixlen. */
+  if (afi == AFI_IP)
+    {
+      ret = str2prefix_ipv4 (prefix_str, (struct prefix_ipv4 *)&p);
+      if (ret <= 0)
+	{
+	  vty_out (vty, "IP address prefix/prefixlen is malformed%s",
+		   VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    {
+      ret = str2prefix_ipv6 (prefix_str, (struct prefix_ipv6 *) &p);
+      if (ret <= 0)
+	{
+	  vty_out (vty, "IPv6 address prefix/prefixlen is malformed%s",
+		   VTY_NEWLINE);
+		   return CMD_WARNING;
+	}
+    }
+#endif /* HAVE_IPV6 */
+  else
+    return CMD_WARNING;
+
+  mfilter = filter_new ();
+  mfilter->type = type;
+  filter = &mfilter->u.zfilter;
+  prefix_copy (&filter->prefix, &p);
+
+  /* "exact-match" */
+  if (exact)
+    filter->exact = 1;
+
+  /* Install new filter to the access_list. */
+  access = access_list_get (afi, name_str);
+
+  if (set)
+    {
+      if (filter_lookup_zebra (access, mfilter))
+	filter_free (mfilter);
+      else
+	access_list_filter_add (access, mfilter);
+    }
+  else
+    {
+      struct filter *delete_filter;
+
+      delete_filter = filter_lookup_zebra (access, mfilter);
+      if (delete_filter)
+        access_list_filter_delete (access, delete_filter);
+
+      filter_free (mfilter);
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* Zebra access-list */
+DEFUN (access_list,
+       access_list_cmd,
+       "access-list WORD (deny|permit) A.B.C.D/M",
+       "Add an access list entry\n"
+       "IP zebra access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 10.0.0.0/8\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, argv[2], 0, 1);
+}
+
+DEFUN (access_list_exact,
+       access_list_exact_cmd,
+       "access-list WORD (deny|permit) A.B.C.D/M exact-match",
+       "Add an access list entry\n"
+       "IP zebra access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 10.0.0.0/8\n"
+       "Exact match of the prefixes\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, argv[2], 1, 1);
+}
+
+DEFUN (access_list_any,
+       access_list_any_cmd,
+       "access-list WORD (deny|permit) any",
+       "Add an access list entry\n"
+       "IP zebra access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 10.0.0.0/8\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, "0.0.0.0/0", 0, 1);
+}
+
+DEFUN (no_access_list,
+       no_access_list_cmd,
+       "no access-list WORD (deny|permit) A.B.C.D/M",
+       NO_STR
+       "Add an access list entry\n"
+       "IP zebra access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 10.0.0.0/8\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, argv[2], 0, 0);
+}
+
+DEFUN (no_access_list_exact,
+       no_access_list_exact_cmd,
+       "no access-list WORD (deny|permit) A.B.C.D/M exact-match",
+       NO_STR
+       "Add an access list entry\n"
+       "IP zebra access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 10.0.0.0/8\n"
+       "Exact match of the prefixes\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, argv[2], 1, 0);
+}
+
+DEFUN (no_access_list_any,
+       no_access_list_any_cmd,
+       "no access-list WORD (deny|permit) any",
+       NO_STR
+       "Add an access list entry\n"
+       "IP zebra access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 10.0.0.0/8\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP, "0.0.0.0/0", 0, 0);
+}
+
+DEFUN (no_access_list_all,
+       no_access_list_all_cmd,
+       "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD)",
+       NO_STR
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP extended access list\n"
+       "IP standard access list (expanded range)\n"
+       "IP extended access list (expanded range)\n"
+       "IP zebra access-list name\n")
+{
+  struct access_list *access;
+  struct access_master *master;
+
+  /* Looking up access_list. */
+  access = access_list_lookup (AFI_IP, argv[0]);
+  if (access == NULL)
+    {
+      vty_out (vty, "%% access-list %s doesn't exist%s", argv[0],
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  master = access->master;
+
+  /* Delete all filter from access-list. */
+  access_list_delete (access);
+
+  /* Run hook function. */
+  if (master->delete_hook)
+    (*master->delete_hook) (access);
+ 
+  return CMD_SUCCESS;
+}
+
+DEFUN (access_list_remark,
+       access_list_remark_cmd,
+       "access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark .LINE",
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP extended access list\n"
+       "IP standard access list (expanded range)\n"
+       "IP extended access list (expanded range)\n"
+       "IP zebra access-list\n"
+       "Access list entry comment\n"
+       "Comment up to 100 characters\n")
+{
+  struct access_list *access;
+  struct buffer *b;
+  int i;
+
+  access = access_list_get (AFI_IP, argv[0]);
+
+  if (access->remark)
+    {
+      XFREE (MTYPE_TMP, access->remark);
+      access->remark = NULL;
+    }
+
+  /* Below is remark get codes. */
+  b = buffer_new (1024);
+  for (i = 1; i < argc; i++)
+    {
+      buffer_putstr (b, (u_char *)argv[i]);
+      buffer_putc (b, ' ');
+    }
+  buffer_putc (b, '\0');
+
+  access->remark = buffer_getstr (b);
+
+  buffer_free (b);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_access_list_remark,
+       no_access_list_remark_cmd,
+       "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark",
+       NO_STR
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP extended access list\n"
+       "IP standard access list (expanded range)\n"
+       "IP extended access list (expanded range)\n"
+       "IP zebra access-list\n"
+       "Access list entry comment\n")
+{
+  return vty_access_list_remark_unset (vty, AFI_IP, argv[0]);
+}
+	
+ALIAS (no_access_list_remark,
+       no_access_list_remark_arg_cmd,
+       "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark .LINE",
+       NO_STR
+       "Add an access list entry\n"
+       "IP standard access list\n"
+       "IP extended access list\n"
+       "IP standard access list (expanded range)\n"
+       "IP extended access list (expanded range)\n"
+       "IP zebra access-list\n"
+       "Access list entry comment\n"
+       "Comment up to 100 characters\n")
+
+#ifdef HAVE_IPV6
+DEFUN (ipv6_access_list,
+       ipv6_access_list_cmd,
+       "ipv6 access-list WORD (deny|permit) X:X::X:X/M",
+       IPV6_STR
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 3ffe:506::/32\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, argv[2], 0, 1);
+}
+
+DEFUN (ipv6_access_list_exact,
+       ipv6_access_list_exact_cmd,
+       "ipv6 access-list WORD (deny|permit) X:X::X:X/M exact-match",
+       IPV6_STR
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 3ffe:506::/32\n"
+       "Exact match of the prefixes\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, argv[2], 1, 1);
+}
+
+DEFUN (ipv6_access_list_any,
+       ipv6_access_list_any_cmd,
+       "ipv6 access-list WORD (deny|permit) any",
+       IPV6_STR
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any prefixi to match\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, "::/0", 0, 1);
+}
+
+DEFUN (no_ipv6_access_list,
+       no_ipv6_access_list_cmd,
+       "no ipv6 access-list WORD (deny|permit) X:X::X:X/M",
+       NO_STR
+       IPV6_STR
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 3ffe:506::/32\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, argv[2], 0, 0);
+}
+
+DEFUN (no_ipv6_access_list_exact,
+       no_ipv6_access_list_exact_cmd,
+       "no ipv6 access-list WORD (deny|permit) X:X::X:X/M exact-match",
+       NO_STR
+       IPV6_STR
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Prefix to match. e.g. 3ffe:506::/32\n"
+       "Exact match of the prefixes\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, argv[2], 1, 0);
+}
+
+DEFUN (no_ipv6_access_list_any,
+       no_ipv6_access_list_any_cmd,
+       "no ipv6 access-list WORD (deny|permit) any",
+       NO_STR
+       IPV6_STR
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Any prefixi to match\n")
+{
+  return filter_set_zebra (vty, argv[0], argv[1], AFI_IP6, "::/0", 0, 0);
+}
+
+
+DEFUN (no_ipv6_access_list_all,
+       no_ipv6_access_list_all_cmd,
+       "no ipv6 access-list WORD",
+       NO_STR
+       IPV6_STR
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n")
+{
+  struct access_list *access;
+  struct access_master *master;
+
+  /* Looking up access_list. */
+  access = access_list_lookup (AFI_IP6, argv[0]);
+  if (access == NULL)
+    {
+      vty_out (vty, "%% access-list %s doesn't exist%s", argv[0],
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  master = access->master;
+
+  /* Delete all filter from access-list. */
+  access_list_delete (access);
+
+  /* Run hook function. */
+  if (master->delete_hook)
+    (*master->delete_hook) (access);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_access_list_remark,
+       ipv6_access_list_remark_cmd,
+       "ipv6 access-list WORD remark .LINE",
+       IPV6_STR
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Access list entry comment\n"
+       "Comment up to 100 characters\n")
+{
+  struct access_list *access;
+  struct buffer *b;
+  int i;
+
+  access = access_list_get (AFI_IP6, argv[0]);
+
+  if (access->remark)
+    {
+      XFREE (MTYPE_TMP, access->remark);
+      access->remark = NULL;
+    }
+
+  /* Below is remark get codes. */
+  b = buffer_new (1024);
+  for (i = 1; i < argc; i++)
+    {
+      buffer_putstr (b, (u_char *)argv[i]);
+      buffer_putc (b, ' ');
+    }
+  buffer_putc (b, '\0');
+
+  access->remark = buffer_getstr (b);
+
+  buffer_free (b);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_access_list_remark,
+       no_ipv6_access_list_remark_cmd,
+       "no ipv6 access-list WORD remark",
+       NO_STR
+       IPV6_STR
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Access list entry comment\n")
+{
+  return vty_access_list_remark_unset (vty, AFI_IP6, argv[0]);
+}
+	
+ALIAS (no_ipv6_access_list_remark,
+       no_ipv6_access_list_remark_arg_cmd,
+       "no ipv6 access-list WORD remark .LINE",
+       NO_STR
+       IPV6_STR
+       "Add an access list entry\n"
+       "IPv6 zebra access-list\n"
+       "Access list entry comment\n"
+       "Comment up to 100 characters\n")
+#endif /* HAVE_IPV6 */
+
+void config_write_access_zebra (struct vty *, struct filter *);
+void config_write_access_cisco (struct vty *, struct filter *);
+
+/* show access-list command. */
+int
+filter_show (struct vty *vty, char *name, afi_t afi)
+{
+  struct access_list *access;
+  struct access_master *master;
+  struct filter *mfilter;
+  struct filter_cisco *filter;
+  int write = 0;
+
+  master = access_master_get (afi);
+  if (master == NULL)
+    return 0;
+
+  for (access = master->num.head; access; access = access->next)
+    {
+      if (name && strcmp (access->name, name) != 0)
+	continue;
+
+      write = 1;
+
+      for (mfilter = access->head; mfilter; mfilter = mfilter->next)
+	{
+	  filter = &mfilter->u.cfilter;
+
+	  if (write)
+	    {
+	      vty_out (vty, "%s IP%s access list %s%s",
+		       mfilter->cisco ? 
+		       (filter->extended ? "Extended" : "Standard") : "Zebra",
+		       afi == AFI_IP6 ? "v6" : "",
+		       access->name, VTY_NEWLINE);
+	      write = 0;
+	    }
+
+	  vty_out (vty, "    %s%s", filter_type_str (mfilter),
+		   mfilter->type == FILTER_DENY ? "  " : "");
+
+	  if (! mfilter->cisco)
+	    config_write_access_zebra (vty, mfilter);
+	  else if (filter->extended)
+	    config_write_access_cisco (vty, mfilter);
+	  else
+	    {
+	      if (filter->addr_mask.s_addr == 0xffffffff)
+		vty_out (vty, " any%s", VTY_NEWLINE);
+	      else
+		{
+		  vty_out (vty, " %s", inet_ntoa (filter->addr));
+		  if (filter->addr_mask.s_addr != 0)
+		    vty_out (vty, ", wildcard bits %s", inet_ntoa (filter->addr_mask));
+		  vty_out (vty, "%s", VTY_NEWLINE);
+		}
+	    }
+	}
+    }
+
+  for (access = master->str.head; access; access = access->next)
+    {
+      if (name && strcmp (access->name, name) != 0)
+	continue;
+
+      write = 1;
+
+      for (mfilter = access->head; mfilter; mfilter = mfilter->next)
+	{
+	  filter = &mfilter->u.cfilter;
+
+	  if (write)
+	    {
+	      vty_out (vty, "%s IP%s access list %s%s",
+		       mfilter->cisco ? 
+		       (filter->extended ? "Extended" : "Standard") : "Zebra",
+		       afi == AFI_IP6 ? "v6" : "",
+		       access->name, VTY_NEWLINE);
+	      write = 0;
+	    }
+
+	  vty_out (vty, "    %s%s", filter_type_str (mfilter),
+		   mfilter->type == FILTER_DENY ? "  " : "");
+
+	  if (! mfilter->cisco)
+	    config_write_access_zebra (vty, mfilter);
+	  else if (filter->extended)
+	    config_write_access_cisco (vty, mfilter);
+	  else
+	    {
+	      if (filter->addr_mask.s_addr == 0xffffffff)
+		vty_out (vty, " any%s", VTY_NEWLINE);
+	      else
+		{
+		  vty_out (vty, " %s", inet_ntoa (filter->addr));
+		  if (filter->addr_mask.s_addr != 0)
+		    vty_out (vty, ", wildcard bits %s", inet_ntoa (filter->addr_mask));
+		  vty_out (vty, "%s", VTY_NEWLINE);
+		}
+	    }
+	}
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_access_list,
+       show_ip_access_list_cmd,
+       "show ip access-list",
+       SHOW_STR
+       IP_STR
+       "List IP access lists\n")
+{
+  return filter_show (vty, NULL, AFI_IP);
+}
+
+DEFUN (show_ip_access_list_name,
+       show_ip_access_list_name_cmd,
+       "show ip access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD)",
+       SHOW_STR
+       IP_STR
+       "List IP access lists\n"
+       "IP standard access list\n"
+       "IP extended access list\n"
+       "IP standard access list (expanded range)\n"
+       "IP extended access list (expanded range)\n"
+       "IP zebra access-list\n")
+{
+  return filter_show (vty, argv[0], AFI_IP);
+}
+
+#ifdef HAVE_IPV6
+DEFUN (show_ipv6_access_list,
+       show_ipv6_access_list_cmd,
+       "show ipv6 access-list",
+       SHOW_STR
+       IPV6_STR
+       "List IPv6 access lists\n")
+{
+  return filter_show (vty, NULL, AFI_IP6);
+}
+
+DEFUN (show_ipv6_access_list_name,
+       show_ipv6_access_list_name_cmd,
+       "show ipv6 access-list WORD",
+       SHOW_STR
+       IPV6_STR
+       "List IPv6 access lists\n"
+       "IPv6 zebra access-list\n")
+{
+  return filter_show (vty, argv[0], AFI_IP6);
+}
+#endif /* HAVE_IPV6 */
+
+void
+config_write_access_cisco (struct vty *vty, struct filter *mfilter)
+{
+  struct filter_cisco *filter;
+
+  filter = &mfilter->u.cfilter;
+
+  if (filter->extended)
+    {
+      vty_out (vty, " ip");
+      if (filter->addr_mask.s_addr == 0xffffffff)
+	vty_out (vty, " any");
+      else if (filter->addr_mask.s_addr == 0)
+	vty_out (vty, " host %s", inet_ntoa (filter->addr));
+      else
+	{
+	  vty_out (vty, " %s", inet_ntoa (filter->addr));
+	  vty_out (vty, " %s", inet_ntoa (filter->addr_mask));
+        }
+
+      if (filter->mask_mask.s_addr == 0xffffffff)
+	vty_out (vty, " any");
+      else if (filter->mask_mask.s_addr == 0)
+	vty_out (vty, " host %s", inet_ntoa (filter->mask));
+      else
+	{
+	  vty_out (vty, " %s", inet_ntoa (filter->mask));
+	  vty_out (vty, " %s", inet_ntoa (filter->mask_mask));
+	}
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+  else
+    {
+      if (filter->addr_mask.s_addr == 0xffffffff)
+	vty_out (vty, " any%s", VTY_NEWLINE);
+      else
+	{
+	  vty_out (vty, " %s", inet_ntoa (filter->addr));
+	  if (filter->addr_mask.s_addr != 0)
+	    vty_out (vty, " %s", inet_ntoa (filter->addr_mask));
+	  vty_out (vty, "%s", VTY_NEWLINE);
+	}
+    }
+}
+
+void
+config_write_access_zebra (struct vty *vty, struct filter *mfilter)
+{
+  struct filter_zebra *filter;
+  struct prefix *p;
+  char buf[BUFSIZ];
+
+  filter = &mfilter->u.zfilter;
+  p = &filter->prefix;
+
+  if (p->prefixlen == 0 && ! filter->exact)
+    vty_out (vty, " any");
+  else
+    vty_out (vty, " %s/%d%s",
+	     inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+	     p->prefixlen,
+	     filter->exact ? " exact-match" : "");
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+}
+
+int
+config_write_access (struct vty *vty, afi_t afi)
+{
+  struct access_list *access;
+  struct access_master *master;
+  struct filter *mfilter;
+  int write = 0;
+
+  master = access_master_get (afi);
+  if (master == NULL)
+    return 0;
+
+  for (access = master->num.head; access; access = access->next)
+    {
+      if (access->remark)
+	{
+	  vty_out (vty, "%saccess-list %s remark %s%s",
+		   afi == AFI_IP ? "" : "ipv6 ",
+		   access->name, access->remark,
+		   VTY_NEWLINE);
+	  write++;
+	}
+
+      for (mfilter = access->head; mfilter; mfilter = mfilter->next)
+	{
+	  vty_out (vty, "%saccess-list %s %s",
+	     afi == AFI_IP ? "" : "ipv6 ",
+	     access->name,
+	     filter_type_str (mfilter));
+
+	  if (mfilter->cisco)
+	    config_write_access_cisco (vty, mfilter);
+	  else
+	    config_write_access_zebra (vty, mfilter);
+
+	  write++;
+	}
+    }
+
+  for (access = master->str.head; access; access = access->next)
+    {
+      if (access->remark)
+	{
+	  vty_out (vty, "%saccess-list %s remark %s%s",
+		   afi == AFI_IP ? "" : "ipv6 ",
+		   access->name, access->remark,
+		   VTY_NEWLINE);
+	  write++;
+	}
+
+      for (mfilter = access->head; mfilter; mfilter = mfilter->next)
+	{
+	  vty_out (vty, "%saccess-list %s %s",
+	     afi == AFI_IP ? "" : "ipv6 ",
+	     access->name,
+	     filter_type_str (mfilter));
+
+	  if (mfilter->cisco)
+	    config_write_access_cisco (vty, mfilter);
+	  else
+	    config_write_access_zebra (vty, mfilter);
+
+	  write++;
+	}
+    }
+  return write;
+}
+
+/* Access-list node. */
+struct cmd_node access_node =
+{
+  ACCESS_NODE,
+  "",				/* Access list has no interface. */
+  1
+};
+
+int
+config_write_access_ipv4 (struct vty *vty)
+{
+  return config_write_access (vty, AFI_IP);
+}
+
+void
+access_list_reset_ipv4 ()
+{
+  struct access_list *access;
+  struct access_list *next;
+  struct access_master *master;
+
+  master = access_master_get (AFI_IP);
+  if (master == NULL)
+    return;
+
+  for (access = master->num.head; access; access = next)
+    {
+      next = access->next;
+      access_list_delete (access);
+    }
+  for (access = master->str.head; access; access = next)
+    {
+      next = access->next;
+      access_list_delete (access);
+    }
+
+  assert (master->num.head == NULL);
+  assert (master->num.tail == NULL);
+
+  assert (master->str.head == NULL);
+  assert (master->str.tail == NULL);
+}
+
+/* Install vty related command. */
+void
+access_list_init_ipv4 ()
+{
+  install_node (&access_node, config_write_access_ipv4);
+
+  install_element (ENABLE_NODE, &show_ip_access_list_cmd);
+  install_element (ENABLE_NODE, &show_ip_access_list_name_cmd);
+
+  /* Zebra access-list */
+  install_element (CONFIG_NODE, &access_list_cmd);
+  install_element (CONFIG_NODE, &access_list_exact_cmd);
+  install_element (CONFIG_NODE, &access_list_any_cmd);
+  install_element (CONFIG_NODE, &no_access_list_cmd);
+  install_element (CONFIG_NODE, &no_access_list_exact_cmd);
+  install_element (CONFIG_NODE, &no_access_list_any_cmd);
+
+  /* Standard access-list */
+  install_element (CONFIG_NODE, &access_list_standard_cmd);
+  install_element (CONFIG_NODE, &access_list_standard_nomask_cmd);
+  install_element (CONFIG_NODE, &access_list_standard_host_cmd);
+  install_element (CONFIG_NODE, &access_list_standard_any_cmd);
+  install_element (CONFIG_NODE, &no_access_list_standard_cmd);
+  install_element (CONFIG_NODE, &no_access_list_standard_nomask_cmd);
+  install_element (CONFIG_NODE, &no_access_list_standard_host_cmd);
+  install_element (CONFIG_NODE, &no_access_list_standard_any_cmd);
+
+  /* Extended access-list */
+  install_element (CONFIG_NODE, &access_list_extended_cmd);
+  install_element (CONFIG_NODE, &access_list_extended_any_mask_cmd);
+  install_element (CONFIG_NODE, &access_list_extended_mask_any_cmd);
+  install_element (CONFIG_NODE, &access_list_extended_any_any_cmd);
+  install_element (CONFIG_NODE, &access_list_extended_host_mask_cmd);
+  install_element (CONFIG_NODE, &access_list_extended_mask_host_cmd);
+  install_element (CONFIG_NODE, &access_list_extended_host_host_cmd);
+  install_element (CONFIG_NODE, &access_list_extended_any_host_cmd);
+  install_element (CONFIG_NODE, &access_list_extended_host_any_cmd);
+  install_element (CONFIG_NODE, &no_access_list_extended_cmd);
+  install_element (CONFIG_NODE, &no_access_list_extended_any_mask_cmd);
+  install_element (CONFIG_NODE, &no_access_list_extended_mask_any_cmd);
+  install_element (CONFIG_NODE, &no_access_list_extended_any_any_cmd);
+  install_element (CONFIG_NODE, &no_access_list_extended_host_mask_cmd);
+  install_element (CONFIG_NODE, &no_access_list_extended_mask_host_cmd);
+  install_element (CONFIG_NODE, &no_access_list_extended_host_host_cmd);
+  install_element (CONFIG_NODE, &no_access_list_extended_any_host_cmd);
+  install_element (CONFIG_NODE, &no_access_list_extended_host_any_cmd);
+
+  install_element (CONFIG_NODE, &access_list_remark_cmd);
+  install_element (CONFIG_NODE, &no_access_list_all_cmd);
+  install_element (CONFIG_NODE, &no_access_list_remark_cmd);
+  install_element (CONFIG_NODE, &no_access_list_remark_arg_cmd);
+}
+
+#ifdef HAVE_IPV6
+struct cmd_node access_ipv6_node =
+{
+  ACCESS_IPV6_NODE,
+  "",
+  1
+};
+
+int
+config_write_access_ipv6 (struct vty *vty)
+{
+  return config_write_access (vty, AFI_IP6);
+}
+
+void
+access_list_reset_ipv6 ()
+{
+  struct access_list *access;
+  struct access_list *next;
+  struct access_master *master;
+
+  master = access_master_get (AFI_IP6);
+  if (master == NULL)
+    return;
+
+  for (access = master->num.head; access; access = next)
+    {
+      next = access->next;
+      access_list_delete (access);
+    }
+  for (access = master->str.head; access; access = next)
+    {
+      next = access->next;
+      access_list_delete (access);
+    }
+
+  assert (master->num.head == NULL);
+  assert (master->num.tail == NULL);
+
+  assert (master->str.head == NULL);
+  assert (master->str.tail == NULL);
+}
+
+void
+access_list_init_ipv6 ()
+{
+  install_node (&access_ipv6_node, config_write_access_ipv6);
+
+  install_element (ENABLE_NODE, &show_ipv6_access_list_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_access_list_name_cmd);
+
+  install_element (CONFIG_NODE, &ipv6_access_list_cmd);
+  install_element (CONFIG_NODE, &ipv6_access_list_exact_cmd);
+  install_element (CONFIG_NODE, &ipv6_access_list_any_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_access_list_exact_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_access_list_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_access_list_any_cmd);
+
+  install_element (CONFIG_NODE, &no_ipv6_access_list_all_cmd);
+  install_element (CONFIG_NODE, &ipv6_access_list_remark_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_access_list_remark_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_access_list_remark_arg_cmd);
+}
+#endif /* HAVE_IPV6 */
+
+void
+access_list_init ()
+{
+  access_list_init_ipv4 ();
+#ifdef HAVE_IPV6
+  access_list_init_ipv6();
+#endif /* HAVE_IPV6 */
+}
+
+void
+access_list_reset ()
+{
+  access_list_reset_ipv4 ();
+#ifdef HAVE_IPV6
+  access_list_reset_ipv6();
+#endif /* HAVE_IPV6 */
+}
diff --git a/lib/filter.h b/lib/filter.h
new file mode 100644
index 0000000..077ac2f
--- /dev/null
+++ b/lib/filter.h
@@ -0,0 +1,67 @@
+/*
+ * Route filtering function.
+ * Copyright (C) 1998 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 _ZEBRA_FILTER_H
+#define _ZEBRA_FILTER_H
+
+#include "if.h"
+
+/* Filter type is made by `permit', `deny' and `dynamic'. */
+enum filter_type 
+{
+  FILTER_DENY,
+  FILTER_PERMIT,
+  FILTER_DYNAMIC
+};
+
+enum access_type
+{
+  ACCESS_TYPE_STRING,
+  ACCESS_TYPE_NUMBER
+};
+
+/* Access list */
+struct access_list
+{
+  char *name;
+  char *remark;
+
+  struct access_master *master;
+
+  enum access_type type;
+
+  struct access_list *next;
+  struct access_list *prev;
+
+  struct filter *head;
+  struct filter *tail;
+};
+
+/* Prototypes for access-list. */
+void access_list_init (void);
+void access_list_reset (void);
+void access_list_add_hook (void (*func)(struct access_list *));
+void access_list_delete_hook (void (*func)(struct access_list *));
+struct access_list *access_list_lookup (afi_t, char *);
+enum filter_type access_list_apply (struct access_list *, void *);
+
+#endif /* _ZEBRA_FILTER_H */
diff --git a/lib/getopt.c b/lib/getopt.c
new file mode 100644
index 0000000..426b29b
--- /dev/null
+++ b/lib/getopt.c
@@ -0,0 +1,1054 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to drepper@gnu.org
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98
+   	Free Software Foundation, Inc.
+
+   NOTE: The canonical source of this file is maintained with the GNU C Library.
+   Bugs can be reported to bug-glibc@gnu.org.
+
+   This program 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.
+
+   This program 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 this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.  */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+   Ditto for AIX 3.2 and <stdlib.h>.  */
+#ifndef _NO_PROTO
+# define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if !defined __STDC__ || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+# ifndef const
+#  define const
+# endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+# include <gnu-versions.h>
+# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#  define ELIDE_CODE
+# endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef	__GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+# include <stdlib.h>
+# include <unistd.h>
+#endif	/* GNU C library.  */
+
+#ifdef VMS
+# include <unixlib.h>
+# if HAVE_STRING_H - 0
+#  include <string.h>
+# endif
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages.
+   When compiling libc, the _ macro is predefined.  */
+# ifdef HAVE_LIBINTL_H
+#  include <libintl.h>
+#  define _(msgid)	gettext (msgid)
+# else
+#  define _(msgid)	(msgid)
+# endif
+#endif
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* 1003.2 says this must be 1 before any call.  */
+int optind = 1;
+
+/* Formerly, initialization of getopt depended on optind==0, which
+   causes problems with re-calling getopt as programs generally don't
+   know that. */
+
+int __getopt_initialized = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return -1 with `optind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable.  */
+static char *posixly_correct;
+
+#ifdef	__GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+# include <string.h>
+# define my_index	strchr
+#else
+
+# if HAVE_STRING_H
+#  include <string.h>
+# else
+#  include <strings.h>
+# endif
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+#ifndef getenv
+extern char *getenv ();
+#endif
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+	return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+   If not using GCC, it is ok not to declare it.  */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+   That was relevant to code that was here before.  */
+# if (!defined __STDC__ || !__STDC__) && !defined strlen
+/* gcc with -traditional declares the built-in strlen to return int,
+   and has done so at least since version 2.4.5. -- rms.  */
+extern int strlen (const char *);
+# endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+#ifdef _LIBC
+/* Bash 2.0 gives us an environment variable containing flags
+   indicating ARGV elements that should not be considered arguments.  */
+
+/* Defined in getopt_init.c  */
+extern char *__getopt_nonoption_flags;
+
+static int nonoption_flags_max_len;
+static int nonoption_flags_len;
+
+static int original_argc;
+static char *const *original_argv;
+
+/* Make sure the environment variable bash 2.0 puts in the environment
+   is valid for the getopt call we must make sure that the ARGV passed
+   to getopt is that one passed to the process.  */
+static void
+__attribute__ ((unused))
+store_args_and_env (int argc, char *const *argv)
+{
+  /* XXX This is no good solution.  We should rather copy the args so
+     that we can compare them later.  But we must not use malloc(3).  */
+  original_argc = argc;
+  original_argv = argv;
+}
+# ifdef text_set_element
+text_set_element (__libc_subinit, store_args_and_env);
+# endif /* text_set_element */
+
+# define SWAP_FLAGS(ch1, ch2) \
+  if (nonoption_flags_len > 0)						      \
+    {									      \
+      char __tmp = __getopt_nonoption_flags[ch1];			      \
+      __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2];	      \
+      __getopt_nonoption_flags[ch2] = __tmp;				      \
+    }
+#else	/* !_LIBC */
+# define SWAP_FLAGS(ch1, ch2)
+#endif	/* _LIBC */
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+#if defined __STDC__ && __STDC__
+static void exchange (char **);
+#endif
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int bottom = first_nonopt;
+  int middle = last_nonopt;
+  int top = optind;
+  char *tem;
+
+  /* Exchange the shorter segment with the far end of the longer segment.
+     That puts the shorter segment into the right place.
+     It leaves the longer segment in the right place overall,
+     but it consists of two parts that need to be swapped next.  */
+
+#ifdef _LIBC
+  /* First make sure the handling of the `__getopt_nonoption_flags'
+     string can work normally.  Our top argument must be in the range
+     of the string.  */
+  if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)
+    {
+      /* We must extend the array.  The user plays games with us and
+	 presents new arguments.  */
+      char *new_str = malloc (top + 1);
+      if (new_str == NULL)
+	nonoption_flags_len = nonoption_flags_max_len = 0;
+      else
+	{
+	  memset (__mempcpy (new_str, __getopt_nonoption_flags,
+			     nonoption_flags_max_len),
+		  '\0', top + 1 - nonoption_flags_max_len);
+	  nonoption_flags_max_len = top + 1;
+	  __getopt_nonoption_flags = new_str;
+	}
+    }
+#endif
+
+  while (top > middle && middle > bottom)
+    {
+      if (top - middle > middle - bottom)
+	{
+	  /* Bottom segment is the short one.  */
+	  int len = middle - bottom;
+	  register int i;
+
+	  /* Swap it with the top part of the top segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[top - (middle - bottom) + i];
+	      argv[top - (middle - bottom) + i] = tem;
+	      SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
+	    }
+	  /* Exclude the moved bottom segment from further swapping.  */
+	  top -= len;
+	}
+      else
+	{
+	  /* Top segment is the short one.  */
+	  int len = top - middle;
+	  register int i;
+
+	  /* Swap it with the bottom part of the bottom segment.  */
+	  for (i = 0; i < len; i++)
+	    {
+	      tem = argv[bottom + i];
+	      argv[bottom + i] = argv[middle + i];
+	      argv[middle + i] = tem;
+	      SWAP_FLAGS (bottom + i, middle + i);
+	    }
+	  /* Exclude the moved top segment from further swapping.  */
+	  bottom += len;
+	}
+    }
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made.  */
+
+#if defined __STDC__ && __STDC__
+static const char *_getopt_initialize (int, char *const *, const char *);
+#endif
+static const char *
+_getopt_initialize (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  /* Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  first_nonopt = last_nonopt = optind;
+
+  nextchar = NULL;
+
+  posixly_correct = getenv ("POSIXLY_CORRECT");
+
+  /* Determine how to handle the ordering of options and nonoptions.  */
+
+  if (optstring[0] == '-')
+    {
+      ordering = RETURN_IN_ORDER;
+      ++optstring;
+    }
+  else if (optstring[0] == '+')
+    {
+      ordering = REQUIRE_ORDER;
+      ++optstring;
+    }
+  else if (posixly_correct != NULL)
+    ordering = REQUIRE_ORDER;
+  else
+    ordering = PERMUTE;
+
+#ifdef _LIBC
+  if (posixly_correct == NULL
+      && argc == original_argc && argv == original_argv)
+    {
+      if (nonoption_flags_max_len == 0)
+	{
+	  if (__getopt_nonoption_flags == NULL
+	      || __getopt_nonoption_flags[0] == '\0')
+	    nonoption_flags_max_len = -1;
+	  else
+	    {
+	      const char *orig_str = __getopt_nonoption_flags;
+	      int len = nonoption_flags_max_len = strlen (orig_str);
+	      if (nonoption_flags_max_len < argc)
+		nonoption_flags_max_len = argc;
+	      __getopt_nonoption_flags =
+		(char *) malloc (nonoption_flags_max_len);
+	      if (__getopt_nonoption_flags == NULL)
+		nonoption_flags_max_len = -1;
+	      else
+		memset (__mempcpy (__getopt_nonoption_flags, orig_str, len),
+			'\0', nonoption_flags_max_len - len);
+	    }
+	}
+      nonoption_flags_len = nonoption_flags_max_len;
+    }
+  else
+    nonoption_flags_len = 0;
+#endif
+
+  return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns -1.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  optarg = NULL;
+
+  if (optind == 0 || !__getopt_initialized)
+    {
+      if (optind == 0)
+	optind = 1;	/* Don't scan ARGV[0], the program name.  */
+      optstring = _getopt_initialize (argc, argv, optstring);
+      __getopt_initialized = 1;
+    }
+
+  /* Test whether ARGV[optind] points to a non-option argument.
+     Either it does not have option syntax, or there is an environment flag
+     from the shell indicating it is not an option.  The later information
+     is only used when the used in the GNU libc.  */
+#ifdef _LIBC
+# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0'	      \
+		      || (optind < nonoption_flags_len			      \
+			  && __getopt_nonoption_flags[optind] == '1'))
+#else
+# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#endif
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      /* Advance to the next ARGV-element.  */
+
+      /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+	 moved back by the user (who may also have changed the arguments).  */
+      if (last_nonopt > optind)
+	last_nonopt = optind;
+      if (first_nonopt > optind)
+	first_nonopt = optind;
+
+      if (ordering == PERMUTE)
+	{
+	  /* If we have just processed some options following some non-options,
+	     exchange them so that the options come first.  */
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (last_nonopt != optind)
+	    first_nonopt = optind;
+
+	  /* Skip any additional non-options
+	     and extend the range of non-options previously skipped.  */
+
+	  while (optind < argc && NONOPTION_P)
+	    optind++;
+	  last_nonopt = optind;
+	}
+
+      /* The special ARGV-element `--' means premature end of options.
+	 Skip it like a null option,
+	 then exchange with previous non-options as if it were an option,
+	 then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+	{
+	  optind++;
+
+	  if (first_nonopt != last_nonopt && last_nonopt != optind)
+	    exchange ((char **) argv);
+	  else if (first_nonopt == last_nonopt)
+	    first_nonopt = optind;
+	  last_nonopt = argc;
+
+	  optind = argc;
+	}
+
+      /* If we have done all the ARGV-elements, stop the scan
+	 and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+	{
+	  /* Set the next-arg-index to point at the non-options
+	     that we previously skipped, so the caller will digest them.  */
+	  if (first_nonopt != last_nonopt)
+	    optind = first_nonopt;
+	  return -1;
+	}
+
+      /* If we have come to a non-option and did not permute it,
+	 either stop the scan or describe it to the caller and pass it by.  */
+
+      if (NONOPTION_P)
+	{
+	  if (ordering == REQUIRE_ORDER)
+	    return -1;
+	  optarg = argv[optind++];
+	  return 1;
+	}
+
+      /* We have found another option-ARGV-element.
+	 Skip the initial punctuation.  */
+
+      nextchar = (argv[optind] + 1
+		  + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  /* Decode the current option-ARGV-element.  */
+
+  /* Check whether the ARGV-element is a long option.
+
+     If long_only and the ARGV-element has the form "-f", where f is
+     a valid short option, don't consider it an abbreviated form of
+     a long option that starts with f.  Otherwise there would be no
+     way to give the -f short option.
+
+     On the other hand, if there's a long option "fubar" and
+     the ARGV-element is "-fu", do consider that an abbreviation of
+     the long option, just like "--fu", and not "-f" with arg "u".
+
+     This distinction seems to be the most useful approach.  */
+
+  if (longopts != NULL
+      && (argv[optind][1] == '-'
+	  || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+    {
+      char *nameend;
+      const struct option *p;
+      const struct option *pfound = NULL;
+      int exact = 0;
+      int ambig = 0;
+      int indfound = -1;
+      int option_index;
+
+      for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+	/* Do nothing.  */ ;
+
+      /* Test all long options for either exact match
+	 or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name; p++, option_index++)
+	if (!strncmp (p->name, nextchar, nameend - nextchar))
+	  {
+	    if ((unsigned int) (nameend - nextchar)
+		== (unsigned int) strlen (p->name))
+	      {
+		/* Exact match found.  */
+		pfound = p;
+		indfound = option_index;
+		exact = 1;
+		break;
+	      }
+	    else if (pfound == NULL)
+	      {
+		/* First nonexact match found.  */
+		pfound = p;
+		indfound = option_index;
+	      }
+	    else
+	      /* Second or later nonexact match found.  */
+	      ambig = 1;
+	  }
+
+      if (ambig && !exact)
+	{
+	  if (opterr)
+	    fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
+		     argv[0], argv[optind]);
+	  nextchar += strlen (nextchar);
+	  optind++;
+	  optopt = 0;
+	  return '?';
+	}
+
+      if (pfound != NULL)
+	{
+	  option_index = indfound;
+	  optind++;
+	  if (*nameend)
+	    {
+	      /* Don't test has_arg with >, because some C compilers don't
+		 allow it to be used on enums.  */
+	      if (pfound->has_arg)
+		optarg = nameend + 1;
+	      else
+		{
+		  if (opterr)
+                    {
+		      if (argv[optind - 1][1] == '-')
+		        /* --option */
+		        fprintf (stderr,
+		         _("%s: option `--%s' doesn't allow an argument\n"),
+		         argv[0], pfound->name);
+		      else
+		        /* +option or -option */
+		        fprintf (stderr,
+		         _("%s: option `%c%s' doesn't allow an argument\n"),
+		         argv[0], argv[optind - 1][0], pfound->name);
+                    }
+
+		  nextchar += strlen (nextchar);
+
+		  optopt = pfound->val;
+		  return '?';
+		}
+	    }
+	  else if (pfound->has_arg == 1)
+	    {
+	      if (optind < argc)
+		optarg = argv[optind++];
+	      else
+		{
+		  if (opterr)
+		    fprintf (stderr,
+			   _("%s: option `%s' requires an argument\n"),
+			   argv[0], argv[optind - 1]);
+		  nextchar += strlen (nextchar);
+		  optopt = pfound->val;
+		  return optstring[0] == ':' ? ':' : '?';
+		}
+	    }
+	  nextchar += strlen (nextchar);
+	  if (longind != NULL)
+	    *longind = option_index;
+	  if (pfound->flag)
+	    {
+	      *(pfound->flag) = pfound->val;
+	      return 0;
+	    }
+	  return pfound->val;
+	}
+
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+	 or the option starts with '--' or is not a valid short
+	 option, then it's an error.
+	 Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+	  || my_index (optstring, *nextchar) == NULL)
+	{
+	  if (opterr)
+	    {
+	      if (argv[optind][1] == '-')
+		/* --option */
+		fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
+			 argv[0], nextchar);
+	      else
+		/* +option or -option */
+		fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
+			 argv[0], argv[optind][0], nextchar);
+	    }
+	  nextchar = (char *) "";
+	  optind++;
+	  optopt = 0;
+	  return '?';
+	}
+    }
+
+  /* Look at and handle the next short option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+	if (opterr)
+	  {
+	    if (posixly_correct)
+	      /* 1003.2 specifies the format of this message.  */
+	      fprintf (stderr, _("%s: illegal option -- %c\n"),
+		       argv[0], c);
+	    else
+	      fprintf (stderr, _("%s: invalid option -- %c\n"),
+		       argv[0], c);
+	  }
+	optopt = c;
+	return '?';
+      }
+    /* Convenience. Treat POSIX -W foo same as long option --foo */
+    if (temp[0] == 'W' && temp[1] == ';')
+      {
+	char *nameend;
+	const struct option *p;
+	const struct option *pfound = NULL;
+	int exact = 0;
+	int ambig = 0;
+	int indfound = 0;
+	int option_index;
+
+	/* This is an option that requires an argument.  */
+	if (*nextchar != '\0')
+	  {
+	    optarg = nextchar;
+	    /* If we end this ARGV-element by taking the rest as an arg,
+	       we must advance to the next element now.  */
+	    optind++;
+	  }
+	else if (optind == argc)
+	  {
+	    if (opterr)
+	      {
+		/* 1003.2 specifies the format of this message.  */
+		fprintf (stderr, _("%s: option requires an argument -- %c\n"),
+			 argv[0], c);
+	      }
+	    optopt = c;
+	    if (optstring[0] == ':')
+	      c = ':';
+	    else
+	      c = '?';
+	    return c;
+	  }
+	else
+	  /* We already incremented `optind' once;
+	     increment it again when taking next ARGV-elt as argument.  */
+	  optarg = argv[optind++];
+
+	/* optarg is now the argument, see if it's in the
+	   table of longopts.  */
+
+	for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
+	  /* Do nothing.  */ ;
+
+	/* Test all long options for either exact match
+	   or abbreviated matches.  */
+	for (p = longopts, option_index = 0; p->name; p++, option_index++)
+	  if (!strncmp (p->name, nextchar, nameend - nextchar))
+	    {
+	      if ((unsigned int) (nameend - nextchar) == strlen (p->name))
+		{
+		  /* Exact match found.  */
+		  pfound = p;
+		  indfound = option_index;
+		  exact = 1;
+		  break;
+		}
+	      else if (pfound == NULL)
+		{
+		  /* First nonexact match found.  */
+		  pfound = p;
+		  indfound = option_index;
+		}
+	      else
+		/* Second or later nonexact match found.  */
+		ambig = 1;
+	    }
+	if (ambig && !exact)
+	  {
+	    if (opterr)
+	      fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
+		       argv[0], argv[optind]);
+	    nextchar += strlen (nextchar);
+	    optind++;
+	    return '?';
+	  }
+	if (pfound != NULL)
+	  {
+	    option_index = indfound;
+	    if (*nameend)
+	      {
+		/* Don't test has_arg with >, because some C compilers don't
+		   allow it to be used on enums.  */
+		if (pfound->has_arg)
+		  optarg = nameend + 1;
+		else
+		  {
+		    if (opterr)
+		      fprintf (stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+			       argv[0], pfound->name);
+
+		    nextchar += strlen (nextchar);
+		    return '?';
+		  }
+	      }
+	    else if (pfound->has_arg == 1)
+	      {
+		if (optind < argc)
+		  optarg = argv[optind++];
+		else
+		  {
+		    if (opterr)
+		      fprintf (stderr,
+			       _("%s: option `%s' requires an argument\n"),
+			       argv[0], argv[optind - 1]);
+		    nextchar += strlen (nextchar);
+		    return optstring[0] == ':' ? ':' : '?';
+		  }
+	      }
+	    nextchar += strlen (nextchar);
+	    if (longind != NULL)
+	      *longind = option_index;
+	    if (pfound->flag)
+	      {
+		*(pfound->flag) = pfound->val;
+		return 0;
+	      }
+	    return pfound->val;
+	  }
+	  nextchar = NULL;
+	  return 'W';	/* Let the application handle it.   */
+      }
+    if (temp[1] == ':')
+      {
+	if (temp[2] == ':')
+	  {
+	    /* This is an option that accepts an argument optionally.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		optind++;
+	      }
+	    else
+	      optarg = NULL;
+	    nextchar = NULL;
+	  }
+	else
+	  {
+	    /* This is an option that requires an argument.  */
+	    if (*nextchar != '\0')
+	      {
+		optarg = nextchar;
+		/* If we end this ARGV-element by taking the rest as an arg,
+		   we must advance to the next element now.  */
+		optind++;
+	      }
+	    else if (optind == argc)
+	      {
+		if (opterr)
+		  {
+		    /* 1003.2 specifies the format of this message.  */
+		    fprintf (stderr,
+			   _("%s: option requires an argument -- %c\n"),
+			   argv[0], c);
+		  }
+		optopt = c;
+		if (optstring[0] == ':')
+		  c = ':';
+		else
+		  c = '?';
+	      }
+	    else
+	      /* We already incremented `optind' once;
+		 increment it again when taking next ARGV-elt as argument.  */
+	      optarg = argv[optind++];
+	    nextchar = NULL;
+	  }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+			   (const struct option *) 0,
+			   (int *) 0,
+			   0);
+}
+
+#endif	/* Not ELIDE_CODE.  */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+
+      c = getopt (argc, argv, "abc:d:0123456789");
+      if (c == -1)
+	break;
+
+      switch (c)
+	{
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+	printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/lib/getopt.h b/lib/getopt.h
new file mode 100644
index 0000000..fb30719
--- /dev/null
+++ b/lib/getopt.h
@@ -0,0 +1,133 @@
+/* Declarations for getopt.
+   Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
+
+   NOTE: The canonical source of this file is maintained with the GNU C Library.
+   Bugs can be reported to bug-glibc@gnu.org.
+
+   This program 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.
+
+   This program 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 this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.  */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument		(or 0) if the option does not take an argument,
+   required_argument	(or 1) if the option requires an argument,
+   optional_argument 	(or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+struct option
+{
+#if defined (__STDC__) && __STDC__
+  const char *name;
+#else
+  char *name;
+#endif
+  /* has_arg can't be an enum because some compilers complain about
+     type mismatches in all the code that assumes it is an int.  */
+  int has_arg;
+  int *flag;
+  int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+#define	no_argument		0
+#define required_argument	1
+#define optional_argument	2
+
+#if defined (__STDC__) && __STDC__
+#ifdef __GNU_LIBRARY__
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+		        const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+			     const char *shortopts,
+		             const struct option *longopts, int *longind);
+
+/* Internal only.  Users should not call this directly.  */
+extern int _getopt_internal (int argc, char *const *argv,
+			     const char *shortopts,
+		             const struct option *longopts, int *longind,
+			     int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* __STDC__ */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* getopt.h */
diff --git a/lib/getopt1.c b/lib/getopt1.c
new file mode 100644
index 0000000..ff25737
--- /dev/null
+++ b/lib/getopt1.c
@@ -0,0 +1,190 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+   Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98
+     Free Software Foundation, Inc.
+
+   NOTE: The canonical source of this file is maintained with the GNU C Library.
+   Bugs can be reported to bug-glibc@gnu.org.
+
+   This program 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.
+
+   This program 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 this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+   USA.  */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "getopt.h"
+
+#if !defined __STDC__ || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#endif
+
+#ifndef	NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead.  */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif	/* Not ELIDE_CODE.  */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+      int option_index = 0;
+      static struct option long_options[] =
+      {
+	{"add", 1, 0, 0},
+	{"append", 0, 0, 0},
+	{"delete", 1, 0, 0},
+	{"verbose", 0, 0, 0},
+	{"create", 0, 0, 0},
+	{"file", 1, 0, 0},
+	{0, 0, 0, 0}
+      };
+
+      c = getopt_long (argc, argv, "abc:d:0123456789",
+		       long_options, &option_index);
+      if (c == -1)
+	break;
+
+      switch (c)
+	{
+	case 0:
+	  printf ("option %s", long_options[option_index].name);
+	  if (optarg)
+	    printf (" with arg %s", optarg);
+	  printf ("\n");
+	  break;
+
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+	case '8':
+	case '9':
+	  if (digit_optind != 0 && digit_optind != this_option_optind)
+	    printf ("digits occur in two different argv-elements.\n");
+	  digit_optind = this_option_optind;
+	  printf ("option %c\n", c);
+	  break;
+
+	case 'a':
+	  printf ("option a\n");
+	  break;
+
+	case 'b':
+	  printf ("option b\n");
+	  break;
+
+	case 'c':
+	  printf ("option c with value `%s'\n", optarg);
+	  break;
+
+	case 'd':
+	  printf ("option d with value `%s'\n", optarg);
+	  break;
+
+	case '?':
+	  break;
+
+	default:
+	  printf ("?? getopt returned character code 0%o ??\n", c);
+	}
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+	printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/lib/hash.c b/lib/hash.c
new file mode 100644
index 0000000..4097507
--- /dev/null
+++ b/lib/hash.c
@@ -0,0 +1,182 @@
+/* Hash routine.
+ * Copyright (C) 1998 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.
+ */
+
+#include <zebra.h>
+
+#include "hash.h"
+#include "memory.h"
+
+/* Allocate a new hash.  */
+struct hash *
+hash_create_size (unsigned int size, 
+		  unsigned int (*hash_key) (), int (*hash_cmp) ())
+{
+  struct hash *hash;
+
+  hash = XMALLOC (MTYPE_HASH, sizeof (struct hash));
+  hash->index = XMALLOC (MTYPE_HASH_INDEX, 
+			 sizeof (struct hash_backet *) * size);
+  memset (hash->index, 0, sizeof (struct hash_backet *) * size);
+  hash->size = size;
+  hash->hash_key = hash_key;
+  hash->hash_cmp = hash_cmp;
+  hash->count = 0;
+
+  return hash;
+}
+
+/* Allocate a new hash with default hash size.  */
+struct hash *
+hash_create (unsigned int (*hash_key) (), int (*hash_cmp) ())
+{
+  return hash_create_size (HASHTABSIZE, hash_key, hash_cmp);
+}
+
+/* Utility function for hash_get().  When this function is specified
+   as alloc_func, return arugment as it is.  This function is used for
+   intern already allocated value.  */
+void *
+hash_alloc_intern (void *arg)
+{
+  return arg;
+}
+
+/* Lookup and return hash backet in hash.  If there is no
+   corresponding hash backet and alloc_func is specified, create new
+   hash backet.  */
+void *
+hash_get (struct hash *hash, void *data, void * (*alloc_func) ())
+{
+  unsigned int key;
+  unsigned int index;
+  void *newdata;
+  struct hash_backet *backet;
+
+  key = (*hash->hash_key) (data);
+  index = key % hash->size;
+
+  for (backet = hash->index[index]; backet != NULL; backet = backet->next) 
+    if (backet->key == key && (*hash->hash_cmp) (backet->data, data))
+      return backet->data;
+
+  if (alloc_func)
+    {
+      newdata = (*alloc_func) (data);
+      if (newdata == NULL)
+	return NULL;
+
+      backet = XMALLOC (MTYPE_HASH_BACKET, sizeof (struct hash_backet));
+      backet->data = newdata;
+      backet->key = key;
+      backet->next = hash->index[index];
+      hash->index[index] = backet;
+      hash->count++;
+      return backet->data;
+    }
+  return NULL;
+}
+
+/* Hash lookup.  */
+void *
+hash_lookup (struct hash *hash, void *data)
+{
+  return hash_get (hash, data, NULL);
+}
+
+/* This function release registered value from specified hash.  When
+   release is successfully finished, return the data pointer in the
+   hash backet.  */
+void *
+hash_release (struct hash *hash, void *data)
+{
+  void *ret;
+  unsigned int key;
+  unsigned int index;
+  struct hash_backet *backet;
+  struct hash_backet *pp;
+
+  key = (*hash->hash_key) (data);
+  index = key % hash->size;
+
+  for (backet = pp = hash->index[index]; backet; backet = backet->next)
+    {
+      if (backet->key == key && (*hash->hash_cmp) (backet->data, data)) 
+	{
+	  if (backet == pp) 
+	    hash->index[index] = backet->next;
+	  else 
+	    pp->next = backet->next;
+
+	  ret = backet->data;
+	  XFREE (MTYPE_HASH_BACKET, backet);
+	  hash->count--;
+	  return ret;
+	}
+      pp = backet;
+    }
+  return NULL;
+}
+
+/* Iterator function for hash.  */
+void
+hash_iterate (struct hash *hash, 
+	      void (*func) (struct hash_backet *, void *), void *arg)
+{
+  int i;
+  struct hash_backet *hb;
+
+  for (i = 0; i < hash->size; i++)
+    for (hb = hash->index[i]; hb; hb = hb->next)
+      (*func) (hb, arg);
+}
+
+/* Clean up hash.  */
+void
+hash_clean (struct hash *hash, void (*free_func) (void *))
+{
+  int i;
+  struct hash_backet *hb;
+  struct hash_backet *next;
+
+  for (i = 0; i < hash->size; i++)
+    {
+      for (hb = hash->index[i]; hb; hb = next)
+	{
+	  next = hb->next;
+	      
+	  if (free_func)
+	    (*free_func) (hb->data);
+
+	  XFREE (MTYPE_HASH_BACKET, hb);
+	  hash->count--;
+	}
+      hash->index[i] = NULL;
+    }
+}
+
+/* Free hash memory.  You may call hash_clean before call this
+   function.  */
+void
+hash_free (struct hash *hash)
+{
+  XFREE (MTYPE_HASH_INDEX, hash->index);
+  XFREE (MTYPE_HASH, hash);
+}
diff --git a/lib/hash.h b/lib/hash.h
new file mode 100644
index 0000000..715e53b
--- /dev/null
+++ b/lib/hash.h
@@ -0,0 +1,71 @@
+/* Hash routine.
+   Copyright (C) 1998 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 _ZEBRA_HASH_H
+#define _ZEBRA_HASH_H
+
+/* Default hash table size.  */ 
+#define HASHTABSIZE     1024
+
+struct hash_backet
+{
+  /* Linked list.  */
+  struct hash_backet *next;
+
+  /* Hash key. */
+  unsigned int key;
+
+  /* Data.  */
+  void *data;
+};
+
+struct hash
+{
+  /* Hash backet. */
+  struct hash_backet **index;
+
+  /* Hash table size. */
+  unsigned int size;
+
+  /* Key make function. */
+  unsigned int (*hash_key) ();
+
+  /* Data compare function. */
+  int (*hash_cmp) ();
+
+  /* Backet alloc. */
+  unsigned long count;
+};
+
+struct hash *hash_create (unsigned int (*) (), int (*) ());
+struct hash *hash_create_size (unsigned int, unsigned int (*) (), int (*) ());
+
+void *hash_get (struct hash *, void *, void * (*) ());
+void *hash_alloc_intern (void *);
+void *hash_lookup (struct hash *, void *);
+void *hash_release (struct hash *, void *);
+
+void hash_iterate (struct hash *, 
+		   void (*) (struct hash_backet *, void *), void *);
+
+void hash_clean (struct hash *, void (*) (void *));
+void hash_free (struct hash *);
+
+#endif /* _ZEBRA_HASH_H */
diff --git a/lib/if.c b/lib/if.c
new file mode 100644
index 0000000..bbf22ab
--- /dev/null
+++ b/lib/if.c
@@ -0,0 +1,713 @@
+/* 
+ * Interface functions.
+ * Copyright (C) 1997, 98 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.
+ */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "vector.h"
+#include "vty.h"
+#include "command.h"
+#include "if.h"
+#include "sockunion.h"
+#include "prefix.h"
+#include "zebra/connected.h"
+#include "memory.h"
+#include "table.h"
+#include "buffer.h"
+#include "str.h"
+#include "log.h"
+
+/* Master list of interfaces. */
+struct list *iflist;
+
+/* One for each program.  This structure is needed to store hooks. */
+struct if_master
+{
+  int (*if_new_hook) (struct interface *);
+  int (*if_delete_hook) (struct interface *);
+} if_master;
+
+/* Create new interface structure. */
+struct interface *
+if_new ()
+{
+  struct interface *ifp;
+
+  ifp = XMALLOC (MTYPE_IF, sizeof (struct interface));
+  memset (ifp, 0, sizeof (struct interface));
+  return ifp;
+}
+
+struct interface *
+if_create ()
+{
+  struct interface *ifp;
+
+  ifp = if_new ();
+  
+  listnode_add (iflist, ifp);
+  ifp->connected = list_new ();
+  ifp->connected->del = (void (*) (void *)) connected_free;
+
+  if (if_master.if_new_hook)
+    (*if_master.if_new_hook) (ifp);
+
+  return ifp;
+}
+
+/* Delete and free interface structure. */
+void
+if_delete (struct interface *ifp)
+{
+  listnode_delete (iflist, ifp);
+
+  if (if_master.if_delete_hook)
+    (*if_master.if_delete_hook) (ifp);
+
+  /* Free connected address list */
+  list_delete (ifp->connected);
+
+  XFREE (MTYPE_IF, ifp);
+}
+
+/* Add hook to interface master. */
+void
+if_add_hook (int type, int (*func)(struct interface *ifp))
+{
+  switch (type) {
+  case IF_NEW_HOOK:
+    if_master.if_new_hook = func;
+    break;
+  case IF_DELETE_HOOK:
+    if_master.if_delete_hook = func;
+    break;
+  default:
+    break;
+  }
+}
+
+/* Interface existance check by index. */
+struct interface *
+if_lookup_by_index (unsigned int index)
+{
+  listnode node;
+  struct interface *ifp;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      if (ifp->ifindex == index)
+	return ifp;
+    }
+  return NULL;
+}
+
+char *
+ifindex2ifname (unsigned int index)
+{
+  listnode node;
+  struct interface *ifp;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      if (ifp->ifindex == index)
+	return ifp->name;
+    }
+  return "unknown";
+}
+
+/* Interface existance check by interface name. */
+struct interface *
+if_lookup_by_name (char *name)
+{
+  listnode node;
+  struct interface *ifp;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      if (strncmp (name, ifp->name, sizeof ifp->name) == 0)
+	return ifp;
+    }
+  return NULL;
+}
+
+/* Lookup interface by IPv4 address. */
+struct interface *
+if_lookup_exact_address (struct in_addr src)
+{
+  listnode node;
+  listnode cnode;
+  struct interface *ifp;
+  struct prefix *p;
+  struct connected *c;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+	{
+	  c = getdata (cnode);
+
+	  p = c->address;
+
+	  if (p && p->family == AF_INET)
+	    {
+	      if (IPV4_ADDR_SAME (&p->u.prefix4, &src))
+		return ifp;
+	    }	      
+	}
+    }
+  return NULL;
+}
+
+/* Lookup interface by IPv4 address. */
+struct interface *
+if_lookup_address (struct in_addr src)
+{
+  listnode node;
+  struct prefix addr;
+  struct prefix best;
+  listnode cnode;
+  struct interface *ifp;
+  struct prefix *p;
+  struct connected *c;
+  struct interface *match;
+
+  /* Zero structures - get rid of rubbish from stack */
+  memset(&addr, 0, sizeof(addr));
+  memset(&best, 0, sizeof(best));
+
+  addr.family = AF_INET;
+  addr.u.prefix4 = src;
+  addr.prefixlen = IPV4_MAX_BITLEN;
+
+  match = NULL;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+	{
+	  c = getdata (cnode);
+
+	  if (if_is_pointopoint (ifp))
+	    {
+	      p = c->address;
+
+	      if (p && p->family == AF_INET)
+		{
+#ifdef OLD_RIB	 /* PTP  links are conventionally identified 
+		     by the address of the far end - MAG */
+		  if (IPV4_ADDR_SAME (&p->u.prefix4, &src))
+		    return ifp;
+#endif
+		  p = c->destination;
+		  if (p && IPV4_ADDR_SAME (&p->u.prefix4, &src))
+		    return ifp;
+		}
+	    }
+	  else
+	    {
+	      p = c->address;
+
+	      if (p->family == AF_INET)
+		{
+		  if (prefix_match (p, &addr) && p->prefixlen > best.prefixlen)
+		    {
+		      best = *p;
+		      match = ifp;
+		    }
+		}
+	    }
+	}
+    }
+  return match;
+}
+
+/* Get interface by name if given name interface doesn't exist create
+   one. */
+struct interface *
+if_get_by_name (char *name)
+{
+  struct interface *ifp;
+
+  ifp = if_lookup_by_name (name);
+  if (ifp == NULL)
+    {
+      ifp = if_create ();
+      strncpy (ifp->name, name, IFNAMSIZ);
+    }
+  return ifp;
+}
+
+/* Does interface up ? */
+int
+if_is_up (struct interface *ifp)
+{
+  return ifp->flags & IFF_UP;
+}
+
+/* Is this loopback interface ? */
+int
+if_is_loopback (struct interface *ifp)
+{
+  return ifp->flags & IFF_LOOPBACK;
+}
+
+/* Does this interface support broadcast ? */
+int
+if_is_broadcast (struct interface *ifp)
+{
+  return ifp->flags & IFF_BROADCAST;
+}
+
+/* Does this interface support broadcast ? */
+int
+if_is_pointopoint (struct interface *ifp)
+{
+  return ifp->flags & IFF_POINTOPOINT;
+}
+
+/* Does this interface support multicast ? */
+int
+if_is_multicast (struct interface *ifp)
+{
+  return ifp->flags & IFF_MULTICAST;
+}
+
+/* Printout flag information into log */
+const char *
+if_flag_dump (unsigned long flag)
+{
+  int separator = 0;
+  static char logbuf[BUFSIZ];
+
+#define IFF_OUT_LOG(X,STR) \
+  if ((X) && (flag & (X))) \
+    { \
+      if (separator) \
+	strlcat (logbuf, ",", BUFSIZ); \
+      else \
+	separator = 1; \
+      strlcat (logbuf, STR, BUFSIZ); \
+    }
+
+  strlcpy (logbuf, "  <", BUFSIZ);
+  IFF_OUT_LOG (IFF_UP, "UP");
+  IFF_OUT_LOG (IFF_BROADCAST, "BROADCAST");
+  IFF_OUT_LOG (IFF_DEBUG, "DEBUG");
+  IFF_OUT_LOG (IFF_LOOPBACK, "LOOPBACK");
+  IFF_OUT_LOG (IFF_POINTOPOINT, "POINTOPOINT");
+  IFF_OUT_LOG (IFF_NOTRAILERS, "NOTRAILERS");
+  IFF_OUT_LOG (IFF_RUNNING, "RUNNING");
+  IFF_OUT_LOG (IFF_NOARP, "NOARP");
+  IFF_OUT_LOG (IFF_PROMISC, "PROMISC");
+  IFF_OUT_LOG (IFF_ALLMULTI, "ALLMULTI");
+  IFF_OUT_LOG (IFF_OACTIVE, "OACTIVE");
+  IFF_OUT_LOG (IFF_SIMPLEX, "SIMPLEX");
+  IFF_OUT_LOG (IFF_LINK0, "LINK0");
+  IFF_OUT_LOG (IFF_LINK1, "LINK1");
+  IFF_OUT_LOG (IFF_LINK2, "LINK2");
+  IFF_OUT_LOG (IFF_MULTICAST, "MULTICAST");
+
+  strlcat (logbuf, ">", BUFSIZ);
+
+  return logbuf;
+}
+
+/* For debugging */
+void
+if_dump (struct interface *ifp)
+{
+  listnode node;
+
+  zlog_info ("Interface %s index %d metric %d mtu %d %s",
+	     ifp->name, ifp->ifindex, ifp->metric, ifp->mtu, 
+	     if_flag_dump (ifp->flags));
+  
+  for (node = listhead (ifp->connected); node; nextnode (node))
+    ;
+}
+
+/* Interface printing for all interface. */
+void
+if_dump_all ()
+{
+  listnode node;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    if_dump (getdata (node));
+}
+
+DEFUN (interface_desc, 
+       interface_desc_cmd,
+       "description .LINE",
+       "Interface specific description\n"
+       "Characters describing this interface\n")
+{
+  int i;
+  struct interface *ifp;
+  struct buffer *b;
+
+  if (argc == 0)
+    return CMD_SUCCESS;
+
+  ifp = vty->index;
+  if (ifp->desc)
+    XFREE (0, ifp->desc);
+
+  b = buffer_new (1024);
+  for (i = 0; i < argc; i++)
+    {
+      buffer_putstr (b, (u_char *)argv[i]);
+      buffer_putc (b, ' ');
+    }
+  buffer_putc (b, '\0');
+
+  ifp->desc = buffer_getstr (b);
+  buffer_free (b);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_interface_desc, 
+       no_interface_desc_cmd,
+       "no description",
+       NO_STR
+       "Interface specific description\n")
+{
+  struct interface *ifp;
+
+  ifp = vty->index;
+  if (ifp->desc)
+    XFREE (0, ifp->desc);
+  ifp->desc = NULL;
+
+  return CMD_SUCCESS;
+}
+
+
+/* See also wrapper function zebra_interface() in zebra/interface.c */
+DEFUN (interface,
+       interface_cmd,
+       "interface IFNAME",
+       "Select an interface to configure\n"
+       "Interface's name\n")
+{
+  struct interface *ifp;
+
+  ifp = if_lookup_by_name (argv[0]);
+
+  if (ifp == NULL)
+    {
+      ifp = if_create ();
+      strncpy (ifp->name, argv[0], INTERFACE_NAMSIZ);
+    }
+  vty->index = ifp;
+  vty->node = INTERFACE_NODE;
+
+  return CMD_SUCCESS;
+}
+
+/* For debug purpose. */
+DEFUN (show_address,
+       show_address_cmd,
+       "show address",
+       SHOW_STR
+       "address\n")
+{
+  listnode node;
+  listnode node2;
+  struct interface *ifp;
+  struct connected *ifc;
+  struct prefix *p;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+
+      for (node2 = listhead (ifp->connected); node2; nextnode (node2))
+	{
+	  ifc = getdata (node2);
+	  p = ifc->address;
+
+	  if (p->family == AF_INET)
+	    vty_out (vty, "%s/%d%s", inet_ntoa (p->u.prefix4), p->prefixlen,
+		     VTY_NEWLINE);
+	}
+    }
+  return CMD_SUCCESS;
+}
+
+/* Allocate connected structure. */
+struct connected *
+connected_new ()
+{
+  struct connected *new = XMALLOC (MTYPE_CONNECTED, sizeof (struct connected));
+  memset (new, 0, sizeof (struct connected));
+  return new;
+}
+
+/* Free connected structure. */
+void
+connected_free (struct connected *connected)
+{
+  if (connected->address)
+    prefix_free (connected->address);
+
+  if (connected->destination)
+    prefix_free (connected->destination);
+
+  if (connected->label)
+    free (connected->label);
+
+  XFREE (MTYPE_CONNECTED, connected);
+}
+
+/* Print if_addr structure. */
+void
+connected_log (struct connected *connected, char *str)
+{
+  struct prefix *p;
+  struct interface *ifp;
+  char logbuf[BUFSIZ];
+  char buf[BUFSIZ];
+  
+  ifp = connected->ifp;
+  p = connected->address;
+
+  snprintf (logbuf, BUFSIZ, "%s interface %s %s %s/%d ", 
+	    str, ifp->name, prefix_family_str (p),
+	    inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+	    p->prefixlen);
+
+  p = connected->destination;
+  if (p)
+    {
+      strncat (logbuf, inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+	       BUFSIZ - strlen(logbuf));
+    }
+  zlog (NULL, LOG_INFO, logbuf);
+}
+
+/* If two connected address has same prefix return 1. */
+int
+connected_same_prefix (struct prefix *p1, struct prefix *p2)
+{
+  if (p1->family == p2->family)
+    {
+      if (p1->family == AF_INET &&
+	  IPV4_ADDR_SAME (&p1->u.prefix4, &p2->u.prefix4))
+	return 1;
+#ifdef HAVE_IPV6
+      if (p1->family == AF_INET6 &&
+	  IPV6_ADDR_SAME (&p1->u.prefix6, &p2->u.prefix6))
+	return 1;
+#endif /* HAVE_IPV6 */
+    }
+  return 0;
+}
+
+struct connected *
+connected_delete_by_prefix (struct interface *ifp, struct prefix *p)
+{
+  struct listnode *node;
+  struct listnode *next;
+  struct connected *ifc;
+
+  /* In case of same prefix come, replace it with new one. */
+  for (node = listhead (ifp->connected); node; node = next)
+    {
+      ifc = getdata (node);
+      next = node->next;
+
+      if (connected_same_prefix (ifc->address, p))
+	{
+	  listnode_delete (ifp->connected, ifc);
+	  return ifc;
+	}
+    }
+  return NULL;
+}
+
+/* Check the connected information is PtP style or not.  */
+int
+ifc_pointopoint (struct connected *ifc)
+{
+  struct prefix *p;
+  int ptp = 0;
+
+  /* When interface has PtP flag.  */
+  if (if_is_pointopoint (ifc->ifp))
+    return 1;
+
+  /* RFC3021 PtP check.  */
+  p = ifc->address;
+
+  if (p->family == AF_INET)
+    ptp = (p->prefixlen >= IPV4_MAX_PREFIXLEN - 1);
+#ifdef HAVE_IPV6
+  if (p->family == AF_INET6)
+    ptp = (p->prefixlen >= IPV6_MAX_PREFIXLEN - 1);
+#endif /* HAVE_IPV6 */
+
+  return ptp;
+}
+
+#ifndef HAVE_IF_NAMETOINDEX
+unsigned int
+if_nametoindex (const char *name)
+{
+  listnode node;
+  struct interface *ifp;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      if (strcmp (ifp->name, name) == 0)
+	return ifp->ifindex;
+    }
+  return 0;
+}
+#endif
+
+#ifndef HAVE_IF_INDEXTONAME
+char *
+if_indextoname (unsigned int ifindex, char *name)
+{
+  listnode node;
+  struct interface *ifp;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      if (ifp->ifindex == ifindex)
+	{
+	  memcpy (name, ifp->name, IFNAMSIZ);
+	  return ifp->name;
+	}
+    }
+  return NULL;
+}
+#endif
+
+/* Interface looking up by interface's address. */
+
+/* Interface's IPv4 address reverse lookup table. */
+struct route_table *ifaddr_ipv4_table;
+/* struct route_table *ifaddr_ipv6_table; */
+
+void
+ifaddr_ipv4_add (struct in_addr *ifaddr, struct interface *ifp)
+{
+  struct route_node *rn;
+  struct prefix_ipv4 p;
+
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_PREFIXLEN;
+  p.prefix = *ifaddr;
+
+  rn = route_node_get (ifaddr_ipv4_table, (struct prefix *) &p);
+  if (rn)
+    {
+      route_unlock_node (rn);
+      zlog_info ("ifaddr_ipv4_add(): address %s is already added",
+		 inet_ntoa (*ifaddr));
+      return;
+    }
+  rn->info = ifp;
+}
+
+void
+ifaddr_ipv4_delete (struct in_addr *ifaddr, struct interface *ifp)
+{
+  struct route_node *rn;
+  struct prefix_ipv4 p;
+
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_PREFIXLEN;
+  p.prefix = *ifaddr;
+
+  rn = route_node_lookup (ifaddr_ipv4_table, (struct prefix *) &p);
+  if (! rn)
+    {
+      zlog_info ("ifaddr_ipv4_delete(): can't find address %s",
+		 inet_ntoa (*ifaddr));
+      return;
+    }
+  rn->info = NULL;
+  route_unlock_node (rn);
+  route_unlock_node (rn);
+}
+
+/* Lookup interface by interface's IP address or interface index. */
+struct interface *
+ifaddr_ipv4_lookup (struct in_addr *addr, unsigned int ifindex)
+{
+  struct prefix_ipv4 p;
+  struct route_node *rn;
+  struct interface *ifp;
+  listnode node;
+
+  if (addr)
+    {
+      p.family = AF_INET;
+      p.prefixlen = IPV4_MAX_PREFIXLEN;
+      p.prefix = *addr;
+
+      rn = route_node_lookup (ifaddr_ipv4_table, (struct prefix *) &p);
+      if (! rn)
+	return NULL;
+      
+      ifp = rn->info;
+      route_unlock_node (rn);
+      return ifp;
+    }
+  else
+    {
+      for (node = listhead (iflist); node; nextnode (node))
+	{
+	  ifp = getdata (node);
+
+	  if (ifp->ifindex == ifindex)
+	    return ifp;
+	}
+    }
+  return NULL;
+}
+
+/* Initialize interface list. */
+void
+if_init ()
+{
+  iflist = list_new ();
+  ifaddr_ipv4_table = route_table_init ();
+
+  if (iflist)
+    return;
+
+  memset (&if_master, 0, sizeof if_master);
+}
diff --git a/lib/if.h b/lib/if.h
new file mode 100644
index 0000000..3896d18
--- /dev/null
+++ b/lib/if.h
@@ -0,0 +1,222 @@
+/* Interface related header.
+   Copyright (C) 1997, 98, 99 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 _ZEBRA_IF_H
+#define _ZEBRA_IF_H
+
+#include "linklist.h"
+
+/*
+  Interface name length.
+
+   Linux define value in /usr/include/linux/if.h.
+   #define IFNAMSIZ        16
+
+   FreeBSD define value in /usr/include/net/if.h.
+   #define IFNAMSIZ        16
+*/
+
+#define INTERFACE_NAMSIZ      20
+#define INTERFACE_HWADDR_MAX  20
+
+/* Internal If indexes start at 0xFFFFFFFF and go down to 1 greater
+   than this */
+#define IFINDEX_INTERNBASE 0x80000000
+
+#ifdef HAVE_PROC_NET_DEV
+struct if_stats
+{
+  unsigned long rx_packets;   /* total packets received       */
+  unsigned long tx_packets;   /* total packets transmitted    */
+  unsigned long rx_bytes;     /* total bytes received         */
+  unsigned long tx_bytes;     /* total bytes transmitted      */
+  unsigned long rx_errors;    /* bad packets received         */
+  unsigned long tx_errors;    /* packet transmit problems     */
+  unsigned long rx_dropped;   /* no space in linux buffers    */
+  unsigned long tx_dropped;   /* no space available in linux  */
+  unsigned long rx_multicast; /* multicast packets received   */
+  unsigned long rx_compressed;
+  unsigned long tx_compressed;
+  unsigned long collisions;
+
+  /* detailed rx_errors: */
+  unsigned long rx_length_errors;
+  unsigned long rx_over_errors;       /* receiver ring buff overflow  */
+  unsigned long rx_crc_errors;        /* recved pkt with crc error    */
+  unsigned long rx_frame_errors;      /* recv'd frame alignment error */
+  unsigned long rx_fifo_errors;       /* recv'r fifo overrun          */
+  unsigned long rx_missed_errors;     /* receiver missed packet     */
+  /* detailed tx_errors */
+  unsigned long tx_aborted_errors;
+  unsigned long tx_carrier_errors;
+  unsigned long tx_fifo_errors;
+  unsigned long tx_heartbeat_errors;
+  unsigned long tx_window_errors;
+};
+#endif /* HAVE_PROC_NET_DEV */
+
+/* Interface structure */
+struct interface 
+{
+  /* Interface name. */
+  char name[INTERFACE_NAMSIZ + 1];
+
+  /* Interface index. */
+  unsigned int ifindex;
+
+  /* Zebra internal interface status */
+  u_char status;
+#define ZEBRA_INTERFACE_ACTIVE     (1 << 0)
+#define ZEBRA_INTERFACE_SUB        (1 << 1)
+  
+  /* Interface flags. */
+  unsigned long flags;
+
+  /* Interface metric */
+  int metric;
+
+  /* Interface MTU. */
+  int mtu;
+
+  /* Hardware address. */
+#ifdef HAVE_SOCKADDR_DL
+  struct sockaddr_dl sdl;
+#else
+  unsigned short hw_type;
+  u_char hw_addr[INTERFACE_HWADDR_MAX];
+  int hw_addr_len;
+#endif /* HAVE_SOCKADDR_DL */
+
+  /* interface bandwidth, kbits */
+  unsigned int bandwidth;
+  
+  /* description of the interface. */
+  char *desc;			
+
+  /* Distribute list. */
+  void *distribute_in;
+  void *distribute_out;
+
+  /* Connected address list. */
+  list connected;
+
+  /* Daemon specific interface data pointer. */
+  void *info;
+
+  /* Statistics fileds. */
+#ifdef HAVE_PROC_NET_DEV
+  struct if_stats stats;
+#endif /* HAVE_PROC_NET_DEV */  
+#ifdef HAVE_NET_RT_IFLIST
+  struct if_data stats;
+#endif /* HAVE_NET_RT_IFLIST */
+};
+
+/* Connected address structure. */
+struct connected
+{
+  /* Attached interface. */
+  struct interface *ifp;
+
+  /* Flags for configuration. */
+  u_char conf;
+#define ZEBRA_IFC_REAL         (1 << 0)
+#define ZEBRA_IFC_CONFIGURED   (1 << 1)
+
+  /* Flags for connected address. */
+  u_char flags;
+#define ZEBRA_IFA_SECONDARY   (1 << 0)
+
+  /* Address of connected network. */
+  struct prefix *address;
+  struct prefix *destination;
+
+  /* Label for Linux 2.2.X and upper. */
+  char *label;
+};
+
+/* Interface hook sort. */
+#define IF_NEW_HOOK   0
+#define IF_DELETE_HOOK 1
+
+/* There are some interface flags which are only supported by some
+   operating system. */
+
+#ifndef IFF_NOTRAILERS
+#define IFF_NOTRAILERS 0x0
+#endif /* IFF_NOTRAILERS */
+#ifndef IFF_OACTIVE
+#define IFF_OACTIVE 0x0
+#endif /* IFF_OACTIVE */
+#ifndef IFF_SIMPLEX
+#define IFF_SIMPLEX 0x0
+#endif /* IFF_SIMPLEX */
+#ifndef IFF_LINK0
+#define IFF_LINK0 0x0
+#endif /* IFF_LINK0 */
+#ifndef IFF_LINK1
+#define IFF_LINK1 0x0
+#endif /* IFF_LINK1 */
+#ifndef IFF_LINK2
+#define IFF_LINK2 0x0
+#endif /* IFF_LINK2 */
+
+/* Prototypes. */
+struct interface *if_new (void);
+struct interface *if_create (void);
+struct interface *if_lookup_by_index (unsigned int);
+struct interface *if_lookup_by_name (char *);
+struct interface *if_lookup_exact_address (struct in_addr);
+struct interface *if_lookup_address (struct in_addr);
+struct interface *if_get_by_name (char *);
+void if_delete (struct interface *);
+int if_is_up (struct interface *);
+int if_is_loopback (struct interface *);
+int if_is_broadcast (struct interface *);
+int if_is_pointopoint (struct interface *);
+int if_is_multicast (struct interface *);
+void if_add_hook (int, int (*)(struct interface *));
+void if_init ();
+void if_dump_all ();
+char *ifindex2ifname (unsigned int);
+
+/* Connected address functions. */
+struct connected *connected_new ();
+void connected_free (struct connected *);
+void connected_add (struct interface *, struct connected *);
+struct connected  *connected_delete_by_prefix (struct interface *, struct prefix *);
+int ifc_pointopoint (struct connected *);
+
+#ifndef HAVE_IF_NAMETOINDEX
+unsigned int if_nametoindex (const char *);
+#endif
+#ifndef HAVE_IF_INDEXTONAME
+char *if_indextoname (unsigned int, char *);
+#endif
+
+/* Exported variables. */
+extern list iflist;
+extern struct cmd_element interface_desc_cmd;
+extern struct cmd_element no_interface_desc_cmd;
+extern struct cmd_element interface_cmd;
+extern struct cmd_element interface_pseudo_cmd;
+extern struct cmd_element no_interface_pseudo_cmd;
+
+#endif /* _ZEBRA_IF_H */
diff --git a/lib/if_rmap.c b/lib/if_rmap.c
new file mode 100644
index 0000000..d3031fa
--- /dev/null
+++ b/lib/if_rmap.c
@@ -0,0 +1,305 @@
+/* route-map for interface.
+ * Copyright (C) 1999 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.  
+ */
+
+#include <zebra.h>
+
+#include "hash.h"
+#include "command.h"
+#include "memory.h"
+#include "if.h"
+#include "if_rmap.h"
+
+struct hash *ifrmaphash;
+
+/* Hook functions. */
+void (*if_rmap_add_hook) (struct if_rmap *) = NULL;
+void (*if_rmap_delete_hook) (struct if_rmap *) = NULL;
+
+struct if_rmap *
+if_rmap_new ()
+{
+  struct if_rmap *new;
+
+  new = XCALLOC (MTYPE_IF_RMAP, sizeof (struct if_rmap));
+
+  return new;
+}
+
+void
+if_rmap_free (struct if_rmap *if_rmap)
+{
+  if (if_rmap->ifname)
+    free (if_rmap->ifname);
+
+  if (if_rmap->routemap[IF_RMAP_IN])
+    free (if_rmap->routemap[IF_RMAP_IN]);
+  if (if_rmap->routemap[IF_RMAP_OUT])
+    free (if_rmap->routemap[IF_RMAP_OUT]);
+
+  XFREE (MTYPE_IF_RMAP, if_rmap);
+}
+
+struct if_rmap *
+if_rmap_lookup (char *ifname)
+{
+  struct if_rmap key;
+  struct if_rmap *if_rmap;
+
+  key.ifname = ifname;
+
+  if_rmap = hash_lookup (ifrmaphash, &key);
+  
+  return if_rmap;
+}
+
+void
+if_rmap_hook_add (void (*func) (struct if_rmap *))
+{
+  if_rmap_add_hook = func;
+}
+
+void
+if_rmap_hook_delete (void (*func) (struct if_rmap *))
+{
+  if_rmap_delete_hook = func;
+}
+
+void *
+if_rmap_hash_alloc (struct if_rmap *arg)
+{
+  struct if_rmap *if_rmap;
+
+  if_rmap = if_rmap_new ();
+  if_rmap->ifname = strdup (arg->ifname);
+
+  return if_rmap;
+}
+
+struct if_rmap *
+if_rmap_get (char *ifname)
+{
+  struct if_rmap key;
+
+  key.ifname = ifname;
+
+  return (struct if_rmap *) hash_get (ifrmaphash, &key, if_rmap_hash_alloc);
+}
+
+unsigned int
+if_rmap_hash_make (struct if_rmap *if_rmap)
+{
+  unsigned int key;
+  int i;
+
+  key = 0;
+  for (i = 0; i < strlen (if_rmap->ifname); i++)
+    key += if_rmap->ifname[i];
+
+  return key;
+}
+
+int
+if_rmap_hash_cmp (struct if_rmap *if_rmap1, struct if_rmap *if_rmap2)
+{
+  if (strcmp (if_rmap1->ifname, if_rmap2->ifname) == 0)
+    return 1;
+  return 0;
+}
+
+struct if_rmap *
+if_rmap_set (char *ifname, enum if_rmap_type type, char *routemap_name)
+{
+  struct if_rmap *if_rmap;
+
+  if_rmap = if_rmap_get (ifname);
+
+  if (type == IF_RMAP_IN)
+    {
+      if (if_rmap->routemap[IF_RMAP_IN])
+	free (if_rmap->routemap[IF_RMAP_IN]);
+      if_rmap->routemap[IF_RMAP_IN] = strdup (routemap_name);
+    }
+  if (type == IF_RMAP_OUT)
+    {
+      if (if_rmap->routemap[IF_RMAP_OUT])
+	free (if_rmap->routemap[IF_RMAP_OUT]);
+      if_rmap->routemap[IF_RMAP_OUT] = strdup (routemap_name);
+    }
+
+  if (if_rmap_add_hook)
+    (*if_rmap_add_hook) (if_rmap);
+  
+  return if_rmap;
+}
+
+int
+if_rmap_unset (char *ifname, enum if_rmap_type type, char *routemap_name)
+{
+  struct if_rmap *if_rmap;
+
+  if_rmap = if_rmap_lookup (ifname);
+  if (!if_rmap)
+    return 0;
+
+  if (type == IF_RMAP_IN)
+    {
+      if (!if_rmap->routemap[IF_RMAP_IN])
+	return 0;
+      if (strcmp (if_rmap->routemap[IF_RMAP_IN], routemap_name) != 0)
+	return 0;
+
+      free (if_rmap->routemap[IF_RMAP_IN]);
+      if_rmap->routemap[IF_RMAP_IN] = NULL;      
+    }
+
+  if (type == IF_RMAP_OUT)
+    {
+      if (!if_rmap->routemap[IF_RMAP_OUT])
+	return 0;
+      if (strcmp (if_rmap->routemap[IF_RMAP_OUT], routemap_name) != 0)
+	return 0;
+
+      free (if_rmap->routemap[IF_RMAP_OUT]);
+      if_rmap->routemap[IF_RMAP_OUT] = NULL;      
+    }
+
+  if (if_rmap_delete_hook)
+    (*if_rmap_delete_hook) (if_rmap);
+
+  if (if_rmap->routemap[IF_RMAP_IN] == NULL &&
+      if_rmap->routemap[IF_RMAP_OUT] == NULL)
+    {
+      hash_release (ifrmaphash, if_rmap);
+      if_rmap_free (if_rmap);
+    }
+
+  return 1;
+}
+
+DEFUN (if_rmap,
+       if_rmap_cmd,
+       "route-map RMAP_NAME (in|out) IFNAME",
+       "Route map set\n"
+       "Route map name\n"
+       "Route map set for input filtering\n"
+       "Route map set for output filtering\n"
+       "Route map interface name\n")
+{
+  enum if_rmap_type type;
+  struct if_rmap *if_rmap;
+
+  if (strncmp (argv[1], "i", 1) == 0)
+    type = IF_RMAP_IN;
+  else if (strncmp (argv[1], "o", 1) == 0)
+    type = IF_RMAP_OUT;
+  else
+    {
+      vty_out (vty, "route-map direction must be [in|out]%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if_rmap = if_rmap_set (argv[2], type, argv[0]);
+
+  return CMD_SUCCESS;
+}       
+
+DEFUN (no_if_rmap,
+       no_if_rmap_cmd,
+       "no route-map ROUTEMAP_NAME (in|out) IFNAME",
+       NO_STR
+       "Route map unset\n"
+       "Route map name\n"
+       "Route map for input filtering\n"
+       "Route map for output filtering\n"
+       "Route map interface name\n")
+{
+  int ret;
+  enum if_rmap_type type;
+
+  if (strncmp (argv[1], "i", 1) == 0)
+    type = IF_RMAP_IN;
+  else if (strncmp (argv[1], "o", 1) == 0)
+    type = IF_RMAP_OUT;
+  else
+    {
+      vty_out (vty, "route-map direction must be [in|out]%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = if_rmap_unset (argv[2], type, argv[0]);
+  if (! ret)
+    {
+      vty_out (vty, "route-map doesn't exist%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}       
+
+/* Configuration write function. */
+int
+config_write_if_rmap (struct vty *vty)
+{
+  int i;
+  struct hash_backet *mp;
+  int write = 0;
+
+  for (i = 0; i < ifrmaphash->size; i++)
+    for (mp = ifrmaphash->index[i]; mp; mp = mp->next)
+      {
+	struct if_rmap *if_rmap;
+
+	if_rmap = mp->data;
+
+	if (if_rmap->routemap[IF_RMAP_IN])
+	  {
+	    vty_out (vty, " route-map %s in %s%s", 
+		     if_rmap->routemap[IF_RMAP_IN],
+		     if_rmap->ifname,
+		     VTY_NEWLINE);
+	    write++;
+	  }
+
+	if (if_rmap->routemap[IF_RMAP_OUT])
+	  {
+	    vty_out (vty, " route-map %s out %s%s", 
+		     if_rmap->routemap[IF_RMAP_OUT],
+		     if_rmap->ifname,
+		     VTY_NEWLINE);
+	    write++;
+	  }
+      }
+  return write;
+}
+
+void
+if_rmap_reset ()
+{
+  hash_clean (ifrmaphash, (void (*) (void *)) if_rmap_free);
+}
+
+void
+if_rmap_init (int node)
+{
+  ifrmaphash = hash_create (if_rmap_hash_make, if_rmap_hash_cmp);
+
+  install_element (node, &if_rmap_cmd);
+  install_element (node, &no_if_rmap_cmd);
+}
diff --git a/lib/if_rmap.h b/lib/if_rmap.h
new file mode 100644
index 0000000..a9355ab
--- /dev/null
+++ b/lib/if_rmap.h
@@ -0,0 +1,47 @@
+/* route-map for interface.
+ * Copyright (C) 1999 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 _ZEBRA_IF_RMAP_H
+#define _ZEBRA_IF_RMAP_H
+
+enum if_rmap_type
+{
+  IF_RMAP_IN,
+  IF_RMAP_OUT,
+  IF_RMAP_MAX
+};
+
+struct if_rmap
+{
+  /* Name of the interface. */
+  char *ifname;
+
+  char *routemap[IF_RMAP_MAX];
+};
+
+void if_rmap_init (int);
+void if_rmap_reset (void);
+void if_rmap_hook_add (void (*) (struct if_rmap *));
+void if_rmap_hook_delete (void (*) (struct if_rmap *));
+struct if_rmap *if_rmap_lookup (char *);
+int config_write_if_rmap (struct vty *);
+
+#endif /* _ZEBRA_IF_RMAP_H */
diff --git a/lib/keychain.c b/lib/keychain.c
new file mode 100644
index 0000000..dbf431a
--- /dev/null
+++ b/lib/keychain.c
@@ -0,0 +1,1001 @@
+/* key-chain for authentication.
+   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.  */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "memory.h"
+#include "linklist.h"
+#include "keychain.h"
+
+/* Master list of key chain. */
+struct list *keychain_list;
+
+struct keychain *
+keychain_new ()
+{
+  struct keychain *new;
+  new = XMALLOC (MTYPE_KEYCHAIN, sizeof (struct keychain));
+  memset (new, 0, sizeof (struct keychain));
+  return new;
+}
+
+void
+keychain_free (struct keychain *keychain)
+{
+  XFREE (MTYPE_KEYCHAIN, keychain);
+}
+
+struct key *
+key_new ()
+{
+  struct key *new;
+  new = XMALLOC (MTYPE_KEY, sizeof (struct key));
+  memset (new, 0, sizeof (struct key));
+  return new;
+}
+
+void
+key_free (struct key *key)
+{
+  XFREE (MTYPE_KEY, key);
+}
+
+struct keychain *
+keychain_lookup (char *name)
+{
+  struct listnode *nn;
+  struct keychain *keychain;
+
+  if (name == NULL)
+    return NULL;
+
+  LIST_LOOP (keychain_list, keychain, nn)
+    {
+      if (strcmp (keychain->name, name) == 0)
+	return keychain;
+    }
+  return NULL;
+}
+
+int
+key_cmp_func (struct key *k1, struct key *k2)
+{
+  if (k1->index > k2->index)
+    return 1;
+  if (k1->index < k2->index)
+    return -1;
+  return 0;
+}
+
+void
+key_delete_func (struct key *key)
+{
+  if (key->string)
+    free (key->string);
+  key_free (key);
+}
+
+struct keychain *
+keychain_get (char *name)
+{
+  struct keychain *keychain;
+
+  keychain = keychain_lookup (name);
+
+  if (keychain)
+    return keychain;
+
+  keychain = keychain_new ();
+  keychain->name = strdup (name);
+  keychain->key = list_new ();
+  keychain->key->cmp = (int (*)(void *, void *)) key_cmp_func;
+  keychain->key->del = (void (*)(void *)) key_delete_func;
+  listnode_add (keychain_list, keychain);
+
+  return keychain;
+}
+
+void
+keychain_delete (struct keychain *keychain)
+{
+  if (keychain->name)
+    free (keychain->name);
+
+  list_delete (keychain->key);
+  listnode_delete (keychain_list, keychain);
+  keychain_free (keychain);
+}
+
+struct key *
+key_lookup (struct keychain *keychain, u_int32_t index)
+{
+  struct listnode *nn;
+  struct key *key;
+
+  LIST_LOOP (keychain->key, key, nn)
+    {
+      if (key->index == index)
+	return key;
+    }
+  return NULL;
+}
+
+struct key *
+key_lookup_for_accept (struct keychain *keychain, u_int32_t index)
+{
+  struct listnode *nn;
+  struct key *key;
+  time_t now;
+
+  now = time (NULL);
+
+  LIST_LOOP (keychain->key, key, nn)
+    {
+      if (key->index >= index)
+	{
+	  if (key->accept.start == 0)
+	    return key;
+
+	  if (key->accept.start <= now)
+	    if (key->accept.end >= now || key->accept.end == -1)
+	      return key;
+	}
+    }
+  return NULL;
+}
+
+struct key *
+key_match_for_accept (struct keychain *keychain, char *auth_str)
+{
+  struct listnode *nn;
+  struct key *key;
+  time_t now;
+
+  now = time (NULL);
+
+  LIST_LOOP (keychain->key, key, nn)
+    {
+      if (key->accept.start == 0 ||
+	  (key->accept.start <= now &&
+	   (key->accept.end >= now || key->accept.end == -1)))
+	if (strncmp (key->string, auth_str, 16) == 0)
+	  return key;
+    }
+  return NULL;
+}
+
+struct key *
+key_lookup_for_send (struct keychain *keychain)
+{
+  struct listnode *nn;
+  struct key *key;
+  time_t now;
+
+  now = time (NULL);
+
+  LIST_LOOP (keychain->key, key, nn)
+    {
+      if (key->send.start == 0)
+	return key;
+
+      if (key->send.start <= now)
+	if (key->send.end >= now || key->send.end == -1)
+	  return key;
+    }
+  return NULL;
+}
+
+struct key *
+key_get (struct keychain *keychain, u_int32_t index)
+{
+  struct key *key;
+
+  key = key_lookup (keychain, index);
+
+  if (key)
+    return key;
+
+  key = key_new ();
+  key->index = index;
+  listnode_add_sort (keychain->key, key);
+
+  return key;
+}
+
+void
+key_delete (struct keychain *keychain, struct key *key)
+{
+  listnode_delete (keychain->key, key);
+
+  if (key->string)
+    free (key->string);
+  key_free (key);
+}
+
+DEFUN (key_chain,
+       key_chain_cmd,
+       "key chain WORD",
+       "Authentication key management\n"
+       "Key-chain management\n"
+       "Key-chain name\n")
+{
+  struct keychain *keychain;
+
+  keychain = keychain_get (argv[0]);
+  vty->index = keychain;
+  vty->node = KEYCHAIN_NODE;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_key_chain,
+       no_key_chain_cmd,
+       "no key chain WORD",
+       NO_STR
+       "Authentication key management\n"
+       "Key-chain management\n"
+       "Key-chain name\n")
+{
+  struct keychain *keychain;
+
+  keychain = keychain_lookup (argv[0]);
+
+  if (! keychain)
+    {
+      vty_out (vty, "Can't find keychain %s%s", argv[0], VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  keychain_delete (keychain);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (key,
+       key_cmd,
+       "key <0-2147483647>",
+       "Configure a key\n"
+       "Key identifier number\n")
+{
+  struct keychain *keychain;
+  struct key *key;
+  u_int32_t index;
+  char *endptr = NULL;
+
+  keychain = vty->index;
+
+  index = strtoul (argv[0], &endptr, 10);
+  if (index == ULONG_MAX || *endptr != '\0')
+    {
+      vty_out (vty, "Key identifier number error%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  key = key_get (keychain, index);
+  vty->index_sub = key;
+  vty->node = KEYCHAIN_KEY_NODE;
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_key,
+       no_key_cmd,
+       "no key <0-2147483647>",
+       NO_STR
+       "Delete a key\n"
+       "Key identifier number\n")
+{
+  struct keychain *keychain;
+  struct key *key;
+  u_int32_t index;
+  char *endptr = NULL;
+  
+  keychain = vty->index;
+
+  index = strtoul (argv[0], &endptr, 10);
+  if (index == ULONG_MAX || *endptr != '\0')
+    {
+      vty_out (vty, "Key identifier number error%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  key = key_lookup (keychain, index);
+  if (! key)
+    {
+      vty_out (vty, "Can't find key %d%s", index, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  key_delete (keychain, key);
+
+  vty->node = KEYCHAIN_NODE;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (key_string,
+       key_string_cmd,
+       "key-string LINE",
+       "Set key string\n"
+       "The key\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  if (key->string)
+    free (key->string);
+  key->string = strdup (argv[0]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_key_string,
+       no_key_string_cmd,
+       "no key-string [LINE]",
+       NO_STR
+       "Unset key string\n"
+       "The key\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  if (key->string)
+    {
+      free (key->string);
+      key->string = NULL;
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* Convert HH:MM:SS MON DAY YEAR to time_t value.  -1 is returned when
+   given string is malformed. */
+time_t 
+key_str2time(char *time_str, char *day_str, char *month_str, char *year_str)
+{
+  int i = 0;
+  char *colon;
+  struct tm tm;
+  time_t time;
+  int sec, min, hour;
+  int day, month, year;
+  char *endptr = NULL;
+
+  char *month_name[] = 
+  {
+    "January",
+    "February",
+    "March",
+    "April",
+    "May",
+    "June",
+    "July",
+    "August",
+    "September",
+    "October",
+    "November",
+    "December",
+    NULL
+  };
+
+  /* Check hour field of time_str. */
+  colon = strchr (time_str, ':');
+  if (colon == NULL)
+    return -1;
+  *colon = '\0';
+
+  /* Hour must be between 0 and 23. */
+  hour = strtoul (time_str, &endptr, 10);
+  if (hour == ULONG_MAX || *endptr != '\0' || hour < 0 || hour > 23)
+    return -1;
+
+  /* Check min field of time_str. */
+  time_str = colon + 1;
+  colon = strchr (time_str, ':');
+  if (*time_str == '\0' || colon == NULL)
+    return -1;
+  *colon = '\0';
+
+  /* Min must be between 0 and 59. */
+  min = strtoul (time_str, &endptr, 10);
+  if (min == ULONG_MAX || *endptr != '\0' || min < 0 || min > 59)
+    return -1;
+
+  /* Check sec field of time_str. */
+  time_str = colon + 1;
+  if (*time_str == '\0')
+    return -1;
+  
+  /* Sec must be between 0 and 59. */
+  sec = strtoul (time_str, &endptr, 10);
+  if (sec == ULONG_MAX || *endptr != '\0' || sec < 0 || sec > 59)
+    return -1;
+  
+  /* Check day_str.  Day must be <1-31>. */
+  day = strtoul (day_str, &endptr, 10);
+  if (day == ULONG_MAX || *endptr != '\0' || day < 0 || day > 31)
+    return -1;
+
+  /* Check month_str.  Month must match month_name. */
+  month = 0;
+  if (strlen (month_str) >= 3)
+    for (i = 0; month_name[i]; i++)
+      if (strncmp (month_str, month_name[i], strlen (month_str)) == 0)
+	{
+	  month = i;
+	  break;
+	}
+  if (! month_name[i])
+    return -1;
+
+  /* Check year_str.  Year must be <1993-2035>. */
+  year = strtoul (year_str, &endptr, 10);
+  if (year == ULONG_MAX || *endptr != '\0' || year < 1993 || year > 2035)
+    return -1;
+  
+  memset (&tm, 0, sizeof (struct tm));
+  tm.tm_sec = sec;
+  tm.tm_min = min;
+  tm.tm_hour = hour;
+  tm.tm_mon = month;
+  tm.tm_mday = day;
+  tm.tm_year = year - 1900;
+    
+  time = mktime (&tm);
+
+  return time;
+}
+
+int
+key_lifetime_set (struct vty *vty, struct key_range *krange, char *stime_str,
+		  char *sday_str, char *smonth_str, char *syear_str,
+		  char *etime_str, char *eday_str, char *emonth_str,
+		  char *eyear_str)
+{
+  time_t time_start;
+  time_t time_end;
+    
+  time_start = key_str2time (stime_str, sday_str, smonth_str, syear_str);
+  if (time_start < 0)
+    {
+      vty_out (vty, "Malformed time value%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  time_end = key_str2time (etime_str, eday_str, emonth_str, eyear_str);
+
+  if (time_end < 0)
+    {
+      vty_out (vty, "Malformed time value%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (time_end <= time_start)
+    {
+      vty_out (vty, "Expire time is not later than start time%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  krange->start = time_start;
+  krange->end = time_end;
+
+  return CMD_SUCCESS;
+}
+
+int
+key_lifetime_duration_set (struct vty *vty, struct key_range *krange,
+			   char *stime_str, char *sday_str, char *smonth_str,
+			   char *syear_str, char *duration_str)
+{
+  time_t time_start;
+  u_int32_t duration;
+  char *endptr = NULL;
+    
+  time_start = key_str2time (stime_str, sday_str, smonth_str, syear_str);
+  if (time_start < 0)
+    {
+      vty_out (vty, "Malformed time value%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  krange->start = time_start;
+
+  duration = strtoul (duration_str, &endptr, 10);
+  if (duration == ULONG_MAX || *endptr != '\0')
+    {
+      vty_out (vty, "Malformed duration%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  krange->duration = 1;
+  krange->end = time_start + duration;
+
+  return CMD_SUCCESS;
+}
+
+int
+key_lifetime_infinite_set (struct vty *vty, struct key_range *krange,
+			   char *stime_str, char *sday_str, char *smonth_str,
+			   char *syear_str)
+{
+  time_t time_start;
+    
+  time_start = key_str2time (stime_str, sday_str, smonth_str, syear_str);
+  if (time_start < 0)
+    {
+      vty_out (vty, "Malformed time value%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  krange->start = time_start;
+
+  krange->end = -1;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (accept_lifetime_day_month_day_month,
+       accept_lifetime_day_month_day_month_cmd,
+       "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>",
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Day of th month to expire\n"
+       "Month of the year to expire\n"
+       "Year to expire\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_set (vty, &key->accept, argv[0], argv[1], argv[2],
+			   argv[3], argv[4], argv[5], argv[6], argv[7]);
+}
+
+DEFUN (accept_lifetime_day_month_month_day,
+       accept_lifetime_day_month_month_day_cmd,
+       "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>",
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Month of the year to expire\n"
+       "Day of th month to expire\n"
+       "Year to expire\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_set (vty, &key->accept, argv[0], argv[1], argv[2],
+			   argv[3], argv[4], argv[6], argv[5], argv[7]);
+}
+
+DEFUN (accept_lifetime_month_day_day_month,
+       accept_lifetime_month_day_day_month_cmd,
+       "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>",
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Day of th month to expire\n"
+       "Month of the year to expire\n"
+       "Year to expire\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_set (vty, &key->accept, argv[0], argv[2], argv[1],
+			   argv[3], argv[4], argv[5], argv[6], argv[7]);
+}
+
+DEFUN (accept_lifetime_month_day_month_day,
+       accept_lifetime_month_day_month_day_cmd,
+       "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>",
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Month of the year to expire\n"
+       "Day of th month to expire\n"
+       "Year to expire\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_set (vty, &key->accept, argv[0], argv[2], argv[1],
+			   argv[3], argv[4], argv[6], argv[5], argv[7]);
+}
+
+DEFUN (accept_lifetime_infinite_day_month,
+       accept_lifetime_infinite_day_month_cmd,
+       "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> infinite",
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Never expires")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_infinite_set (vty, &key->accept, argv[0], argv[1],
+				    argv[2], argv[3]);
+}
+
+DEFUN (accept_lifetime_infinite_month_day,
+       accept_lifetime_infinite_month_day_cmd,
+       "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> infinite",
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Never expires")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_infinite_set (vty, &key->accept, argv[0], argv[2],
+				    argv[1], argv[3]);
+}
+
+DEFUN (accept_lifetime_duration_day_month,
+       accept_lifetime_duration_day_month_cmd,
+       "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> duration <1-2147483646>",
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Duration of the key\n"
+       "Duration seconds\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_duration_set (vty, &key->accept, argv[0], argv[1],
+				    argv[2], argv[3], argv[4]);
+}
+
+DEFUN (accept_lifetime_duration_month_day,
+       accept_lifetime_duration_month_day_cmd,
+       "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> duration <1-2147483646>",
+       "Set accept lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Duration of the key\n"
+       "Duration seconds\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_duration_set (vty, &key->accept, argv[0], argv[2],
+				    argv[1], argv[3], argv[4]);
+}
+
+DEFUN (send_lifetime_day_month_day_month,
+       send_lifetime_day_month_day_month_cmd,
+       "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>",
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Day of th month to expire\n"
+       "Month of the year to expire\n"
+       "Year to expire\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_set (vty, &key->send, argv[0], argv[1], argv[2], argv[3],
+			   argv[4], argv[5], argv[6], argv[7]);
+}
+
+DEFUN (send_lifetime_day_month_month_day,
+       send_lifetime_day_month_month_day_cmd,
+       "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>",
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Month of the year to expire\n"
+       "Day of th month to expire\n"
+       "Year to expire\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_set (vty, &key->send, argv[0], argv[1], argv[2], argv[3],
+			   argv[4], argv[6], argv[5], argv[7]);
+}
+
+DEFUN (send_lifetime_month_day_day_month,
+       send_lifetime_month_day_day_month_cmd,
+       "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>",
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Day of th month to expire\n"
+       "Month of the year to expire\n"
+       "Year to expire\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_set (vty, &key->send, argv[0], argv[2], argv[1], argv[3],
+			   argv[4], argv[5], argv[6], argv[7]);
+}
+
+DEFUN (send_lifetime_month_day_month_day,
+       send_lifetime_month_day_month_day_cmd,
+       "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>",
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Time to expire\n"
+       "Month of the year to expire\n"
+       "Day of th month to expire\n"
+       "Year to expire\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_set (vty, &key->send, argv[0], argv[2], argv[1], argv[3],
+			   argv[4], argv[6], argv[5], argv[7]);
+}
+
+DEFUN (send_lifetime_infinite_day_month,
+       send_lifetime_infinite_day_month_cmd,
+       "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> infinite",
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Never expires")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_infinite_set (vty, &key->send, argv[0], argv[1], argv[2],
+				    argv[3]);
+}
+
+DEFUN (send_lifetime_infinite_month_day,
+       send_lifetime_infinite_month_day_cmd,
+       "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> infinite",
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Never expires")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_infinite_set (vty, &key->send, argv[0], argv[2], argv[1],
+				    argv[3]);
+}
+
+DEFUN (send_lifetime_duration_day_month,
+       send_lifetime_duration_day_month_cmd,
+       "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> duration <1-2147483646>",
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Day of th month to start\n"
+       "Month of the year to start\n"
+       "Year to start\n"
+       "Duration of the key\n"
+       "Duration seconds\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_duration_set (vty, &key->send, argv[0], argv[1], argv[2],
+				    argv[3], argv[4]);
+}
+
+DEFUN (send_lifetime_duration_month_day,
+       send_lifetime_duration_month_day_cmd,
+       "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> duration <1-2147483646>",
+       "Set send lifetime of the key\n"
+       "Time to start\n"
+       "Month of the year to start\n"
+       "Day of th month to start\n"
+       "Year to start\n"
+       "Duration of the key\n"
+       "Duration seconds\n")
+{
+  struct key *key;
+
+  key = vty->index_sub;
+
+  return key_lifetime_duration_set (vty, &key->send, argv[0], argv[2], argv[1],
+				    argv[3], argv[4]);
+}
+
+struct cmd_node keychain_node =
+{
+  KEYCHAIN_NODE,
+  "%s(config-keychain)# ",
+  1
+};
+
+struct cmd_node keychain_key_node =
+{
+  KEYCHAIN_KEY_NODE,
+  "%s(config-keychain-key)# ",
+  1
+};
+
+int
+keychain_strftime (char *buf, int bufsiz, time_t *time)
+{
+  struct tm *tm;
+  size_t len;
+
+  tm = localtime (time);
+
+  len = strftime (buf, bufsiz, "%T %b %d %Y", tm);
+
+  return len;
+}
+
+int
+keychain_config_write (struct vty *vty)
+{
+  struct keychain *keychain;
+  struct key *key;
+  struct listnode *nn;
+  struct listnode *nm;
+  char buf[BUFSIZ];
+
+  LIST_LOOP (keychain_list, keychain, nn)
+    {
+      vty_out (vty, "key chain %s%s", keychain->name, VTY_NEWLINE);
+      
+      LIST_LOOP (keychain->key, key, nm)
+	{
+	  vty_out (vty, " key %d%s", key->index, VTY_NEWLINE);
+
+	  if (key->string)
+	    vty_out (vty, "  key-string %s%s", key->string, VTY_NEWLINE);
+
+	  if (key->accept.start)
+	    {
+	      keychain_strftime (buf, BUFSIZ, &key->accept.start);
+	      vty_out (vty, "  accept-lifetime %s", buf);
+
+	      if (key->accept.end == -1)
+		vty_out (vty, " infinite");
+	      else if (key->accept.duration)
+		vty_out (vty, " duration %ld",
+			 key->accept.end - key->accept.start);
+	      else
+		{
+		  keychain_strftime (buf, BUFSIZ, &key->accept.end);
+		  vty_out (vty, " %s", buf);
+		}
+	      vty_out (vty, "%s", VTY_NEWLINE);
+	    }
+
+	  if (key->send.start)
+	    {
+	      keychain_strftime (buf, BUFSIZ, &key->send.start);
+	      vty_out (vty, "  send-lifetime %s", buf);
+
+	      if (key->send.end == -1)
+		vty_out (vty, " infinite");
+	      else if (key->send.duration)
+		vty_out (vty, " duration %ld", key->send.end - key->send.start);
+	      else
+		{
+		  keychain_strftime (buf, BUFSIZ, &key->send.end);
+		  vty_out (vty, " %s", buf);
+		}
+	      vty_out (vty, "%s", VTY_NEWLINE);
+	    }
+	}
+      vty_out (vty, "!%s", VTY_NEWLINE);
+    }
+
+  return 0;
+}
+
+void
+keychain_init ()
+{
+  keychain_list = list_new ();
+
+  install_node (&keychain_node, keychain_config_write);
+  install_node (&keychain_key_node, NULL);
+
+  install_default (KEYCHAIN_NODE);
+  install_default (KEYCHAIN_KEY_NODE);
+
+  install_element (CONFIG_NODE, &key_chain_cmd);
+  install_element (CONFIG_NODE, &no_key_chain_cmd);
+  install_element (KEYCHAIN_NODE, &key_cmd);
+  install_element (KEYCHAIN_NODE, &no_key_cmd);
+
+  install_element (KEYCHAIN_NODE, &key_chain_cmd);
+  install_element (KEYCHAIN_NODE, &no_key_chain_cmd);
+
+  install_element (KEYCHAIN_KEY_NODE, &key_string_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &no_key_string_cmd);
+
+  install_element (KEYCHAIN_KEY_NODE, &key_chain_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &no_key_chain_cmd);
+
+  install_element (KEYCHAIN_KEY_NODE, &key_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &no_key_cmd);
+
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_day_month_day_month_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_day_month_month_day_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_month_day_day_month_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_month_day_month_day_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_infinite_day_month_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_infinite_month_day_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_duration_day_month_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_duration_month_day_cmd);
+
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_day_month_day_month_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_day_month_month_day_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_month_day_day_month_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_month_day_month_day_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_infinite_day_month_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_infinite_month_day_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_duration_day_month_cmd);
+  install_element (KEYCHAIN_KEY_NODE, &send_lifetime_duration_month_day_cmd);
+}
diff --git a/lib/keychain.h b/lib/keychain.h
new file mode 100644
index 0000000..0cfa3d5
--- /dev/null
+++ b/lib/keychain.h
@@ -0,0 +1,56 @@
+/* key-chain for authentication.
+ * 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 _ZEBRA_KEYCHAIN_H
+#define _ZEBRA_KEYCHAIN_H
+
+struct keychain
+{
+  char *name;
+
+  struct list *key;
+};
+
+struct key_range
+{
+  time_t start;
+  time_t end;
+
+  u_char duration;
+};
+
+struct key
+{
+  u_int32_t index;
+
+  char *string;
+
+  struct key_range send;
+  struct key_range accept;
+};
+
+void keychain_init ();
+struct keychain *keychain_lookup (char *);
+struct key *key_lookup_for_accept (struct keychain *, u_int32_t);
+struct key *key_match_for_accept (struct keychain *, char *);
+struct key *key_lookup_for_send (struct keychain *);
+
+#endif /* _ZEBRA_KEYCHAIN_H */
diff --git a/lib/linklist.c b/lib/linklist.c
new file mode 100644
index 0000000..5a2b696
--- /dev/null
+++ b/lib/linklist.c
@@ -0,0 +1,312 @@
+/* Generic linked list routine.
+ * Copyright (C) 1997, 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.
+ */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "memory.h"
+
+/* Allocate new list. */
+struct list *
+list_new ()
+{
+  struct list *new;
+
+  new = XMALLOC (MTYPE_LINK_LIST, sizeof (struct list));
+  memset (new, 0, sizeof (struct list));
+  return new;
+}
+
+/* Free list. */
+void
+list_free (struct list *l)
+{
+  XFREE (MTYPE_LINK_LIST, l);
+}
+
+/* Allocate new listnode.  Internal use only. */
+static struct listnode *
+listnode_new ()
+{
+  struct listnode *node;
+
+  node = XMALLOC (MTYPE_LINK_NODE, sizeof (struct listnode));
+  memset (node, 0, sizeof (struct listnode));
+  return node;
+}
+
+/* Free listnode. */
+static void
+listnode_free (struct listnode *node)
+{
+  XFREE (MTYPE_LINK_NODE, node);
+}
+
+/* Add new data to the list. */
+void
+listnode_add (struct list *list, void *val)
+{
+  struct listnode *node;
+
+  node = listnode_new ();
+
+  node->prev = list->tail;
+  node->data = val;
+
+  if (list->head == NULL)
+    list->head = node;
+  else
+    list->tail->next = node;
+  list->tail = node;
+
+  list->count++;
+}
+
+/* Add new node with sort function. */
+void
+listnode_add_sort (struct list *list, void *val)
+{
+  struct listnode *n;
+  struct listnode *new;
+
+  new = listnode_new ();
+  new->data = val;
+
+  if (list->cmp)
+    {
+      for (n = list->head; n; n = n->next)
+	{
+	  if ((*list->cmp) (val, n->data) < 0)
+	    {	    
+	      new->next = n;
+	      new->prev = n->prev;
+
+	      if (n->prev)
+		n->prev->next = new;
+	      else
+		list->head = new;
+	      n->prev = new;
+	      list->count++;
+	      return;
+	    }
+	}
+    }
+
+  new->prev = list->tail;
+
+  if (list->tail)
+    list->tail->next = new;
+  else
+    list->head = new;
+
+  list->tail = new;
+  list->count++;
+}
+
+void
+listnode_add_after (struct list *list, struct listnode *pp, void *val)
+{
+  struct listnode *nn;
+
+  nn = listnode_new ();
+  nn->data = val;
+
+  if (pp == NULL)
+    {
+      if (list->head)
+	list->head->prev = nn;
+      else
+	list->tail = nn;
+
+      nn->next = list->head;
+      nn->prev = pp;
+
+      list->head = nn;
+    }
+  else
+    {
+      if (pp->next)
+	pp->next->prev = nn;
+      else
+	list->tail = nn;
+
+      nn->next = pp->next;
+      nn->prev = pp;
+
+      pp->next = nn;
+    }
+}
+
+
+/* Delete specific date pointer from the list. */
+void
+listnode_delete (struct list *list, void *val)
+{
+  struct listnode *node;
+
+  for (node = list->head; node; node = node->next)
+    {
+      if (node->data == val)
+	{
+	  if (node->prev)
+	    node->prev->next = node->next;
+	  else
+	    list->head = node->next;
+
+	  if (node->next)
+	    node->next->prev = node->prev;
+	  else
+	    list->tail = node->prev;
+
+	  list->count--;
+	  listnode_free (node);
+	  return;
+	}
+    }
+}
+
+/* Return first node's data if it is there.  */
+void *
+listnode_head (struct list *list)
+{
+  struct listnode *node;
+
+  node = list->head;
+
+  if (node)
+    return node->data;
+  return NULL;
+}
+
+/* Delete all listnode from the list. */
+void
+list_delete_all_node (struct list *list)
+{
+  struct listnode *node;
+  struct listnode *next;
+
+  for (node = list->head; node; node = next)
+    {
+      next = node->next;
+      if (list->del)
+	(*list->del) (node->data);
+      listnode_free (node);
+    }
+  list->head = list->tail = NULL;
+  list->count = 0;
+}
+
+/* Delete all listnode then free list itself. */
+void
+list_delete (struct list *list)
+{
+  struct listnode *node;
+  struct listnode *next;
+
+  for (node = list->head; node; node = next)
+    {
+      next = node->next;
+      if (list->del)
+	(*list->del) (node->data);
+      listnode_free (node);
+    }
+  list_free (list);
+}
+
+/* Lookup the node which has given data. */
+struct listnode *
+listnode_lookup (struct list *list, void *data)
+{
+  listnode node;
+
+  for (node = list->head; node; nextnode (node))
+    if (data == getdata (node))
+      return node;
+  return NULL;
+}
+
+/* Delete the node from list.  For ospfd and ospf6d. */
+void
+list_delete_node (list list, listnode node)
+{
+  if (node->prev)
+    node->prev->next = node->next;
+  else
+    list->head = node->next;
+  if (node->next)
+    node->next->prev = node->prev;
+  else
+    list->tail = node->prev;
+  list->count--;
+  listnode_free (node);
+}
+
+/* ospf_spf.c */
+void
+list_add_node_prev (list list, listnode current, void *val)
+{
+  struct listnode *node;
+
+  node = listnode_new ();
+  node->next = current;
+  node->data = val;
+
+  if (current->prev == NULL)
+    list->head = node;
+  else
+    current->prev->next = node;
+
+  node->prev = current->prev;
+  current->prev = node;
+
+  list->count++;
+}
+
+/* ospf_spf.c */
+void
+list_add_node_next (list list, listnode current, void *val)
+{
+  struct listnode *node;
+
+  node = listnode_new ();
+  node->prev = current;
+  node->data = val;
+
+  if (current->next == NULL)
+    list->tail = node;
+  else
+    current->next->prev = node;
+
+  node->next = current->next;
+  current->next = node;
+
+  list->count++;
+}
+
+/* ospf_spf.c */
+void
+list_add_list (struct list *l, struct list *m)
+{
+  struct listnode *n;
+
+  for (n = listhead (m); n; nextnode (n))
+    listnode_add (l, n->data);
+}
diff --git a/lib/linklist.h b/lib/linklist.h
new file mode 100644
index 0000000..a91947c
--- /dev/null
+++ b/lib/linklist.h
@@ -0,0 +1,101 @@
+/* Generic linked list
+ * Copyright (C) 1997, 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 _ZEBRA_LINKLIST_H
+#define _ZEBRA_LINKLIST_H
+
+typedef struct list *list;
+typedef struct listnode *listnode;
+
+struct listnode 
+{
+  struct listnode *next;
+  struct listnode *prev;
+  void *data;
+};
+
+struct list 
+{
+  struct listnode *head;
+  struct listnode *tail;
+  unsigned int count;
+  int (*cmp) (void *val1, void *val2);
+  void (*del) (void *val);
+};
+
+#define nextnode(X) ((X) = (X)->next)
+#define listhead(X) ((X)->head)
+#define listcount(X) ((X)->count)
+#define list_isempty(X) ((X)->head == NULL && (X)->tail == NULL)
+#define getdata(X) ((X)->data)
+
+/* Prototypes. */
+struct list *list_new();
+void list_free (struct list *);
+
+void listnode_add (struct list *, void *);
+void listnode_add_sort (struct list *, void *);
+void listnode_add_after (struct list *, struct listnode *, void *);
+void listnode_delete (struct list *, void *);
+struct listnode *listnode_lookup (struct list *, void *);
+void *listnode_head (struct list *);
+
+void list_delete (struct list *);
+void list_delete_all_node (struct list *);
+
+/* For ospfd and ospf6d. */
+void list_delete_node (list, listnode);
+
+/* For ospf_spf.c */
+void list_add_node_prev (list, listnode, void *);
+void list_add_node_next (list, listnode, void *);
+void list_add_list (list, list);
+
+/* List iteration macro. */
+#define LIST_LOOP(L,V,N) \
+  for ((N) = (L)->head; (N); (N) = (N)->next) \
+    if (((V) = (N)->data) != NULL)
+
+/* List node add macro.  */
+#define LISTNODE_ADD(L,N) \
+  do { \
+    (N)->prev = (L)->tail; \
+    if ((L)->head == NULL) \
+      (L)->head = (N); \
+    else \
+      (L)->tail->next = (N); \
+    (L)->tail = (N); \
+  } while (0)
+
+/* List node delete macro.  */
+#define LISTNODE_DELETE(L,N) \
+  do { \
+    if ((N)->prev) \
+      (N)->prev->next = (N)->next; \
+    else \
+      (L)->head = (N)->next; \
+    if ((N)->next) \
+      (N)->next->prev = (N)->prev; \
+    else \
+      (L)->tail = (N)->prev; \
+  } while (0)
+
+#endif /* _ZEBRA_LINKLIST_H */
diff --git a/lib/log.c b/lib/log.c
new file mode 100644
index 0000000..9c67642
--- /dev/null
+++ b/lib/log.c
@@ -0,0 +1,483 @@
+/* Logging of zebra
+ * Copyright (C) 1997, 1998, 1999 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.  
+ */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+#include "command.h"
+
+struct zlog *zlog_default = NULL;
+
+const char *zlog_proto_names[] = 
+{
+  "NONE",
+  "DEFAULT",
+  "ZEBRA",
+  "RIP",
+  "BGP",
+  "OSPF",
+  "RIPNG",
+  "OSPF6",
+  "MASC",
+  NULL,
+};
+
+const char *zlog_priority[] =
+{
+  "emergencies",
+  "alerts",
+  "critical",
+  "errors",
+  "warnings",
+  "notifications",
+  "informational",
+  "debugging",
+  NULL,
+};
+  
+
+
+/* For time string format. */
+#define TIME_BUF 27
+
+/* Utility routine for current time printing. */
+static void
+time_print (FILE *fp)
+{
+  int ret;
+  char buf [TIME_BUF];
+  time_t clock;
+  struct tm *tm;
+  
+  time (&clock);
+  tm = localtime (&clock);
+
+  ret = strftime (buf, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm);
+  if (ret == 0) {
+    zlog_warn ("strftime error");
+  }
+
+  fprintf (fp, "%s ", buf);
+}
+
+/* va_list version of zlog. */
+void
+vzlog (struct zlog *zl, int priority, const char *format, va_list *args)
+{
+  /* If zlog is not specified, use default one. */
+  if (zl == NULL)
+    zl = zlog_default;
+
+  /* When zlog_default is also NULL, use stderr for logging. */
+  if (zl == NULL)
+    {
+      time_print (stderr);
+      fprintf (stderr, "%s: ", "unknown");
+      vfprintf (stderr, format, args[ZLOG_NOLOG_INDEX]);
+      fprintf (stderr, "\n");
+      fflush (stderr);
+
+      /* In this case we return at here. */
+      return;
+    }
+
+  /* only log this information if it has not been masked out */
+  if ( priority > zl->maskpri )
+    return ;
+		
+  /* Syslog output */
+  if (zl->flags & ZLOG_SYSLOG)
+    vsyslog (priority, format, args[ZLOG_SYSLOG_INDEX]);
+
+  /* File output. */
+  if (zl->flags & ZLOG_FILE)
+    {
+      time_print (zl->fp);
+      if (zl->record_priority) fprintf (zl->fp, "%s: ", zlog_priority[priority]);
+      fprintf (zl->fp, "%s: ", zlog_proto_names[zl->protocol]);
+      vfprintf (zl->fp, format, args[ZLOG_FILE_INDEX]);
+      fprintf (zl->fp, "\n");
+      fflush (zl->fp);
+    }
+
+  /* stdout output. */
+  if (zl->flags & ZLOG_STDOUT)
+    {
+      time_print (stdout);
+      if (zl->record_priority) fprintf (stdout, "%s: ", zlog_priority[priority]);
+      fprintf (stdout, "%s: ", zlog_proto_names[zl->protocol]);
+      vfprintf (stdout, format, args[ZLOG_STDOUT_INDEX]);
+      fprintf (stdout, "\n");
+      fflush (stdout);
+    }
+
+  /* stderr output. */
+  if (zl->flags & ZLOG_STDERR)
+    {
+      time_print (stderr);
+      if (zl->record_priority) fprintf (stderr, "%s: ", zlog_priority[priority]);
+      fprintf (stderr, "%s: ", zlog_proto_names[zl->protocol]);
+      vfprintf (stderr, format, args[ZLOG_STDERR_INDEX]);
+      fprintf (stderr, "\n");
+      fflush (stderr);
+    }
+
+  /* Terminal monitor. */
+  vty_log (zlog_proto_names[zl->protocol], format, args[ZLOG_NOLOG_INDEX]);
+}
+
+void
+zlog (struct zlog *zl, int priority, const char *format, ...)
+{
+  va_list args[ZLOG_MAX_INDEX];
+  int index;
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_start(args[index], format);
+
+  vzlog (zl, priority, format, args);
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_end (args[index]);
+}
+
+void
+zlog_err (const char *format, ...)
+{
+  va_list args[ZLOG_MAX_INDEX];
+  int index;
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_start(args[index], format);
+
+  vzlog (NULL, LOG_ERR, format, args);
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_end (args[index]);
+}
+
+void
+zlog_warn (const char *format, ...)
+{
+  va_list args[ZLOG_MAX_INDEX];
+  int index;
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_start(args[index], format);
+
+  vzlog (NULL, LOG_WARNING, format, args);
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_end (args[index]);
+}
+
+void
+zlog_info (const char *format, ...)
+{
+  va_list args[ZLOG_MAX_INDEX];
+  int index;
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_start(args[index], format);
+
+  vzlog (NULL, LOG_INFO, format, args);
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_end (args[index]);
+}
+
+void
+zlog_notice (const char *format, ...)
+{
+  va_list args[ZLOG_MAX_INDEX];
+  int index;
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_start(args[index], format);
+
+  vzlog (NULL, LOG_NOTICE, format, args);
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_end (args[index]);
+}
+
+void
+zlog_debug (const char *format, ...)
+{
+  va_list args[ZLOG_MAX_INDEX];
+  int index;
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_start(args[index], format);
+
+  vzlog (NULL, LOG_DEBUG, format, args);
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_end (args[index]);
+}
+
+void
+plog_err (struct zlog *zl, const char *format, ...)
+{
+  va_list args[ZLOG_MAX_INDEX];
+  int index;
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_start(args[index], format);
+
+  vzlog (zl, LOG_ERR, format, args);
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_end (args[index]);
+}
+
+void
+plog_warn (struct zlog *zl, const char *format, ...)
+{
+  va_list args[ZLOG_MAX_INDEX];
+  int index;
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_start(args[index], format);
+
+  vzlog (zl, LOG_WARNING, format, args);
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_end (args[index]);
+}
+
+void
+plog_info (struct zlog *zl, const char *format, ...)
+{
+  va_list args[ZLOG_MAX_INDEX];
+  int index;
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_start(args[index], format);
+
+  vzlog (zl, LOG_INFO, format, args);
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_end (args[index]);
+}
+
+void
+plog_notice (struct zlog *zl, const char *format, ...)
+{
+  va_list args[ZLOG_MAX_INDEX];
+  int index;
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_start(args[index], format);
+
+  vzlog (zl, LOG_NOTICE, format, args);
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_end (args[index]);
+}
+
+void
+plog_debug (struct zlog *zl, const char *format, ...)
+{
+  va_list args[ZLOG_MAX_INDEX];
+  int index;
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_start(args[index], format);
+
+  vzlog (zl, LOG_DEBUG, format, args);
+
+  for (index = 0; index < ZLOG_MAX_INDEX; index++)
+    va_end (args[index]);
+}
+
+
+/* Open log stream */
+struct zlog *
+openzlog (const char *progname, int flags, zlog_proto_t protocol,
+	  int syslog_flags, int syslog_facility)
+{
+  struct zlog *zl;
+
+  zl = XMALLOC(MTYPE_ZLOG, sizeof (struct zlog));
+  memset (zl, 0, sizeof (struct zlog));
+
+  zl->ident = progname;
+  zl->flags = flags;
+  zl->protocol = protocol;
+  zl->facility = syslog_facility;
+  zl->maskpri = LOG_DEBUG;
+  zl->record_priority = 0;
+
+  openlog (progname, syslog_flags, zl->facility);
+  
+  return zl;
+}
+
+void
+closezlog (struct zlog *zl)
+{
+  closelog();
+  fclose (zl->fp);
+
+  XFREE (MTYPE_ZLOG, zl);
+}
+
+/* Called from command.c. */
+void
+zlog_set_flag (struct zlog *zl, int flags)
+{
+  if (zl == NULL)
+    zl = zlog_default;
+
+  zl->flags |= flags;
+}
+
+void
+zlog_reset_flag (struct zlog *zl, int flags)
+{
+  if (zl == NULL)
+    zl = zlog_default;
+
+  zl->flags &= ~flags;
+}
+
+int
+zlog_set_file (struct zlog *zl, int flags, char *filename)
+{
+  FILE *fp;
+
+  /* There is opend file.  */
+  zlog_reset_file (zl);
+
+  /* Set default zl. */
+  if (zl == NULL)
+    zl = zlog_default;
+
+  /* Open file. */
+  fp = fopen (filename, "a");
+  if (fp == NULL)
+    return 0;
+
+  /* Set flags. */
+  zl->filename = strdup (filename);
+  zl->flags |= ZLOG_FILE;
+  zl->fp = fp;
+
+  return 1;
+}
+
+/* Reset opend file. */
+int
+zlog_reset_file (struct zlog *zl)
+{
+  if (zl == NULL)
+    zl = zlog_default;
+
+  zl->flags &= ~ZLOG_FILE;
+
+  if (zl->fp)
+    fclose (zl->fp);
+  zl->fp = NULL;
+
+  if (zl->filename)
+    free (zl->filename);
+  zl->filename = NULL;
+
+  return 1;
+}
+
+/* Reopen log file. */
+int
+zlog_rotate (struct zlog *zl)
+{
+  FILE *fp;
+
+  if (zl == NULL)
+    zl = zlog_default;
+
+  if (zl->fp)
+    fclose (zl->fp);
+  zl->fp = NULL;
+
+  if (zl->filename)
+    {
+      fp = fopen (zl->filename, "a");
+      if (fp == NULL)
+	return -1;
+      zl->fp = fp;
+    }
+
+  return 1;
+}
+
+static char *zlog_cwd = NULL;
+
+void
+zlog_save_cwd ()
+{
+  char *cwd;
+
+  cwd = getcwd (NULL, MAXPATHLEN);
+
+  zlog_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
+  strcpy (zlog_cwd, cwd);
+}
+
+char *
+zlog_get_cwd ()
+{
+  return zlog_cwd;
+}
+
+void
+zlog_free_cwd ()
+{
+  if (zlog_cwd)
+    XFREE (MTYPE_TMP, zlog_cwd);
+}
+
+/* Message lookup function. */
+char *
+lookup (struct message *mes, int key)
+{
+  struct message *pnt;
+
+  for (pnt = mes; pnt->key != 0; pnt++) 
+    if (pnt->key == key) 
+      return pnt->str;
+
+  return "";
+}
+
+/* Very old hacky version of message lookup function.  Still partly
+   used in bgpd and ospfd. */
+char *
+mes_lookup (struct message *meslist, int max, int index)
+{
+  if (index < 0 || index >= max) 
+    {
+      zlog_err ("message index out of bound: %d", max);
+      return NULL;
+    }
+  return meslist[index].str;
+}
diff --git a/lib/log.h b/lib/log.h
new file mode 100644
index 0000000..69919b4
--- /dev/null
+++ b/lib/log.h
@@ -0,0 +1,128 @@
+/* Zebra logging funcions.
+ * Copyright (C) 1997, 1998, 1999 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 _ZEBRA_LOG_H
+#define _ZEBRA_LOG_H
+
+#include <syslog.h>
+
+#define ZLOG_NOLOG              0x00
+#define ZLOG_FILE		0x01
+#define ZLOG_SYSLOG		0x02
+#define ZLOG_STDOUT             0x04
+#define ZLOG_STDERR             0x08
+
+#define ZLOG_NOLOG_INDEX        0
+#define ZLOG_FILE_INDEX         1
+#define ZLOG_SYSLOG_INDEX       2
+#define ZLOG_STDOUT_INDEX       3
+#define ZLOG_STDERR_INDEX       4
+#define ZLOG_MAX_INDEX          5
+
+typedef enum 
+{
+  ZLOG_NONE,
+  ZLOG_DEFAULT,
+  ZLOG_ZEBRA,
+  ZLOG_RIP,
+  ZLOG_BGP,
+  ZLOG_OSPF,
+  ZLOG_RIPNG,  
+  ZLOG_OSPF6,
+  ZLOG_MASC
+} zlog_proto_t;
+
+struct zlog 
+{
+  const char *ident;
+  zlog_proto_t protocol;
+  int flags;
+  FILE *fp;
+  char *filename;
+  int syslog;
+  int stat;
+  int connected;
+  int maskpri;		/* as per syslog setlogmask */
+  int priority;		/* as per syslog priority */
+  int facility;		/* as per syslog facility */
+  int record_priority;
+};
+
+/* Message structure. */
+struct message
+{
+  int key;
+  char *str;
+};
+
+/* Default logging strucutre. */
+extern struct zlog *zlog_default;
+
+/* Open zlog function */
+struct zlog *openzlog (const char *, int, zlog_proto_t, int, int);
+
+/* Close zlog function. */
+void closezlog (struct zlog *zl);
+
+/* GCC have printf type attribute check.  */
+#ifdef __GNUC__
+#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
+#else
+#define PRINTF_ATTRIBUTE(a,b)
+#endif /* __GNUC__ */
+
+/* Generic function for zlog. */
+void zlog (struct zlog *zl, int priority, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
+
+/* Handy zlog functions. */
+void zlog_err (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+void zlog_warn (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+void zlog_info (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+void zlog_notice (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+void zlog_debug (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+
+/* For bgpd's peer oriented log. */
+void plog_err (struct zlog *, const char *format, ...);
+void plog_warn (struct zlog *, const char *format, ...);
+void plog_info (struct zlog *, const char *format, ...);
+void plog_notice (struct zlog *, const char *format, ...);
+void plog_debug (struct zlog *, const char *format, ...);
+
+/* Set zlog flags. */
+void zlog_set_flag (struct zlog *zl, int flags);
+void zlog_reset_flag (struct zlog *zl, int flags);
+
+/* Set zlog filename. */
+int zlog_set_file (struct zlog *zl, int flags, char *filename);
+int zlog_reset_file (struct zlog *zl);
+
+/* Rotate log. */
+int zlog_rotate ();
+
+/* For hackey massage lookup and check */
+#define LOOKUP(x, y) mes_lookup(x, x ## _max, y)
+
+char *lookup (struct message *, int);
+char *mes_lookup (struct message *meslist, int max, int index);
+
+extern const char *zlog_priority[];
+
+#endif /* _ZEBRA_LOG_H */
diff --git a/lib/md5-gnu.h b/lib/md5-gnu.h
new file mode 100644
index 0000000..dacc1ae
--- /dev/null
+++ b/lib/md5-gnu.h
@@ -0,0 +1,156 @@
+/* Declaration of functions and data types used for MD5 sum computing
+   library functions.
+   Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _MD5_H
+#define _MD5_H 1
+
+#include <stdio.h>
+
+#if defined HAVE_LIMITS_H || _LIBC
+# include <limits.h>
+#endif
+
+/* The following contortions are an attempt to use the C preprocessor
+   to determine an unsigned integral type that is 32 bits wide.  An
+   alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
+   doing that would require that the configure script compile and *run*
+   the resulting executable.  Locally running cross-compiled executables
+   is usually not possible.  */
+
+#ifdef _LIBC
+# include <sys/types.h>
+typedef u_int32_t md5_uint32;
+#else
+# if defined __STDC__ && __STDC__
+#  define UINT_MAX_32_BITS 4294967295U
+# else
+#  define UINT_MAX_32_BITS 0xFFFFFFFF
+# endif
+
+/* If UINT_MAX isn't defined, assume it's a 32-bit type.
+   This should be valid for all systems GNU cares about because
+   that doesn't include 16-bit systems, and only modern systems
+   (that certainly have <limits.h>) have 64+-bit integral types.  */
+
+# ifndef UINT_MAX
+#  define UINT_MAX UINT_MAX_32_BITS
+# endif
+
+# if UINT_MAX == UINT_MAX_32_BITS
+   typedef unsigned int md5_uint32;
+# else
+#  if USHRT_MAX == UINT_MAX_32_BITS
+    typedef unsigned short md5_uint32;
+#  else
+#   if ULONG_MAX == UINT_MAX_32_BITS
+     typedef unsigned long md5_uint32;
+#   else
+     /* The following line is intended to evoke an error.
+        Using #error is not portable enough.  */
+     "Cannot determine unsigned 32-bit data type."
+#   endif
+#  endif
+# endif
+#endif
+
+#undef __P
+#if defined (__STDC__) && __STDC__
+# define __P(x) x
+#else
+# define __P(x) ()
+#endif
+
+/* Structure to save state of computation between the single steps.  */
+struct md5_ctx
+{
+  md5_uint32 A;
+  md5_uint32 B;
+  md5_uint32 C;
+  md5_uint32 D;
+
+  md5_uint32 total[2];
+  md5_uint32 buflen;
+  char buffer[128];
+};
+
+/*
+ * The following three functions are build up the low level used in
+ * the functions `md5_stream' and `md5_buffer'.
+ */
+
+/* Initialize structure containing state of computation.
+   (RFC 1321, 3.3: Step 3)  */
+extern void __md5_init_ctx __P ((struct md5_ctx *ctx));
+extern void md5_init_ctx __P ((struct md5_ctx *ctx));
+
+/* Starting with the result of former calls of this function (or the
+   initialization function update the context for the next LEN bytes
+   starting at BUFFER.
+   It is necessary that LEN is a multiple of 64!!! */
+extern void __md5_process_block __P ((const void *buffer, size_t len,
+				      struct md5_ctx *ctx));
+extern void md5_process_block __P ((const void *buffer, size_t len,
+				    struct md5_ctx *ctx));
+
+/* Starting with the result of former calls of this function (or the
+   initialization function update the context for the next LEN bytes
+   starting at BUFFER.
+   It is NOT required that LEN is a multiple of 64.  */
+extern void __md5_process_bytes __P ((const void *buffer, size_t len,
+				      struct md5_ctx *ctx));
+extern void md5_process_bytes __P ((const void *buffer, size_t len,
+				    struct md5_ctx *ctx));
+
+/* Process the remaining bytes in the buffer and put result from CTX
+   in first 16 bytes following RESBUF.  The result is always in little
+   endian byte order, so that a byte-wise output yields to the wanted
+   ASCII representation of the message digest.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+extern void *__md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf));
+extern void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf));
+
+
+/* Put result from CTX in first 16 bytes following RESBUF.  The result is
+   always in little endian byte order, so that a byte-wise output yields
+   to the wanted ASCII representation of the message digest.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+extern void *__md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf));
+extern void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf));
+
+
+/* Compute MD5 message digest for bytes read from STREAM.  The
+   resulting message digest number will be written into the 16 bytes
+   beginning at RESBLOCK.  */
+extern int __md5_stream __P ((FILE *stream, void *resblock));
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
+   result is always in little endian byte order, so that a byte-wise
+   output yields to the wanted ASCII representation of the message
+   digest.  */
+extern void *__md5_buffer __P ((const char *buffer, size_t len,
+				void *resblock));
+extern void *md5_buffer __P ((const char *buffer, size_t len,
+			      void *resblock));
+
+#endif /* md5.h */
diff --git a/lib/md5.c b/lib/md5.c
new file mode 100644
index 0000000..2068c46
--- /dev/null
+++ b/lib/md5.c
@@ -0,0 +1,447 @@
+/* md5.c - Functions to compute MD5 message digest of files or memory blocks
+   according to the definition of MD5 in RFC 1321 from April 1992.
+   Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+# include <string.h>
+#else
+# ifndef HAVE_MEMCPY
+#  define memcpy(d, s, n) bcopy ((s), (d), (n))
+# endif
+#endif
+
+#include "md5-gnu.h"
+
+#ifdef _LIBC
+# include <endian.h>
+# if __BYTE_ORDER == __BIG_ENDIAN
+#  define WORDS_BIGENDIAN 1
+# endif
+/* We need to keep the namespace clean so define the MD5 function
+   protected using leading __ and use weak aliases.  */
+# define md5_init_ctx __md5_init_ctx
+# define md5_process_block __md5_process_block
+# define md5_process_bytes __md5_process_bytes
+# define md5_finish_ctx __md5_finish_ctx
+# define md5_read_ctx __md5_read_ctx
+# define md5_stream __md5_stream
+# define md5_buffer __md5_buffer
+#endif
+
+#ifdef WORDS_BIGENDIAN
+# define SWAP(n)							\
+    (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
+#else
+# define SWAP(n) (n)
+#endif
+
+
+/* This array contains the bytes used to pad the buffer to the next
+   64-byte boundary.  (RFC 1321, 3.1: Step 1)  */
+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */ };
+
+
+/* Initialize structure containing state of computation.
+   (RFC 1321, 3.3: Step 3)  */
+void
+md5_init_ctx (ctx)
+     struct md5_ctx *ctx;
+{
+  ctx->A = 0x67452301;
+  ctx->B = 0xefcdab89;
+  ctx->C = 0x98badcfe;
+  ctx->D = 0x10325476;
+
+  ctx->total[0] = ctx->total[1] = 0;
+  ctx->buflen = 0;
+}
+
+/* Put result from CTX in first 16 bytes following RESBUF.  The result
+   must be in little endian byte order.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+void *
+md5_read_ctx (ctx, resbuf)
+     const struct md5_ctx *ctx;
+     void *resbuf;
+{
+  ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
+  ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
+  ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
+  ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
+
+  return resbuf;
+}
+
+/* Process the remaining bytes in the internal buffer and the usual
+   prolog according to the standard and write the result to RESBUF.
+
+   IMPORTANT: On some systems it is required that RESBUF is correctly
+   aligned for a 32 bits value.  */
+void *
+md5_finish_ctx (ctx, resbuf)
+     struct md5_ctx *ctx;
+     void *resbuf;
+{
+  /* Take yet unprocessed bytes into account.  */
+  md5_uint32 bytes = ctx->buflen;
+  size_t pad;
+
+  /* Now count remaining bytes.  */
+  ctx->total[0] += bytes;
+  if (ctx->total[0] < bytes)
+    ++ctx->total[1];
+
+  pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
+  memcpy (&ctx->buffer[bytes], fillbuf, pad);
+
+  /* Put the 64-bit file length in *bits* at the end of the buffer.  */
+  *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3);
+  *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) |
+							(ctx->total[0] >> 29));
+
+  /* Process last bytes.  */
+  md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
+
+  return md5_read_ctx (ctx, resbuf);
+}
+
+/* Compute MD5 message digest for bytes read from STREAM.  The
+   resulting message digest number will be written into the 16 bytes
+   beginning at RESBLOCK.  */
+int
+md5_stream (stream, resblock)
+     FILE *stream;
+     void *resblock;
+{
+  /* Important: BLOCKSIZE must be a multiple of 64.  */
+#define BLOCKSIZE 4096
+  struct md5_ctx ctx;
+  char buffer[BLOCKSIZE + 72];
+  size_t sum;
+
+  /* Initialize the computation context.  */
+  md5_init_ctx (&ctx);
+
+  /* Iterate over full file contents.  */
+  while (1)
+    {
+      /* We read the file in blocks of BLOCKSIZE bytes.  One call of the
+	 computation function processes the whole buffer so that with the
+	 next round of the loop another block can be read.  */
+      size_t n;
+      sum = 0;
+
+      /* Read block.  Take care for partial reads.  */
+      do
+	{
+	  n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
+
+	  sum += n;
+	}
+      while (sum < BLOCKSIZE && n != 0);
+      if (n == 0 && ferror (stream))
+        return 1;
+
+      /* If end of file is reached, end the loop.  */
+      if (n == 0)
+	break;
+
+      /* Process buffer with BLOCKSIZE bytes.  Note that
+			BLOCKSIZE % 64 == 0
+       */
+      md5_process_block (buffer, BLOCKSIZE, &ctx);
+    }
+
+  /* Add the last bytes if necessary.  */
+  if (sum > 0)
+    md5_process_bytes (buffer, sum, &ctx);
+
+  /* Construct result in desired memory.  */
+  md5_finish_ctx (&ctx, resblock);
+  return 0;
+}
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER.  The
+   result is always in little endian byte order, so that a byte-wise
+   output yields to the wanted ASCII representation of the message
+   digest.  */
+void *
+md5_buffer (buffer, len, resblock)
+     const char *buffer;
+     size_t len;
+     void *resblock;
+{
+  struct md5_ctx ctx;
+
+  /* Initialize the computation context.  */
+  md5_init_ctx (&ctx);
+
+  /* Process whole buffer but last len % 64 bytes.  */
+  md5_process_bytes (buffer, len, &ctx);
+
+  /* Put result in desired memory area.  */
+  return md5_finish_ctx (&ctx, resblock);
+}
+
+
+void
+md5_process_bytes (buffer, len, ctx)
+     const void *buffer;
+     size_t len;
+     struct md5_ctx *ctx;
+{
+  /* When we already have some bits in our internal buffer concatenate
+     both inputs first.  */
+  if (ctx->buflen != 0)
+    {
+      size_t left_over = ctx->buflen;
+      size_t add = 128 - left_over > len ? len : 128 - left_over;
+
+      memcpy (&ctx->buffer[left_over], buffer, add);
+      ctx->buflen += add;
+
+      if (left_over + add > 64)
+	{
+	  md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx);
+	  /* The regions in the following copy operation cannot overlap.  */
+	  memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
+		  (left_over + add) & 63);
+	  ctx->buflen = (left_over + add) & 63;
+	}
+
+      buffer = (const char *) buffer + add;
+      len -= add;
+    }
+
+  /* Process available complete blocks.  */
+  if (len > 64)
+    {
+      md5_process_block (buffer, len & ~63, ctx);
+      buffer = (const char *) buffer + (len & ~63);
+      len &= 63;
+    }
+
+  /* Move remaining bytes in internal buffer.  */
+  if (len > 0)
+    {
+      memcpy (ctx->buffer, buffer, len);
+      ctx->buflen = len;
+    }
+}
+
+
+/* These are the four functions used in the four steps of the MD5 algorithm
+   and defined in the RFC 1321.  The first function is a little bit optimized
+   (as found in Colin Plumbs public domain implementation).  */
+/* #define FF(b, c, d) ((b & c) | (~b & d)) */
+#define FF(b, c, d) (d ^ (b & (c ^ d)))
+#define FG(b, c, d) FF (d, b, c)
+#define FH(b, c, d) (b ^ c ^ d)
+#define FI(b, c, d) (c ^ (b | ~d))
+
+/* Process LEN bytes of BUFFER, accumulating context into CTX.
+   It is assumed that LEN % 64 == 0.  */
+
+void
+md5_process_block (buffer, len, ctx)
+     const void *buffer;
+     size_t len;
+     struct md5_ctx *ctx;
+{
+  md5_uint32 correct_words[16];
+  const md5_uint32 *words = buffer;
+  size_t nwords = len / sizeof (md5_uint32);
+  const md5_uint32 *endp = words + nwords;
+  md5_uint32 A = ctx->A;
+  md5_uint32 B = ctx->B;
+  md5_uint32 C = ctx->C;
+  md5_uint32 D = ctx->D;
+
+  /* First increment the byte count.  RFC 1321 specifies the possible
+     length of the file up to 2^64 bits.  Here we only compute the
+     number of bytes.  Do a double word increment.  */
+  ctx->total[0] += len;
+  if (ctx->total[0] < len)
+    ++ctx->total[1];
+
+  /* Process all bytes in the buffer with 64 bytes in each round of
+     the loop.  */
+  while (words < endp)
+    {
+      md5_uint32 *cwp = correct_words;
+      md5_uint32 A_save = A;
+      md5_uint32 B_save = B;
+      md5_uint32 C_save = C;
+      md5_uint32 D_save = D;
+
+      /* First round: using the given function, the context and a constant
+	 the next context is computed.  Because the algorithms processing
+	 unit is a 32-bit word and it is determined to work on words in
+	 little endian byte order we perhaps have to change the byte order
+	 before the computation.  To reduce the work for the next steps
+	 we store the swapped words in the array CORRECT_WORDS.  */
+
+#define OP(a, b, c, d, s, T)						\
+      do								\
+        {								\
+	  a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T;		\
+	  ++words;							\
+	  CYCLIC (a, s);						\
+	  a += b;							\
+        }								\
+      while (0)
+
+      /* It is unfortunate that C does not provide an operator for
+	 cyclic rotation.  Hope the C compiler is smart enough.  */
+#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
+
+      /* Before we start, one word to the strange constants.
+	 They are defined in RFC 1321 as
+
+	 T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
+       */
+
+      /* Round 1.  */
+      OP (A, B, C, D,  7, 0xd76aa478);
+      OP (D, A, B, C, 12, 0xe8c7b756);
+      OP (C, D, A, B, 17, 0x242070db);
+      OP (B, C, D, A, 22, 0xc1bdceee);
+      OP (A, B, C, D,  7, 0xf57c0faf);
+      OP (D, A, B, C, 12, 0x4787c62a);
+      OP (C, D, A, B, 17, 0xa8304613);
+      OP (B, C, D, A, 22, 0xfd469501);
+      OP (A, B, C, D,  7, 0x698098d8);
+      OP (D, A, B, C, 12, 0x8b44f7af);
+      OP (C, D, A, B, 17, 0xffff5bb1);
+      OP (B, C, D, A, 22, 0x895cd7be);
+      OP (A, B, C, D,  7, 0x6b901122);
+      OP (D, A, B, C, 12, 0xfd987193);
+      OP (C, D, A, B, 17, 0xa679438e);
+      OP (B, C, D, A, 22, 0x49b40821);
+
+      /* For the second to fourth round we have the possibly swapped words
+	 in CORRECT_WORDS.  Redefine the macro to take an additional first
+	 argument specifying the function to use.  */
+#undef OP
+#define OP(f, a, b, c, d, k, s, T)					\
+      do 								\
+	{								\
+	  a += f (b, c, d) + correct_words[k] + T;			\
+	  CYCLIC (a, s);						\
+	  a += b;							\
+	}								\
+      while (0)
+
+      /* Round 2.  */
+      OP (FG, A, B, C, D,  1,  5, 0xf61e2562);
+      OP (FG, D, A, B, C,  6,  9, 0xc040b340);
+      OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
+      OP (FG, B, C, D, A,  0, 20, 0xe9b6c7aa);
+      OP (FG, A, B, C, D,  5,  5, 0xd62f105d);
+      OP (FG, D, A, B, C, 10,  9, 0x02441453);
+      OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
+      OP (FG, B, C, D, A,  4, 20, 0xe7d3fbc8);
+      OP (FG, A, B, C, D,  9,  5, 0x21e1cde6);
+      OP (FG, D, A, B, C, 14,  9, 0xc33707d6);
+      OP (FG, C, D, A, B,  3, 14, 0xf4d50d87);
+      OP (FG, B, C, D, A,  8, 20, 0x455a14ed);
+      OP (FG, A, B, C, D, 13,  5, 0xa9e3e905);
+      OP (FG, D, A, B, C,  2,  9, 0xfcefa3f8);
+      OP (FG, C, D, A, B,  7, 14, 0x676f02d9);
+      OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
+
+      /* Round 3.  */
+      OP (FH, A, B, C, D,  5,  4, 0xfffa3942);
+      OP (FH, D, A, B, C,  8, 11, 0x8771f681);
+      OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
+      OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
+      OP (FH, A, B, C, D,  1,  4, 0xa4beea44);
+      OP (FH, D, A, B, C,  4, 11, 0x4bdecfa9);
+      OP (FH, C, D, A, B,  7, 16, 0xf6bb4b60);
+      OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
+      OP (FH, A, B, C, D, 13,  4, 0x289b7ec6);
+      OP (FH, D, A, B, C,  0, 11, 0xeaa127fa);
+      OP (FH, C, D, A, B,  3, 16, 0xd4ef3085);
+      OP (FH, B, C, D, A,  6, 23, 0x04881d05);
+      OP (FH, A, B, C, D,  9,  4, 0xd9d4d039);
+      OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
+      OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
+      OP (FH, B, C, D, A,  2, 23, 0xc4ac5665);
+
+      /* Round 4.  */
+      OP (FI, A, B, C, D,  0,  6, 0xf4292244);
+      OP (FI, D, A, B, C,  7, 10, 0x432aff97);
+      OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
+      OP (FI, B, C, D, A,  5, 21, 0xfc93a039);
+      OP (FI, A, B, C, D, 12,  6, 0x655b59c3);
+      OP (FI, D, A, B, C,  3, 10, 0x8f0ccc92);
+      OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
+      OP (FI, B, C, D, A,  1, 21, 0x85845dd1);
+      OP (FI, A, B, C, D,  8,  6, 0x6fa87e4f);
+      OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
+      OP (FI, C, D, A, B,  6, 15, 0xa3014314);
+      OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
+      OP (FI, A, B, C, D,  4,  6, 0xf7537e82);
+      OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
+      OP (FI, C, D, A, B,  2, 15, 0x2ad7d2bb);
+      OP (FI, B, C, D, A,  9, 21, 0xeb86d391);
+
+      /* Add the starting values of the context.  */
+      A += A_save;
+      B += B_save;
+      C += C_save;
+      D += D_save;
+    }
+
+  /* Put checksum in context given as argument.  */
+  ctx->A = A;
+  ctx->B = B;
+  ctx->C = C;
+  ctx->D = D;
+}
+
+
+#ifdef _LIBC
+/* Define weak aliases.  */
+# undef md5_init_ctx
+weak_alias (__md5_init_ctx, md5_init_ctx)
+# undef md5_process_block
+weak_alias (__md5_process_block, md5_process_block)
+# undef md5_process_bytes
+weak_alias (__md5_process_bytes, md5_process_bytes)
+# undef md5_finish_ctx
+weak_alias (__md5_finish_ctx, md5_finish_ctx)
+# undef md5_read_ctx
+weak_alias (__md5_read_ctx, md5_read_ctx)
+# undef md5_stream
+weak_alias (__md5_stream, md5_stream)
+# undef md5_buffer
+weak_alias (__md5_buffer, md5_buffer)
+#endif
diff --git a/lib/memory.c b/lib/memory.c
new file mode 100644
index 0000000..bf142dc
--- /dev/null
+++ b/lib/memory.c
@@ -0,0 +1,493 @@
+/*
+ * Memory management routine
+ * Copyright (C) 1998 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.  
+ */
+
+#include <zebra.h>
+
+#include "log.h"
+#include "memory.h"
+
+void alloc_inc (int);
+void alloc_dec (int);
+
+struct message mstr [] =
+{
+  { MTYPE_THREAD, "thread" },
+  { MTYPE_THREAD_MASTER, "thread_master" },
+  { MTYPE_VECTOR, "vector" },
+  { MTYPE_VECTOR_INDEX, "vector_index" },
+  { MTYPE_IF, "interface" },
+  { 0, NULL },
+};
+
+/* Fatal memory allocation error occured. */
+static void
+zerror (const char *fname, int type, size_t size)
+{
+  fprintf (stderr, "%s : can't allocate memory for `%s' size %d\n", 
+	   fname, lookup (mstr, type), (int) size);
+  exit (1);
+}
+
+/* Memory allocation. */
+void *
+zmalloc (int type, size_t size)
+{
+  void *memory;
+
+  memory = malloc (size);
+
+  if (memory == NULL)
+    zerror ("malloc", type, size);
+
+  alloc_inc (type);
+
+  return memory;
+}
+
+/* Memory allocation with num * size with cleared. */
+void *
+zcalloc (int type, size_t size)
+{
+  void *memory;
+
+  memory = calloc (1, size);
+
+  if (memory == NULL)
+    zerror ("calloc", type, size);
+
+  alloc_inc (type);
+
+  return memory;
+}
+
+/* Memory reallocation. */
+void *
+zrealloc (int type, void *ptr, size_t size)
+{
+  void *memory;
+
+  memory = realloc (ptr, size);
+  if (memory == NULL)
+    zerror ("realloc", type, size);
+  return memory;
+}
+
+/* Memory free. */
+void
+zfree (int type, void *ptr)
+{
+  alloc_dec (type);
+  free (ptr);
+}
+
+/* String duplication. */
+char *
+zstrdup (int type, char *str)
+{
+  void *dup;
+
+  dup = strdup (str);
+  if (dup == NULL)
+    zerror ("strdup", type, strlen (str));
+  alloc_inc (type);
+  return dup;
+}
+
+#ifdef MEMORY_LOG
+struct 
+{
+  char *name;
+  unsigned long alloc;
+  unsigned long t_malloc;
+  unsigned long c_malloc;
+  unsigned long t_calloc;
+  unsigned long c_calloc;
+  unsigned long t_realloc;
+  unsigned long t_free;
+  unsigned long c_strdup;
+} mstat [MTYPE_MAX];
+
+void
+mtype_log (char *func, void *memory, const char *file, int line, int type)
+{
+  zlog_info ("%s: %s %p %s %d", func, lookup (mstr, type), memory, file, line);
+}
+
+void *
+mtype_zmalloc (const char *file, int line, int type, size_t size)
+{
+  void *memory;
+
+  mstat[type].c_malloc++;
+  mstat[type].t_malloc++;
+
+  memory = zmalloc (type, size);
+  mtype_log ("zmalloc", memory, file, line, type);
+
+  return memory;
+}
+
+void *
+mtype_zcalloc (const char *file, int line, int type, size_t size)
+{
+  void *memory;
+
+  mstat[type].c_calloc++;
+  mstat[type].t_calloc++;
+
+  memory = zcalloc (type, size);
+  mtype_log ("xcalloc", memory, file, line, type);
+
+  return memory;
+}
+
+void *
+mtype_zrealloc (const char *file, int line, int type, void *ptr, size_t size)
+{
+  void *memory;
+
+  /* Realloc need before allocated pointer. */
+  mstat[type].t_realloc++;
+
+  memory = zrealloc (type, ptr, size);
+
+  mtype_log ("xrealloc", memory, file, line, type);
+
+  return memory;
+}
+
+/* Important function. */
+void 
+mtype_zfree (const char *file, int line, int type, void *ptr)
+{
+  mstat[type].t_free++;
+
+  mtype_log ("xfree", ptr, file, line, type);
+
+  zfree (type, ptr);
+}
+
+char *
+mtype_zstrdup (const char *file, int line, int type, char *str)
+{
+  char *memory;
+
+  mstat[type].c_strdup++;
+
+  memory = zstrdup (type, str);
+  
+  mtype_log ("xstrdup", memory, file, line, type);
+
+  return memory;
+}
+#else
+struct 
+{
+  char *name;
+  unsigned long alloc;
+} mstat [MTYPE_MAX];
+#endif /* MTPYE_LOG */
+
+/* Increment allocation counter. */
+void
+alloc_inc (int type)
+{
+  mstat[type].alloc++;
+}
+
+/* Decrement allocation counter. */
+void
+alloc_dec (int type)
+{
+  mstat[type].alloc--;
+}
+
+/* Looking up memory status from vty interface. */
+#include "vector.h"
+#include "vty.h"
+#include "command.h"
+
+/* For pretty printng of memory allocate information. */
+struct memory_list
+{
+  int index;
+  char *format;
+};
+
+struct memory_list memory_list_lib[] =
+{
+  { MTYPE_TMP,                "Temporary memory" },
+  { MTYPE_ROUTE_TABLE,        "Route table     " },
+  { MTYPE_ROUTE_NODE,         "Route node      " },
+  { MTYPE_RIB,                "RIB             " },
+  { MTYPE_NEXTHOP,            "Nexthop         " },
+  { MTYPE_LINK_LIST,          "Link List       " },
+  { MTYPE_LINK_NODE,          "Link Node       " },
+  { MTYPE_HASH,               "Hash            " },
+  { MTYPE_HASH_BACKET,        "Hash Bucket     " },
+  { MTYPE_ACCESS_LIST,        "Access List     " },
+  { MTYPE_ACCESS_LIST_STR,    "Access List Str " },
+  { MTYPE_ACCESS_FILTER,      "Access Filter   " },
+  { MTYPE_PREFIX_LIST,        "Prefix List     " },
+  { MTYPE_PREFIX_LIST_STR,    "Prefix List Str " },
+  { MTYPE_PREFIX_LIST_ENTRY,  "Prefix List Entry "},
+  { MTYPE_ROUTE_MAP,          "Route map       " },
+  { MTYPE_ROUTE_MAP_NAME,     "Route map name  " },
+  { MTYPE_ROUTE_MAP_INDEX,    "Route map index " },
+  { MTYPE_ROUTE_MAP_RULE,     "Route map rule  " },
+  { MTYPE_ROUTE_MAP_RULE_STR, "Route map rule str" },
+  { MTYPE_DESC,               "Command desc    " },
+  { MTYPE_BUFFER,             "Buffer          " },
+  { MTYPE_BUFFER_DATA,        "Buffer data     " },
+  { MTYPE_STREAM,             "Stream          " },
+  { MTYPE_KEYCHAIN,           "Key chain       " },
+  { MTYPE_KEY,                "Key             " },
+  { MTYPE_VTY,                "VTY             " },
+  { -1, NULL }
+};
+
+struct memory_list memory_list_bgp[] =
+{
+  { MTYPE_BGP_PEER,               "BGP peer" },
+  { MTYPE_ATTR,                   "BGP attribute" },
+  { MTYPE_AS_PATH,                "BGP aspath" },
+  { MTYPE_AS_SEG,                 "BGP aspath seg" },
+  { MTYPE_AS_STR,                 "BGP aspath str" },
+  { 0, NULL },
+  { MTYPE_BGP_TABLE,              "BGP table" },
+  { MTYPE_BGP_NODE,               "BGP node" },
+  { MTYPE_BGP_ADVERTISE_ATTR,     "BGP adv attr" },
+  { MTYPE_BGP_ADVERTISE,          "BGP adv" },
+  { MTYPE_BGP_ADJ_IN,             "BGP adj in" },
+  { MTYPE_BGP_ADJ_OUT,            "BGP adj out" },
+  { 0, NULL },
+  { MTYPE_AS_LIST,                "BGP AS list" },
+  { MTYPE_AS_FILTER,              "BGP AS filter" },
+  { MTYPE_AS_FILTER_STR,          "BGP AS filter str" },
+  { 0, NULL },
+  { MTYPE_COMMUNITY,              "community" },
+  { MTYPE_COMMUNITY_VAL,          "community val" },
+  { MTYPE_COMMUNITY_STR,          "community str" },
+  { 0, NULL },
+  { MTYPE_ECOMMUNITY,             "extcommunity" },
+  { MTYPE_ECOMMUNITY_VAL,         "extcommunity val" },
+  { MTYPE_ECOMMUNITY_STR,         "extcommunity str" },
+  { 0, NULL },
+  { MTYPE_COMMUNITY_LIST,         "community-list" },
+  { MTYPE_COMMUNITY_LIST_NAME,    "community-list name" },
+  { MTYPE_COMMUNITY_LIST_ENTRY,   "community-list entry" },
+  { MTYPE_COMMUNITY_LIST_CONFIG,  "community-list config" },
+  { 0, NULL },
+  { MTYPE_CLUSTER,                "Cluster list" },
+  { MTYPE_CLUSTER_VAL,            "Cluster list val" },
+  { 0, NULL },
+  { MTYPE_TRANSIT,                "BGP transit attr" },
+  { MTYPE_TRANSIT_VAL,            "BGP transit val" },
+  { 0, NULL },
+  { MTYPE_BGP_DISTANCE,           "BGP distance" },
+  { MTYPE_BGP_NEXTHOP_CACHE,      "BGP nexthop" },
+  { MTYPE_BGP_CONFED_LIST,        "BGP confed list" },
+  { MTYPE_PEER_UPDATE_SOURCE,     "peer update if" },
+  { MTYPE_BGP_DAMP_INFO,          "Dampening info" },
+  { MTYPE_BGP_REGEXP,             "BGP regexp" },
+  { -1, NULL }
+};
+
+struct memory_list memory_list_rip[] =
+{
+  { MTYPE_RIP,                "RIP structure   " },
+  { MTYPE_RIP_INFO,           "RIP route info  " },
+  { MTYPE_RIP_INTERFACE,      "RIP interface   " },
+  { MTYPE_RIP_PEER,           "RIP peer        " },
+  { MTYPE_RIP_OFFSET_LIST,    "RIP offset list " },
+  { MTYPE_RIP_DISTANCE,       "RIP distance    " },
+  { -1, NULL }
+};
+
+struct memory_list memory_list_ospf[] =
+{
+  { MTYPE_OSPF_TOP,           "OSPF top        " },
+  { MTYPE_OSPF_AREA,          "OSPF area       " },
+  { MTYPE_OSPF_AREA_RANGE,    "OSPF area range " },
+  { MTYPE_OSPF_NETWORK,       "OSPF network    " },
+#ifdef NBMA_ENABLE
+  { MTYPE_OSPF_NEIGHBOR_STATIC,"OSPF static nbr " },
+#endif  /* NBMA_ENABLE */
+  { MTYPE_OSPF_IF,            "OSPF interface  " },
+  { MTYPE_OSPF_NEIGHBOR,      "OSPF neighbor   " },
+  { MTYPE_OSPF_ROUTE,         "OSPF route      " },
+  { MTYPE_OSPF_TMP,           "OSPF tmp mem    " },
+  { MTYPE_OSPF_LSA,           "OSPF LSA        " },
+  { MTYPE_OSPF_LSA_DATA,      "OSPF LSA data   " },
+  { MTYPE_OSPF_LSDB,          "OSPF LSDB       " },
+  { MTYPE_OSPF_PACKET,        "OSPF packet     " },
+  { MTYPE_OSPF_FIFO,          "OSPF FIFO queue " },
+  { MTYPE_OSPF_VERTEX,        "OSPF vertex     " },
+  { MTYPE_OSPF_NEXTHOP,       "OSPF nexthop    " },
+  { MTYPE_OSPF_PATH,	      "OSPF path       " },
+  { MTYPE_OSPF_VL_DATA,       "OSPF VL data    " },
+  { MTYPE_OSPF_CRYPT_KEY,     "OSPF crypt key  " },
+  { MTYPE_OSPF_EXTERNAL_INFO, "OSPF ext. info  " },
+  { MTYPE_OSPF_DISTANCE,      "OSPF distance   " },
+  { MTYPE_OSPF_IF_INFO,       "OSPF if info    " },
+  { MTYPE_OSPF_IF_PARAMS,     "OSPF if params  " },
+  { -1, NULL },
+};
+
+struct memory_list memory_list_ospf6[] =
+{
+  { MTYPE_OSPF6_TOP,          "OSPF6 top         " },
+  { MTYPE_OSPF6_AREA,         "OSPF6 area        " },
+  { MTYPE_OSPF6_IF,           "OSPF6 interface   " },
+  { MTYPE_OSPF6_NEIGHBOR,     "OSPF6 neighbor    " },
+  { MTYPE_OSPF6_ROUTE,        "OSPF6 route       " },
+  { MTYPE_OSPF6_PREFIX,       "OSPF6 prefix      " },
+  { MTYPE_OSPF6_MESSAGE,      "OSPF6 message     " },
+  { MTYPE_OSPF6_LSA,          "OSPF6 LSA         " },
+  { MTYPE_OSPF6_LSA_SUMMARY,  "OSPF6 LSA summary " },
+  { MTYPE_OSPF6_LSDB,         "OSPF6 LSA database" },
+  { MTYPE_OSPF6_VERTEX,       "OSPF6 vertex      " },
+  { MTYPE_OSPF6_SPFTREE,      "OSPF6 SPF tree    " },
+  { MTYPE_OSPF6_NEXTHOP,      "OSPF6 nexthop     " },
+  { MTYPE_OSPF6_EXTERNAL_INFO,"OSPF6 ext. info   " },
+  { MTYPE_OSPF6_OTHER,        "OSPF6 other       " },
+  { -1, NULL },
+};
+
+struct memory_list memory_list_separator[] =
+{
+  { 0, NULL},
+  {-1, NULL}
+};
+
+void
+show_memory_vty (struct vty *vty, struct memory_list *list)
+{
+  struct memory_list *m;
+
+  for (m = list; m->index >= 0; m++)
+    if (m->index == 0)
+      vty_out (vty, "-----------------------------\r\n");
+    else
+      vty_out (vty, "%-22s: %5ld\r\n", m->format, mstat[m->index].alloc);
+}
+
+DEFUN (show_memory_all,
+       show_memory_all_cmd,
+       "show memory all",
+       "Show running system information\n"
+       "Memory statistics\n"
+       "All memory statistics\n")
+{
+  show_memory_vty (vty, memory_list_lib);
+  show_memory_vty (vty, memory_list_separator);
+  show_memory_vty (vty, memory_list_rip);
+  show_memory_vty (vty, memory_list_separator);
+  show_memory_vty (vty, memory_list_ospf);
+  show_memory_vty (vty, memory_list_separator);
+  show_memory_vty (vty, memory_list_ospf6);
+  show_memory_vty (vty, memory_list_separator);
+  show_memory_vty (vty, memory_list_bgp);
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (show_memory_all,
+       show_memory_cmd,
+       "show memory",
+       "Show running system information\n"
+       "Memory statistics\n")
+
+DEFUN (show_memory_lib,
+       show_memory_lib_cmd,
+       "show memory lib",
+       SHOW_STR
+       "Memory statistics\n"
+       "Library memory\n")
+{
+  show_memory_vty (vty, memory_list_lib);
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_memory_rip,
+       show_memory_rip_cmd,
+       "show memory rip",
+       SHOW_STR
+       "Memory statistics\n"
+       "RIP memory\n")
+{
+  show_memory_vty (vty, memory_list_rip);
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_memory_bgp,
+       show_memory_bgp_cmd,
+       "show memory bgp",
+       SHOW_STR
+       "Memory statistics\n"
+       "BGP memory\n")
+{
+  show_memory_vty (vty, memory_list_bgp);
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_memory_ospf,
+       show_memory_ospf_cmd,
+       "show memory ospf",
+       SHOW_STR
+       "Memory statistics\n"
+       "OSPF memory\n")
+{
+  show_memory_vty (vty, memory_list_ospf);
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_memory_ospf6,
+       show_memory_ospf6_cmd,
+       "show memory ospf6",
+       SHOW_STR
+       "Memory statistics\n"
+       "OSPF6 memory\n")
+{
+  show_memory_vty (vty, memory_list_ospf6);
+  return CMD_SUCCESS;
+}
+
+void
+memory_init ()
+{
+  install_element (VIEW_NODE, &show_memory_cmd);
+  install_element (VIEW_NODE, &show_memory_all_cmd);
+  install_element (VIEW_NODE, &show_memory_lib_cmd);
+  install_element (VIEW_NODE, &show_memory_rip_cmd);
+  install_element (VIEW_NODE, &show_memory_bgp_cmd);
+  install_element (VIEW_NODE, &show_memory_ospf_cmd);
+  install_element (VIEW_NODE, &show_memory_ospf6_cmd);
+
+  install_element (ENABLE_NODE, &show_memory_cmd);
+  install_element (ENABLE_NODE, &show_memory_all_cmd);
+  install_element (ENABLE_NODE, &show_memory_lib_cmd);
+  install_element (ENABLE_NODE, &show_memory_rip_cmd);
+  install_element (ENABLE_NODE, &show_memory_bgp_cmd);
+  install_element (ENABLE_NODE, &show_memory_ospf_cmd);
+  install_element (ENABLE_NODE, &show_memory_ospf6_cmd);
+}
diff --git a/lib/memory.h b/lib/memory.h
new file mode 100644
index 0000000..52e3bc1
--- /dev/null
+++ b/lib/memory.h
@@ -0,0 +1,245 @@
+/* Memory management routine
+   Copyright (C) 1998 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 _ZEBRA_MEMORY_H
+#define _ZEBRA_MEMORY_H
+
+/* #define MEMORY_LOG */
+
+/* For tagging memory, below is the type of the memory. */
+enum
+{
+  MTYPE_TMP = 1,
+  MTYPE_STRVEC,
+  MTYPE_VECTOR,
+  MTYPE_VECTOR_INDEX,
+  MTYPE_LINK_LIST,
+  MTYPE_LINK_NODE,
+  MTYPE_THREAD,
+  MTYPE_THREAD_MASTER,
+  MTYPE_VTY,
+  MTYPE_VTY_HIST,
+  MTYPE_VTY_OUT_BUF,
+  MTYPE_IF,
+  MTYPE_CONNECTED,
+  MTYPE_AS_SEG,
+  MTYPE_AS_STR,
+  MTYPE_AS_PATH,
+  MTYPE_CLUSTER,
+  MTYPE_CLUSTER_VAL,
+  MTYPE_ATTR,
+  MTYPE_TRANSIT,
+  MTYPE_TRANSIT_VAL,
+  MTYPE_BUFFER,
+  MTYPE_BUFFER_DATA,
+  MTYPE_STREAM,
+  MTYPE_STREAM_DATA,
+  MTYPE_STREAM_FIFO,
+  MTYPE_PREFIX,
+  MTYPE_PREFIX_IPV4,
+  MTYPE_PREFIX_IPV6,
+  MTYPE_HASH,
+  MTYPE_HASH_INDEX,
+  MTYPE_HASH_BACKET,
+  MTYPE_RIPNG_ROUTE,
+  MTYPE_RIPNG_AGGREGATE,
+  MTYPE_ROUTE_TABLE,
+  MTYPE_ROUTE_NODE,
+  MTYPE_ACCESS_LIST,
+  MTYPE_ACCESS_LIST_STR,
+  MTYPE_ACCESS_FILTER,
+  MTYPE_PREFIX_LIST,
+  MTYPE_PREFIX_LIST_STR,
+  MTYPE_PREFIX_LIST_ENTRY,
+  MTYPE_ROUTE_MAP,
+  MTYPE_ROUTE_MAP_NAME,
+  MTYPE_ROUTE_MAP_INDEX,
+  MTYPE_ROUTE_MAP_RULE,
+  MTYPE_ROUTE_MAP_RULE_STR,
+  MTYPE_ROUTE_MAP_COMPILED,
+
+  MTYPE_RIB,
+  MTYPE_DISTRIBUTE,
+  MTYPE_ZLOG,
+  MTYPE_ZCLIENT,
+  MTYPE_NEXTHOP,
+  MTYPE_RTADV_PREFIX,
+  MTYPE_IF_RMAP,
+  MTYPE_SOCKUNION,
+  MTYPE_STATIC_IPV4,
+  MTYPE_STATIC_IPV6,
+
+  MTYPE_DESC,
+  MTYPE_OSPF_TOP,
+  MTYPE_OSPF_AREA,
+  MTYPE_OSPF_AREA_RANGE,
+  MTYPE_OSPF_NETWORK,
+  MTYPE_OSPF_NEIGHBOR_STATIC,
+  MTYPE_OSPF_IF,
+  MTYPE_OSPF_NEIGHBOR,
+  MTYPE_OSPF_ROUTE,
+  MTYPE_OSPF_TMP,
+  MTYPE_OSPF_LSA,
+  MTYPE_OSPF_LSA_DATA,
+  MTYPE_OSPF_LSDB,
+  MTYPE_OSPF_PACKET,
+  MTYPE_OSPF_FIFO,
+  MTYPE_OSPF_VERTEX,
+  MTYPE_OSPF_NEXTHOP,
+  MTYPE_OSPF_PATH,
+  MTYPE_OSPF_VL_DATA,
+  MTYPE_OSPF_CRYPT_KEY,
+  MTYPE_OSPF_EXTERNAL_INFO,
+  MTYPE_OSPF_MESSAGE,
+  MTYPE_OSPF_DISTANCE,
+  MTYPE_OSPF_IF_INFO,
+  MTYPE_OSPF_IF_PARAMS,
+
+  MTYPE_OSPF6_TOP,
+  MTYPE_OSPF6_AREA,
+  MTYPE_OSPF6_IF,
+  MTYPE_OSPF6_NEIGHBOR,
+  MTYPE_OSPF6_ROUTE,
+  MTYPE_OSPF6_PREFIX,
+  MTYPE_OSPF6_MESSAGE,
+  MTYPE_OSPF6_LSA,
+  MTYPE_OSPF6_LSA_SUMMARY,
+  MTYPE_OSPF6_LSDB,
+  MTYPE_OSPF6_VERTEX,
+  MTYPE_OSPF6_SPFTREE,
+  MTYPE_OSPF6_NEXTHOP,
+  MTYPE_OSPF6_EXTERNAL_INFO,
+  MTYPE_OSPF6_OTHER,
+
+  MTYPE_BGP,
+  MTYPE_BGP_PEER,
+  MTYPE_PEER_GROUP,
+  MTYPE_PEER_DESC,
+  MTYPE_PEER_UPDATE_SOURCE,
+  MTYPE_BGP_STATIC,
+  MTYPE_BGP_AGGREGATE,
+  MTYPE_BGP_CONFED_LIST,
+  MTYPE_BGP_NEXTHOP_CACHE,
+  MTYPE_BGP_DAMP_INFO,
+  MTYPE_BGP_DAMP_ARRAY,
+  MTYPE_BGP_ANNOUNCE,
+  MTYPE_BGP_ATTR_QUEUE,
+  MTYPE_BGP_ROUTE_QUEUE,
+  MTYPE_BGP_DISTANCE,
+  MTYPE_BGP_ROUTE,
+  MTYPE_BGP_TABLE,
+  MTYPE_BGP_NODE,
+  MTYPE_BGP_ADVERTISE_ATTR,
+  MTYPE_BGP_ADVERTISE,
+  MTYPE_BGP_ADJ_IN,
+  MTYPE_BGP_ADJ_OUT,
+  MTYPE_BGP_REGEXP,
+  MTYPE_AS_FILTER,
+  MTYPE_AS_FILTER_STR,
+  MTYPE_AS_LIST,
+
+  MTYPE_COMMUNITY,
+  MTYPE_COMMUNITY_VAL,
+  MTYPE_COMMUNITY_STR,
+
+  MTYPE_ECOMMUNITY,
+  MTYPE_ECOMMUNITY_VAL,
+  MTYPE_ECOMMUNITY_STR,
+
+  /* community-list and extcommunity-list.  */
+  MTYPE_COMMUNITY_LIST_HANDLER,
+  MTYPE_COMMUNITY_LIST,
+  MTYPE_COMMUNITY_LIST_NAME,
+  MTYPE_COMMUNITY_LIST_ENTRY,
+  MTYPE_COMMUNITY_LIST_CONFIG,
+
+  MTYPE_RIP,
+  MTYPE_RIP_INTERFACE,
+  MTYPE_RIP_DISTANCE,
+  MTYPE_RIP_OFFSET_LIST,
+  MTYPE_RIP_INFO,
+  MTYPE_RIP_PEER,
+  MTYPE_KEYCHAIN,
+  MTYPE_KEY,
+
+  MTYPE_VTYSH_CONFIG,
+  MTYPE_VTYSH_CONFIG_LINE,
+
+  MTYPE_VRF,
+  MTYPE_VRF_NAME,
+
+  MTYPE_MAX
+};
+
+#ifdef MEMORY_LOG
+#define XMALLOC(mtype, size) \
+  mtype_zmalloc (__FILE__, __LINE__, (mtype), (size))
+#define XCALLOC(mtype, size) \
+  mtype_zcalloc (__FILE__, __LINE__, (mtype), (size))
+#define XREALLOC(mtype, ptr, size)  \
+  mtype_zrealloc (__FILE__, __LINE__, (mtype), (ptr), (size))
+#define XFREE(mtype, ptr) \
+  mtype_zfree (__FILE__, __LINE__, (mtype), (ptr))
+#define XSTRDUP(mtype, str) \
+  mtype_zstrdup (__FILE__, __LINE__, (mtype), (str))
+#else
+#define XMALLOC(mtype, size)       zmalloc ((mtype), (size))
+#define XCALLOC(mtype, size)       zcalloc ((mtype), (size))
+#define XREALLOC(mtype, ptr, size) zrealloc ((mtype), (ptr), (size))
+#define XFREE(mtype, ptr)          zfree ((mtype), (ptr))
+#define XSTRDUP(mtype, str)        zstrdup ((mtype), (str))
+#endif /* MEMORY_LOG */
+
+/* Prototypes of memory function. */
+void *zmalloc (int type, size_t size);
+void *zcalloc (int type, size_t size);
+void *zrealloc (int type, void *ptr, size_t size);
+void  zfree (int type, void *ptr);
+char *zstrdup (int type, char *str);
+
+void *mtype_zmalloc (const char *file,
+		     int line,
+		     int type,
+		     size_t size);
+
+void *mtype_zcalloc (const char *file,
+		     int line,
+		     int type,
+		     size_t num,
+		     size_t size);
+
+void *mtype_zrealloc (const char *file,
+		     int line,
+		     int type, 
+		     void *ptr,
+		     size_t size);
+
+void mtype_zfree (const char *file,
+		  int line,
+		  int type,
+		  void *ptr);
+
+char *mtype_zstrdup (const char *file,
+		     int line,
+		     int type,
+		     char *str);
+void memory_init ();
+
+#endif /* _ZEBRA_MEMORY_H */
diff --git a/lib/network.c b/lib/network.c
new file mode 100644
index 0000000..b68761b
--- /dev/null
+++ b/lib/network.c
@@ -0,0 +1,71 @@
+/*
+ * Network library.
+ * Copyright (C) 1997 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.  
+ */
+
+#include <zebra.h>
+
+/* Read nbytes from fd and store into ptr. */
+int
+readn (int fd, char *ptr, int nbytes)
+{
+  int nleft;
+  int nread;
+
+  nleft = nbytes;
+
+  while (nleft > 0) 
+    {
+      nread = read (fd, ptr, nleft);
+
+      if (nread < 0) 
+	return (nread);
+      else
+	if (nread == 0) 
+	  break;
+
+      nleft -= nread;
+      ptr += nread;
+    }
+
+  return nbytes - nleft;
+}  
+
+/* Write nbytes from ptr to fd. */
+int
+writen(int fd, char *ptr, int nbytes)
+{
+  int nleft;
+  int nwritten;
+
+  nleft = nbytes;
+
+  while (nleft > 0) 
+    {
+      nwritten = write(fd, ptr, nleft);
+      
+      if (nwritten <= 0) 
+	return (nwritten);
+
+      nleft -= nwritten;
+      ptr += nwritten;
+    }
+  return nbytes - nleft;
+}
diff --git a/lib/network.h b/lib/network.h
new file mode 100644
index 0000000..a021295
--- /dev/null
+++ b/lib/network.h
@@ -0,0 +1,29 @@
+/*
+ * Network library header.
+ * Copyright (C) 1998 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 _ZEBRA_NETWORK_H
+#define _ZEBRA_NETWORK_H
+
+int readn (int, char *, int);
+int writen (int, char *, int);
+
+#endif /* _ZEBRA_NETWORK_H */
diff --git a/lib/pid_output.c b/lib/pid_output.c
new file mode 100644
index 0000000..4146244
--- /dev/null
+++ b/lib/pid_output.c
@@ -0,0 +1,77 @@
+/*
+ * Process id output.
+ * Copyright (C) 1998, 1999 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.  
+ */
+
+#include <zebra.h>
+
+pid_t
+pid_output (char *path)
+{
+  FILE *fp;
+  pid_t pid;
+
+  pid = getpid();
+
+  fp = fopen (path, "w");
+  if (fp != NULL) 
+    {
+      fprintf (fp, "%d\n", (int) pid);
+      fclose (fp);
+      return -1;
+    }
+  return pid;
+}
+
+pid_t
+pid_output_lock (char *path)
+{
+  int tmp;
+  int fd;
+  pid_t pid;
+  char buf[16], *p;
+
+  pid = getpid ();
+
+  fd = open (path, O_RDWR | O_CREAT | O_EXCL, 0644);
+  if (fd < 0)
+    {
+      fd = open (path, O_RDONLY);
+      if (fd < 0)
+        fprintf (stderr, "Can't creat pid lock file, exit\n");
+      else
+        {
+          read (fd, buf, sizeof (buf));
+          if ((p = index (buf, '\n')) != NULL)
+            *p = 0;
+          fprintf (stderr, "Another process(%s) running, exit\n", buf);
+        }
+      exit (-1);
+    }
+  else
+    {
+      sprintf (buf, "%d\n", (int) pid);
+      tmp = write (fd, buf, strlen (buf));
+      close (fd);
+    }
+
+  return pid;
+}
+
diff --git a/lib/plist.c b/lib/plist.c
new file mode 100644
index 0000000..c2aeea5
--- /dev/null
+++ b/lib/plist.c
@@ -0,0 +1,2881 @@
+/* Prefix list functions.
+ * Copyright (C) 1999 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.
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "command.h"
+#include "memory.h"
+#include "plist.h"
+#include "sockunion.h"
+#include "buffer.h"
+
+/* Each prefix-list's entry. */
+struct prefix_list_entry
+{
+  int seq;
+
+  int le;
+  int ge;
+
+  enum prefix_list_type type;
+
+  int any;
+  struct prefix prefix;
+
+  unsigned long refcnt;
+  unsigned long hitcnt;
+
+  struct prefix_list_entry *next;
+  struct prefix_list_entry *prev;
+};
+
+/* List of struct prefix_list. */
+struct prefix_list_list
+{
+  struct prefix_list *head;
+  struct prefix_list *tail;
+};
+
+/* Master structure of prefix_list. */
+struct prefix_master
+{
+  /* List of prefix_list which name is number. */
+  struct prefix_list_list num;
+
+  /* List of prefix_list which name is string. */
+  struct prefix_list_list str;
+
+  /* Whether sequential number is used. */
+  int seqnum;
+
+  /* The latest update. */
+  struct prefix_list *recent;
+
+  /* Hook function which is executed when new prefix_list is added. */
+  void (*add_hook) ();
+
+  /* Hook function which is executed when prefix_list is deleted. */
+  void (*delete_hook) ();
+};
+
+/* Static structure of IPv4 prefix_list's master. */
+static struct prefix_master prefix_master_ipv4 = 
+{ 
+  {NULL, NULL},
+  {NULL, NULL},
+  1,
+  NULL,
+  NULL,
+};
+
+#ifdef HAVE_IPV6
+/* Static structure of IPv6 prefix-list's master. */
+static struct prefix_master prefix_master_ipv6 = 
+{ 
+  {NULL, NULL},
+  {NULL, NULL},
+  1,
+  NULL,
+  NULL,
+};
+#endif /* HAVE_IPV6*/
+
+/* Static structure of BGP ORF prefix_list's master. */
+static struct prefix_master prefix_master_orf = 
+{ 
+  {NULL, NULL},
+  {NULL, NULL},
+  1,
+  NULL,
+  NULL,
+};
+
+struct prefix_master *
+prefix_master_get (afi_t afi)
+{
+  if (afi == AFI_IP)
+    return &prefix_master_ipv4;
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    return &prefix_master_ipv6;
+#endif /* HAVE_IPV6 */
+  else if (afi == AFI_ORF_PREFIX)
+    return &prefix_master_orf;
+  return NULL;
+}
+
+/* Lookup prefix_list from list of prefix_list by name. */
+struct prefix_list *
+prefix_list_lookup (afi_t afi, char *name)
+{
+  struct prefix_list *plist;
+  struct prefix_master *master;
+
+  if (name == NULL)
+    return NULL;
+
+  master = prefix_master_get (afi);
+  if (master == NULL)
+    return NULL;
+
+  for (plist = master->num.head; plist; plist = plist->next)
+    if (strcmp (plist->name, name) == 0)
+      return plist;
+
+  for (plist = master->str.head; plist; plist = plist->next)
+    if (strcmp (plist->name, name) == 0)
+      return plist;
+
+  return NULL;
+}
+
+struct prefix_list *
+prefix_list_new ()
+{
+  struct prefix_list *new;
+
+  new = XCALLOC (MTYPE_PREFIX_LIST, sizeof (struct prefix_list));
+  return new;
+}
+
+void
+prefix_list_free (struct prefix_list *plist)
+{
+  XFREE (MTYPE_PREFIX_LIST, plist);
+}
+
+struct prefix_list_entry *
+prefix_list_entry_new ()
+{
+  struct prefix_list_entry *new;
+
+  new = XCALLOC (MTYPE_PREFIX_LIST_ENTRY, sizeof (struct prefix_list_entry));
+  return new;
+}
+
+void
+prefix_list_entry_free (struct prefix_list_entry *pentry)
+{
+  XFREE (MTYPE_PREFIX_LIST_ENTRY, pentry);
+}
+
+/* Insert new prefix list to list of prefix_list.  Each prefix_list
+   is sorted by the name. */
+struct prefix_list *
+prefix_list_insert (afi_t afi, char *name)
+{
+  int i;
+  long number;
+  struct prefix_list *plist;
+  struct prefix_list *point;
+  struct prefix_list_list *list;
+  struct prefix_master *master;
+
+  master = prefix_master_get (afi);
+  if (master == NULL)
+    return NULL;
+
+  /* Allocate new prefix_list and copy given name. */
+  plist = prefix_list_new ();
+  plist->name = XSTRDUP (MTYPE_PREFIX_LIST_STR, name);
+  plist->master = master;
+
+  /* If name is made by all digit character.  We treat it as
+     number. */
+  for (number = 0, i = 0; i < strlen (name); i++)
+    {
+      if (isdigit ((int) name[i]))
+	number = (number * 10) + (name[i] - '0');
+      else
+	break;
+    }
+
+  /* In case of name is all digit character */
+  if (i == strlen (name))
+    {
+      plist->type = PREFIX_TYPE_NUMBER;
+
+      /* Set prefix_list to number list. */
+      list = &master->num;
+
+      for (point = list->head; point; point = point->next)
+	if (atol (point->name) >= number)
+	  break;
+    }
+  else
+    {
+      plist->type = PREFIX_TYPE_STRING;
+
+      /* Set prefix_list to string list. */
+      list = &master->str;
+  
+      /* Set point to insertion point. */
+      for (point = list->head; point; point = point->next)
+	if (strcmp (point->name, name) >= 0)
+	  break;
+    }
+
+  /* In case of this is the first element of master. */
+  if (list->head == NULL)
+    {
+      list->head = list->tail = plist;
+      return plist;
+    }
+
+  /* In case of insertion is made at the tail of access_list. */
+  if (point == NULL)
+    {
+      plist->prev = list->tail;
+      list->tail->next = plist;
+      list->tail = plist;
+      return plist;
+    }
+
+  /* In case of insertion is made at the head of access_list. */
+  if (point == list->head)
+    {
+      plist->next = list->head;
+      list->head->prev = plist;
+      list->head = plist;
+      return plist;
+    }
+
+  /* Insertion is made at middle of the access_list. */
+  plist->next = point;
+  plist->prev = point->prev;
+
+  if (point->prev)
+    point->prev->next = plist;
+  point->prev = plist;
+
+  return plist;
+}
+
+struct prefix_list *
+prefix_list_get (afi_t afi, char *name)
+{
+  struct prefix_list *plist;
+
+  plist = prefix_list_lookup (afi, name);
+
+  if (plist == NULL)
+    plist = prefix_list_insert (afi, name);
+  return plist;
+}
+
+/* Delete prefix-list from prefix_list_master and free it. */
+void
+prefix_list_delete (struct prefix_list *plist)
+{
+  struct prefix_list_list *list;
+  struct prefix_master *master;
+  struct prefix_list_entry *pentry;
+  struct prefix_list_entry *next;
+
+  /* If prefix-list contain prefix_list_entry free all of it. */
+  for (pentry = plist->head; pentry; pentry = next)
+    {
+      next = pentry->next;
+      prefix_list_entry_free (pentry);
+      plist->count--;
+    }
+
+  master = plist->master;
+
+  if (plist->type == PREFIX_TYPE_NUMBER)
+    list = &master->num;
+  else
+    list = &master->str;
+
+  if (plist->next)
+    plist->next->prev = plist->prev;
+  else
+    list->tail = plist->prev;
+
+  if (plist->prev)
+    plist->prev->next = plist->next;
+  else
+    list->head = plist->next;
+
+  if (plist->desc)
+    XFREE (MTYPE_TMP, plist->desc);
+
+  /* Make sure master's recent changed prefix-list information is
+     cleared. */
+  master->recent = NULL;
+
+  if (plist->name)
+    XFREE (MTYPE_PREFIX_LIST_STR, plist->name);
+
+  prefix_list_free (plist);
+
+  if (master->delete_hook)
+    (*master->delete_hook) ();
+}
+
+struct prefix_list_entry *
+prefix_list_entry_make (struct prefix *prefix, enum prefix_list_type type,
+			int seq, int le, int ge, int any)
+{
+  struct prefix_list_entry *pentry;
+
+  pentry = prefix_list_entry_new ();
+
+  if (any)
+    pentry->any = 1;
+
+  prefix_copy (&pentry->prefix, prefix);
+  pentry->type = type;
+  pentry->seq = seq;
+  pentry->le = le;
+  pentry->ge = ge;
+
+  return pentry;
+}
+
+/* Add hook function. */
+void
+prefix_list_add_hook (void (*func) (struct prefix_list *plist))
+{
+  prefix_master_ipv4.add_hook = func;
+#ifdef HAVE_IPV6
+  prefix_master_ipv6.add_hook = func;
+#endif /* HAVE_IPV6 */
+}
+
+/* Delete hook function. */
+void
+prefix_list_delete_hook (void (*func) (struct prefix_list *plist))
+{
+  prefix_master_ipv4.delete_hook = func;
+#ifdef HAVE_IPV6
+  prefix_master_ipv6.delete_hook = func;
+#endif /* HAVE_IPVt6 */
+}
+
+/* Calculate new sequential number. */
+int
+prefix_new_seq_get (struct prefix_list *plist)
+{
+  int maxseq;
+  int newseq;
+  struct prefix_list_entry *pentry;
+
+  maxseq = newseq = 0;
+
+  for (pentry = plist->head; pentry; pentry = pentry->next)
+    {
+      if (maxseq < pentry->seq)
+	maxseq = pentry->seq;
+    }
+
+  newseq = ((maxseq / 5) * 5) + 5;
+  
+  return newseq;
+}
+
+/* Return prefix list entry which has same seq number. */
+struct prefix_list_entry *
+prefix_seq_check (struct prefix_list *plist, int seq)
+{
+  struct prefix_list_entry *pentry;
+
+  for (pentry = plist->head; pentry; pentry = pentry->next)
+    if (pentry->seq == seq)
+      return pentry;
+  return NULL;
+}
+
+struct prefix_list_entry *
+prefix_list_entry_lookup (struct prefix_list *plist, struct prefix *prefix,
+			  enum prefix_list_type type, int seq, int le, int ge)
+{
+  struct prefix_list_entry *pentry;
+
+  for (pentry = plist->head; pentry; pentry = pentry->next)
+    if (prefix_same (&pentry->prefix, prefix) && pentry->type == type)
+      {
+	if (seq >= 0 && pentry->seq != seq)
+	  continue;
+
+	if (pentry->le != le)
+	  continue;
+	if (pentry->ge != ge)
+	  continue;
+
+	return pentry;
+      }
+
+  return NULL;
+}
+
+void
+prefix_list_entry_delete (struct prefix_list *plist, 
+			  struct prefix_list_entry *pentry,
+			  int update_list)
+{
+  if (plist == NULL || pentry == NULL)
+    return;
+  if (pentry->prev)
+    pentry->prev->next = pentry->next;
+  else
+    plist->head = pentry->next;
+  if (pentry->next)
+    pentry->next->prev = pentry->prev;
+  else
+    plist->tail = pentry->prev;
+
+  prefix_list_entry_free (pentry);
+
+  plist->count--;
+
+  if (update_list)
+    {
+      if (plist->master->delete_hook)
+	(*plist->master->delete_hook) (plist);
+
+      if (plist->head == NULL && plist->tail == NULL && plist->desc == NULL)
+	prefix_list_delete (plist);
+      else
+	plist->master->recent = plist;
+    }
+}
+
+void
+prefix_list_entry_add (struct prefix_list *plist,
+		       struct prefix_list_entry *pentry)
+{
+  struct prefix_list_entry *replace;
+  struct prefix_list_entry *point;
+
+  /* Automatic asignment of seq no. */
+  if (pentry->seq == -1)
+    pentry->seq = prefix_new_seq_get (plist);
+
+  /* Is there any same seq prefix list entry? */
+  replace = prefix_seq_check (plist, pentry->seq);
+  if (replace)
+    prefix_list_entry_delete (plist, replace, 0);
+
+  /* Check insert point. */
+  for (point = plist->head; point; point = point->next)
+    if (point->seq >= pentry->seq)
+      break;
+
+  /* In case of this is the first element of the list. */
+  pentry->next = point;
+
+  if (point)
+    {
+      if (point->prev)
+	point->prev->next = pentry;
+      else
+	plist->head = pentry;
+
+      pentry->prev = point->prev;
+      point->prev = pentry;
+    }
+  else
+    {
+      if (plist->tail)
+	plist->tail->next = pentry;
+      else
+	plist->head = pentry;
+
+      pentry->prev = plist->tail;
+      plist->tail = pentry;
+    }
+
+  /* Increment count. */
+  plist->count++;
+
+  /* Run hook function. */
+  if (plist->master->add_hook)
+    (*plist->master->add_hook) (plist);
+
+  plist->master->recent = plist;
+}
+
+/* Return string of prefix_list_type. */
+static char *
+prefix_list_type_str (struct prefix_list_entry *pentry)
+{
+  switch (pentry->type)
+    {
+    case PREFIX_PERMIT:
+      return "permit";
+      break;
+    case PREFIX_DENY:
+      return "deny";
+      break;
+    default:
+      return "";
+      break;
+    }
+}
+
+int
+prefix_list_entry_match (struct prefix_list_entry *pentry, struct prefix *p)
+{
+  int ret;
+
+  ret = prefix_match (&pentry->prefix, p);
+  if (! ret)
+    return 0;
+  
+  /* In case of le nor ge is specified, exact match is performed. */
+  if (! pentry->le && ! pentry->ge)
+    {
+      if (pentry->prefix.prefixlen != p->prefixlen)
+	return 0;
+    }
+  else
+    {  
+      if (pentry->le)
+	if (p->prefixlen > pentry->le)
+	  return 0;
+
+      if (pentry->ge)
+	if (p->prefixlen < pentry->ge)
+	  return 0;
+    }
+  return 1;
+}
+
+enum prefix_list_type
+prefix_list_apply (struct prefix_list *plist, void *object)
+{
+  struct prefix_list_entry *pentry;
+  struct prefix *p;
+
+  p = (struct prefix *) object;
+
+  if (plist == NULL)
+    return PREFIX_DENY;
+
+  if (plist->count == 0)
+    return PREFIX_PERMIT;
+
+  for (pentry = plist->head; pentry; pentry = pentry->next)
+    {
+      pentry->refcnt++;
+      if (prefix_list_entry_match (pentry, p))
+	{
+	  pentry->hitcnt++;
+	  return pentry->type;
+	}
+    }
+
+  return PREFIX_DENY;
+}
+
+void
+prefix_list_print (struct prefix_list *plist)
+{
+  struct prefix_list_entry *pentry;
+
+  if (plist == NULL)
+    return;
+
+  printf ("ip prefix-list %s: %d entries\n", plist->name, plist->count);
+
+  for (pentry = plist->head; pentry; pentry = pentry->next)
+    {
+      if (pentry->any)
+	printf ("any %s\n", prefix_list_type_str (pentry));
+      else
+	{
+	  struct prefix *p;
+	  char buf[BUFSIZ];
+	  
+	  p = &pentry->prefix;
+	  
+	  printf ("  seq %d %s %s/%d", 
+		  pentry->seq,
+		  prefix_list_type_str (pentry),
+		  inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+		  p->prefixlen);
+	  if (pentry->ge)
+	    printf (" ge %d", pentry->ge);
+	  if (pentry->le)
+	    printf (" le %d", pentry->le);
+	  printf ("\n");
+	}
+    }
+}
+
+/* Retrun 1 when plist already include pentry policy. */
+struct prefix_list_entry *
+prefix_entry_dup_check (struct prefix_list *plist,
+			struct prefix_list_entry *new)
+{
+  struct prefix_list_entry *pentry;
+  int seq = 0;
+
+  if (new->seq == -1)
+    seq = prefix_new_seq_get (plist);
+  else
+    seq = new->seq;
+
+  for (pentry = plist->head; pentry; pentry = pentry->next)
+    {
+      if (prefix_same (&pentry->prefix, &new->prefix)
+	  && pentry->type == new->type
+	  && pentry->le == new->le
+	  && pentry->ge == new->ge
+	  && pentry->seq != seq)
+	return pentry;
+    }
+  return NULL;
+}
+
+int
+vty_invalid_prefix_range (struct vty *vty, char *prefix)
+{
+  vty_out (vty, "%% Invalid prefix range for %s, make sure: len < ge-value <= le-value%s",
+           prefix, VTY_NEWLINE);
+  return CMD_WARNING;
+}
+
+int
+vty_prefix_list_install (struct vty *vty, afi_t afi,
+			 char *name, char *seq, char *typestr,
+			 char *prefix, char *ge, char *le)
+{
+  int ret;
+  enum prefix_list_type type;
+  struct prefix_list *plist;
+  struct prefix_list_entry *pentry;
+  struct prefix_list_entry *dup;
+  struct prefix p;
+  int any = 0;
+  int seqnum = -1;
+  int lenum = 0;
+  int genum = 0;
+
+  /* Sequential number. */
+  if (seq)
+    seqnum = atoi (seq);
+
+  /* ge and le number */
+  if (ge)
+    genum = atoi (ge);
+  if (le)
+    lenum = atoi (le);
+
+  /* Check filter type. */
+  if (strncmp ("permit", typestr, 1) == 0)
+    type = PREFIX_PERMIT;
+  else if (strncmp ("deny", typestr, 1) == 0)
+    type = PREFIX_DENY;
+  else
+    {
+      vty_out (vty, "%% prefix type must be permit or deny%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* "any" is special token for matching any IPv4 addresses.  */
+  if (afi == AFI_IP)
+    {
+      if (strncmp ("any", prefix, strlen (prefix)) == 0)
+	{
+	  ret = str2prefix_ipv4 ("0.0.0.0/0", (struct prefix_ipv4 *) &p);
+	  genum = 0;
+	  lenum = IPV4_MAX_BITLEN;
+	  any = 1;
+	}
+      else
+	ret = str2prefix_ipv4 (prefix, (struct prefix_ipv4 *) &p);
+
+      if (ret <= 0)
+	{
+	  vty_out (vty, "%% Malformed IPv4 prefix%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    {
+      if (strncmp ("any", prefix, strlen (prefix)) == 0)
+	{
+	  ret = str2prefix_ipv6 ("::/0", (struct prefix_ipv6 *) &p);
+	  genum = 0;
+	  lenum = IPV6_MAX_BITLEN;
+	  any = 1;
+	}
+      else
+	ret = str2prefix_ipv6 (prefix, (struct prefix_ipv6 *) &p);
+
+      if (ret <= 0)
+	{
+	  vty_out (vty, "%% Malformed IPv6 prefix%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+#endif /* HAVE_IPV6 */
+
+  /* ge and le check. */
+  if (genum && genum <= p.prefixlen)
+    return vty_invalid_prefix_range (vty, prefix);
+
+  if (lenum && lenum <= p.prefixlen)
+    return vty_invalid_prefix_range (vty, prefix);
+
+  if (lenum && genum > lenum)
+    return vty_invalid_prefix_range (vty, prefix);
+
+  if (genum && lenum == (afi == AFI_IP ? 32 : 128))
+    lenum = 0;
+
+  /* Get prefix_list with name. */
+  plist = prefix_list_get (afi, name);
+
+  /* Make prefix entry. */
+  pentry = prefix_list_entry_make (&p, type, seqnum, lenum, genum, any);
+    
+  /* Check same policy. */
+  dup = prefix_entry_dup_check (plist, pentry);
+
+  if (dup)
+    {
+      prefix_list_entry_free (pentry);
+      vty_out (vty, "%% Insertion failed - prefix-list entry exists:%s",
+	       VTY_NEWLINE);
+      vty_out (vty, "   seq %d %s %s", dup->seq, typestr, prefix);
+      if (! any && genum)
+	vty_out (vty, " ge %d", genum);
+      if (! any && lenum)
+	vty_out (vty, " le %d", lenum);
+      vty_out (vty, "%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Install new filter to the access_list. */
+  prefix_list_entry_add (plist, pentry);
+
+  return CMD_SUCCESS;
+}
+
+int
+vty_prefix_list_uninstall (struct vty *vty, afi_t afi,
+			   char *name, char *seq, char *typestr,
+			   char *prefix, char *ge, char *le)
+{
+  int ret;
+  enum prefix_list_type type;
+  struct prefix_list *plist;
+  struct prefix_list_entry *pentry;
+  struct prefix p;
+  int seqnum = -1;
+  int lenum = 0;
+  int genum = 0;
+
+  /* Check prefix list name. */
+  plist = prefix_list_lookup (afi, name);
+  if (! plist)
+    {
+      vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Only prefix-list name specified, delete the entire prefix-list. */
+  if (seq == NULL && typestr == NULL && prefix == NULL && 
+      ge == NULL && le == NULL)
+    {
+      prefix_list_delete (plist);
+      return CMD_SUCCESS;
+    }
+
+  /* Check sequence number. */
+  if (seq)
+    seqnum = atoi (seq);
+
+  /* ge and le number */
+  if (ge)
+    genum = atoi (ge);
+  if (le)
+    lenum = atoi (le);
+
+  /* Check of filter type. */
+  if (strncmp ("permit", typestr, 1) == 0)
+    type = PREFIX_PERMIT;
+  else if (strncmp ("deny", typestr, 1) == 0)
+    type = PREFIX_DENY;
+  else
+    {
+      vty_out (vty, "%% prefix type must be permit or deny%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* "any" is special token for matching any IPv4 addresses.  */
+  if (afi == AFI_IP)
+    {
+      if (strncmp ("any", prefix, strlen (prefix)) == 0)
+	{
+	  ret = str2prefix_ipv4 ("0.0.0.0/0", (struct prefix_ipv4 *) &p);
+	  genum = 0;
+	  lenum = IPV4_MAX_BITLEN;
+	}
+      else
+	ret = str2prefix_ipv4 (prefix, (struct prefix_ipv4 *) &p);
+
+      if (ret <= 0)
+	{
+	  vty_out (vty, "%% Malformed IPv4 prefix%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    {
+      if (strncmp ("any", prefix, strlen (prefix)) == 0)
+	{
+	  ret = str2prefix_ipv6 ("::/0", (struct prefix_ipv6 *) &p);
+	  genum = 0;
+	  lenum = IPV6_MAX_BITLEN;
+	}
+      else
+	ret = str2prefix_ipv6 (prefix, (struct prefix_ipv6 *) &p);
+
+      if (ret <= 0)
+	{
+	  vty_out (vty, "%% Malformed IPv6 prefix%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+#endif /* HAVE_IPV6 */
+
+  /* Lookup prefix entry. */
+  pentry = prefix_list_entry_lookup(plist, &p, type, seqnum, lenum, genum);
+
+  if (pentry == NULL)
+    {
+      vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Install new filter to the access_list. */
+  prefix_list_entry_delete (plist, pentry, 1);
+
+  return CMD_SUCCESS;
+}
+
+int
+vty_prefix_list_desc_unset (struct vty *vty, afi_t afi, char *name)
+{
+  struct prefix_list *plist;
+
+  plist = prefix_list_lookup (afi, name);
+  if (! plist)
+    {
+      vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (plist->desc)
+    {
+      XFREE (MTYPE_TMP, plist->desc);
+      plist->desc = NULL;
+    }
+
+  if (plist->head == NULL && plist->tail == NULL && plist->desc == NULL)
+    prefix_list_delete (plist);
+
+  return CMD_SUCCESS;
+}
+
+enum display_type
+{
+  normal_display,
+  summary_display,
+  detail_display,
+  sequential_display,
+  longer_display,
+  first_match_display
+};
+
+void
+vty_show_prefix_entry (struct vty *vty, afi_t afi, struct prefix_list *plist,
+		       struct prefix_master *master, enum display_type dtype,
+		       int seqnum)
+{
+  struct prefix_list_entry *pentry;
+
+  if (dtype == normal_display)
+    {
+      vty_out (vty, "ip%s prefix-list %s: %d entries%s",
+	       afi == AFI_IP ? "" : "v6",
+	       plist->name, plist->count, VTY_NEWLINE);
+      if (plist->desc)
+	vty_out (vty, "   Description: %s%s", plist->desc, VTY_NEWLINE);
+    }
+  else if (dtype == summary_display || dtype == detail_display)
+    {
+      vty_out (vty, "ip%s prefix-list %s:%s",
+	       afi == AFI_IP ? "" : "v6", plist->name, VTY_NEWLINE);
+
+      if (plist->desc)
+	vty_out (vty, "   Description: %s%s", plist->desc, VTY_NEWLINE);
+
+      vty_out (vty, "   count: %d, range entries: %d, sequences: %d - %d%s",
+	       plist->count, plist->rangecount, 
+	       plist->head ? plist->head->seq : 0, 
+	       plist->tail ? plist->tail->seq : 0,
+	       VTY_NEWLINE);
+    }
+
+  if (dtype != summary_display)
+    {
+      for (pentry = plist->head; pentry; pentry = pentry->next)
+	{
+	  if (dtype == sequential_display && pentry->seq != seqnum)
+	    continue;
+	    
+	  vty_out (vty, "   ");
+
+	  if (master->seqnum)
+	    vty_out (vty, "seq %d ", pentry->seq);
+
+	  vty_out (vty, "%s ", prefix_list_type_str (pentry));
+
+	  if (pentry->any)
+	    vty_out (vty, "any");
+	  else
+	    {
+	      struct prefix *p = &pentry->prefix;
+	      char buf[BUFSIZ];
+
+	      vty_out (vty, "%s/%d",
+		       inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+		       p->prefixlen);
+
+	      if (pentry->ge)
+		vty_out (vty, " ge %d", pentry->ge);
+	      if (pentry->le)
+		vty_out (vty, " le %d", pentry->le);
+	    }
+
+	  if (dtype == detail_display || dtype == sequential_display)
+	    vty_out (vty, " (hit count: %ld, refcount: %ld)", 
+		     pentry->hitcnt, pentry->refcnt);
+	  
+	  vty_out (vty, "%s", VTY_NEWLINE);
+	}
+    }
+}
+
+int
+vty_show_prefix_list (struct vty *vty, afi_t afi, char *name,
+		      char *seq, enum display_type dtype)
+{
+  struct prefix_list *plist;
+  struct prefix_master *master;
+  int seqnum = 0;
+
+  master = prefix_master_get (afi);
+  if (master == NULL)
+    return CMD_WARNING;
+
+  if (seq)
+    seqnum = atoi (seq);
+
+  if (name)
+    {
+      plist = prefix_list_lookup (afi, name);
+      if (! plist)
+	{
+	  vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+      vty_show_prefix_entry (vty, afi, plist, master, dtype, seqnum);
+    }
+  else
+    {
+      if (dtype == detail_display || dtype == summary_display)
+	{
+	  if (master->recent)
+	    vty_out (vty, "Prefix-list with the last deletion/insertion: %s%s",
+		     master->recent->name, VTY_NEWLINE);
+	}
+
+      for (plist = master->num.head; plist; plist = plist->next)
+	vty_show_prefix_entry (vty, afi, plist, master, dtype, seqnum);
+
+      for (plist = master->str.head; plist; plist = plist->next)
+	vty_show_prefix_entry (vty, afi, plist, master, dtype, seqnum);
+    }
+
+  return CMD_SUCCESS;
+}
+
+int
+vty_show_prefix_list_prefix (struct vty *vty, afi_t afi, char *name, 
+			     char *prefix, enum display_type type)
+{
+  struct prefix_list *plist;
+  struct prefix_list_entry *pentry;
+  struct prefix p;
+  int ret;
+  int match;
+
+  plist = prefix_list_lookup (afi, name);
+  if (! plist)
+    {
+      vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = str2prefix (prefix, &p);
+  if (ret <= 0)
+    {
+      vty_out (vty, "%% prefix is malformed%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  for (pentry = plist->head; pentry; pentry = pentry->next)
+    {
+      match = 0;
+
+      if (type == normal_display || type == first_match_display)
+	if (prefix_same (&p, &pentry->prefix))
+	  match = 1;
+
+      if (type == longer_display)
+	if (prefix_match (&p, &pentry->prefix))
+	  match = 1;
+
+      if (match)
+	{
+	  vty_out (vty, "   seq %d %s ", 
+		   pentry->seq,
+		   prefix_list_type_str (pentry));
+
+	  if (pentry->any)
+	    vty_out (vty, "any");
+	  else
+	    {
+	      struct prefix *p = &pentry->prefix;
+	      char buf[BUFSIZ];
+	      
+	      vty_out (vty, "%s/%d",
+		       inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+		       p->prefixlen);
+
+	      if (pentry->ge)
+		vty_out (vty, " ge %d", pentry->ge);
+	      if (pentry->le)
+		vty_out (vty, " le %d", pentry->le);
+	    }
+	  
+	  if (type == normal_display || type == first_match_display)
+	    vty_out (vty, " (hit count: %ld, refcount: %ld)", 
+		     pentry->hitcnt, pentry->refcnt);
+
+	  vty_out (vty, "%s", VTY_NEWLINE);
+
+	  if (type == first_match_display)
+	    return CMD_SUCCESS;
+	}
+    }
+  return CMD_SUCCESS;
+}
+
+int
+vty_clear_prefix_list (struct vty *vty, afi_t afi, char *name, char *prefix)
+{
+  struct prefix_master *master;
+  struct prefix_list *plist;
+  struct prefix_list_entry *pentry;
+  int ret;
+  struct prefix p;
+
+  master = prefix_master_get (afi);
+  if (master == NULL)
+    return CMD_WARNING;
+
+  if (name == NULL && prefix == NULL)
+    {
+      for (plist = master->num.head; plist; plist = plist->next)
+	for (pentry = plist->head; pentry; pentry = pentry->next)
+	  pentry->hitcnt = 0;
+
+      for (plist = master->str.head; plist; plist = plist->next)
+	for (pentry = plist->head; pentry; pentry = pentry->next)
+	  pentry->hitcnt = 0;
+    }
+  else
+    {
+      plist = prefix_list_lookup (afi, name);
+      if (! plist)
+	{
+	  vty_out (vty, "%% Can't find specified prefix-list%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+
+      if (prefix)
+	{
+	  ret = str2prefix (prefix, &p);
+	  if (ret <= 0)
+	    {
+	      vty_out (vty, "%% prefix is malformed%s", VTY_NEWLINE);
+	      return CMD_WARNING;
+	    }
+	}
+
+      for (pentry = plist->head; pentry; pentry = pentry->next)
+	{
+	  if (prefix)
+	    {
+	      if (prefix_match (&pentry->prefix, &p))
+		pentry->hitcnt = 0;
+	    }
+	  else
+	    pentry->hitcnt = 0;
+	}
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_prefix_list,
+       ip_prefix_list_cmd,
+       "ip prefix-list WORD (deny|permit) (A.B.C.D/M|any)",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, 
+				  argv[1], argv[2], NULL, NULL);
+}
+
+DEFUN (ip_prefix_list_ge,
+       ip_prefix_list_ge_cmd,
+       "ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32>",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1], 
+				 argv[2], argv[3], NULL);
+}
+
+DEFUN (ip_prefix_list_ge_le,
+       ip_prefix_list_ge_le_cmd,
+       "ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32> le <0-32>",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1], 
+				  argv[2], argv[3], argv[4]);
+}
+
+DEFUN (ip_prefix_list_le,
+       ip_prefix_list_le_cmd,
+       "ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32>",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1],
+				  argv[2], NULL, argv[3]);
+}
+
+DEFUN (ip_prefix_list_le_ge,
+       ip_prefix_list_le_ge_cmd,
+       "ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32> ge <0-32>",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP, argv[0], NULL, argv[1],
+				  argv[2], argv[4], argv[3]);
+}
+
+DEFUN (ip_prefix_list_seq,
+       ip_prefix_list_seq_cmd,
+       "ip prefix-list WORD seq <1-4294967295> (deny|permit) (A.B.C.D/M|any)",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2],
+				  argv[3], NULL, NULL);
+}
+
+DEFUN (ip_prefix_list_seq_ge,
+       ip_prefix_list_seq_ge_cmd,
+       "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32>",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2],
+				  argv[3], argv[4], NULL);
+}
+
+DEFUN (ip_prefix_list_seq_ge_le,
+       ip_prefix_list_seq_ge_le_cmd,
+       "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32> le <0-32>",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2],
+				  argv[3], argv[4], argv[5]);
+}
+
+DEFUN (ip_prefix_list_seq_le,
+       ip_prefix_list_seq_le_cmd,
+       "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32>",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2],
+				  argv[3], NULL, argv[4]);
+}
+
+DEFUN (ip_prefix_list_seq_le_ge,
+       ip_prefix_list_seq_le_ge_cmd,
+       "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32> ge <0-32>",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP, argv[0], argv[1], argv[2],
+				  argv[3], argv[5], argv[4]);
+}
+
+DEFUN (no_ip_prefix_list,
+       no_ip_prefix_list_cmd,
+       "no ip prefix-list WORD",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, NULL,
+				    NULL, NULL, NULL);
+}
+
+DEFUN (no_ip_prefix_list_prefix,
+       no_ip_prefix_list_prefix_cmd,
+       "no ip prefix-list WORD (deny|permit) (A.B.C.D/M|any)",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Any prefix match.  Same as \"0.0.0.0/0 le 32\"\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1],
+				    argv[2], NULL, NULL);
+}
+
+DEFUN (no_ip_prefix_list_ge,
+       no_ip_prefix_list_ge_cmd,
+       "no ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32>",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1],
+				    argv[2], argv[3], NULL);
+}
+
+DEFUN (no_ip_prefix_list_ge_le,
+       no_ip_prefix_list_ge_le_cmd,
+       "no ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32> le <0-32>",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1],
+				    argv[2], argv[3], argv[4]);
+}
+
+DEFUN (no_ip_prefix_list_le,
+       no_ip_prefix_list_le_cmd,
+       "no ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32>",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1],
+				    argv[2], NULL, argv[3]);
+}
+
+DEFUN (no_ip_prefix_list_le_ge,
+       no_ip_prefix_list_le_ge_cmd,
+       "no ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32> ge <0-32>",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], NULL, argv[1],
+				    argv[2], argv[4], argv[3]);
+}
+
+DEFUN (no_ip_prefix_list_seq,
+       no_ip_prefix_list_seq_cmd,
+       "no ip prefix-list WORD seq <1-4294967295> (deny|permit) (A.B.C.D/M|any)",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Any prefix match.  Same as \"0.0.0.0/0 le 32\"\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2],
+				    argv[3], NULL, NULL);
+}
+
+DEFUN (no_ip_prefix_list_seq_ge,
+       no_ip_prefix_list_seq_ge_cmd,
+       "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32>",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2],
+				    argv[3], argv[4], NULL);
+}
+
+DEFUN (no_ip_prefix_list_seq_ge_le,
+       no_ip_prefix_list_seq_ge_le_cmd,
+       "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32> le <0-32>",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2],
+				    argv[3], argv[4], argv[5]);
+}
+
+DEFUN (no_ip_prefix_list_seq_le,
+       no_ip_prefix_list_seq_le_cmd,
+       "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32>",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2],
+				    argv[3], NULL, argv[4]);
+}
+
+DEFUN (no_ip_prefix_list_seq_le_ge,
+       no_ip_prefix_list_seq_le_ge_cmd,
+       "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32> ge <0-32>",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP, argv[0], argv[1], argv[2],
+				    argv[3], argv[5], argv[4]);
+}
+
+DEFUN (ip_prefix_list_sequence_number,
+       ip_prefix_list_sequence_number_cmd,
+       "ip prefix-list sequence-number",
+       IP_STR
+       PREFIX_LIST_STR
+       "Include/exclude sequence numbers in NVGEN\n")
+{
+  prefix_master_ipv4.seqnum = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_prefix_list_sequence_number,
+       no_ip_prefix_list_sequence_number_cmd,
+       "no ip prefix-list sequence-number",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Include/exclude sequence numbers in NVGEN\n")
+{
+  prefix_master_ipv4.seqnum = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_prefix_list_description,
+       ip_prefix_list_description_cmd,
+       "ip prefix-list WORD description .LINE",
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Prefix-list specific description\n"
+       "Up to 80 characters describing this prefix-list\n")
+{
+  struct prefix_list *plist;
+  struct buffer *b;
+  int i;
+
+  plist = prefix_list_get (AFI_IP, argv[0]);
+  
+  if (plist->desc)
+    {
+      XFREE (MTYPE_TMP, plist->desc);
+      plist->desc = NULL;
+    }
+
+  /* Below is description get codes. */
+  b = buffer_new (1024);
+  for (i = 1; i < argc; i++)
+    {
+      buffer_putstr (b, (u_char *)argv[i]);
+      buffer_putc (b, ' ');
+    }
+  buffer_putc (b, '\0');
+
+  plist->desc = buffer_getstr (b);
+
+  buffer_free (b);
+
+  return CMD_SUCCESS;
+}       
+
+DEFUN (no_ip_prefix_list_description,
+       no_ip_prefix_list_description_cmd,
+       "no ip prefix-list WORD description",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Prefix-list specific description\n")
+{
+  return vty_prefix_list_desc_unset (vty, AFI_IP, argv[0]);
+}
+
+ALIAS (no_ip_prefix_list_description,
+       no_ip_prefix_list_description_arg_cmd,
+       "no ip prefix-list WORD description .LINE",
+       NO_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Prefix-list specific description\n"
+       "Up to 80 characters describing this prefix-list\n")
+
+DEFUN (show_ip_prefix_list,
+       show_ip_prefix_list_cmd,
+       "show ip prefix-list",
+       SHOW_STR
+       IP_STR
+       PREFIX_LIST_STR)
+{
+  return vty_show_prefix_list (vty, AFI_IP, NULL, NULL, normal_display);
+}
+
+DEFUN (show_ip_prefix_list_name,
+       show_ip_prefix_list_name_cmd,
+       "show ip prefix-list WORD",
+       SHOW_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP, argv[0], NULL, normal_display);
+}
+
+DEFUN (show_ip_prefix_list_name_seq,
+       show_ip_prefix_list_name_seq_cmd,
+       "show ip prefix-list WORD seq <1-4294967295>",
+       SHOW_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP, argv[0], argv[1], sequential_display);
+}
+
+DEFUN (show_ip_prefix_list_prefix,
+       show_ip_prefix_list_prefix_cmd,
+       "show ip prefix-list WORD A.B.C.D/M",
+       SHOW_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+  return vty_show_prefix_list_prefix (vty, AFI_IP, argv[0], argv[1], normal_display);
+}
+
+DEFUN (show_ip_prefix_list_prefix_longer,
+       show_ip_prefix_list_prefix_longer_cmd,
+       "show ip prefix-list WORD A.B.C.D/M longer",
+       SHOW_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Lookup longer prefix\n")
+{
+  return vty_show_prefix_list_prefix (vty, AFI_IP, argv[0], argv[1], longer_display);
+}
+
+DEFUN (show_ip_prefix_list_prefix_first_match,
+       show_ip_prefix_list_prefix_first_match_cmd,
+       "show ip prefix-list WORD A.B.C.D/M first-match",
+       SHOW_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "First matched prefix\n")
+{
+  return vty_show_prefix_list_prefix (vty, AFI_IP, argv[0], argv[1], first_match_display);
+}
+
+DEFUN (show_ip_prefix_list_summary,
+       show_ip_prefix_list_summary_cmd,
+       "show ip prefix-list summary",
+       SHOW_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Summary of prefix lists\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP, NULL, NULL, summary_display);
+}
+
+DEFUN (show_ip_prefix_list_summary_name,
+       show_ip_prefix_list_summary_name_cmd,
+       "show ip prefix-list summary WORD",
+       SHOW_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Summary of prefix lists\n"
+       "Name of a prefix list\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP, argv[0], NULL, summary_display);
+}
+
+
+DEFUN (show_ip_prefix_list_detail,
+       show_ip_prefix_list_detail_cmd,
+       "show ip prefix-list detail",
+       SHOW_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Detail of prefix lists\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP, NULL, NULL, detail_display);
+}
+
+DEFUN (show_ip_prefix_list_detail_name,
+       show_ip_prefix_list_detail_name_cmd,
+       "show ip prefix-list detail WORD",
+       SHOW_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Detail of prefix lists\n"
+       "Name of a prefix list\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP, argv[0], NULL, detail_display);
+}
+
+DEFUN (clear_ip_prefix_list,
+       clear_ip_prefix_list_cmd,
+       "clear ip prefix-list",
+       CLEAR_STR
+       IP_STR
+       PREFIX_LIST_STR)
+{
+  return vty_clear_prefix_list (vty, AFI_IP, NULL, NULL);
+}
+
+DEFUN (clear_ip_prefix_list_name,
+       clear_ip_prefix_list_name_cmd,
+       "clear ip prefix-list WORD",
+       CLEAR_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n")
+{
+  return vty_clear_prefix_list (vty, AFI_IP, argv[0], NULL);
+}
+
+DEFUN (clear_ip_prefix_list_name_prefix,
+       clear_ip_prefix_list_name_prefix_cmd,
+       "clear ip prefix-list WORD A.B.C.D/M",
+       CLEAR_STR
+       IP_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+  return vty_clear_prefix_list (vty, AFI_IP, argv[0], argv[1]);
+}
+
+#ifdef HAVE_IPV6
+DEFUN (ipv6_prefix_list,
+       ipv6_prefix_list_cmd,
+       "ipv6 prefix-list WORD (deny|permit) (X:X::X:X/M|any)",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Any prefix match.  Same as \"::0/0 le 128\"\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, 
+				  argv[1], argv[2], NULL, NULL);
+}
+
+DEFUN (ipv6_prefix_list_ge,
+       ipv6_prefix_list_ge_cmd,
+       "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128>",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1], 
+				 argv[2], argv[3], NULL);
+}
+
+DEFUN (ipv6_prefix_list_ge_le,
+       ipv6_prefix_list_ge_le_cmd,
+       "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128> le <0-128>",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+
+{
+  return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1], 
+				  argv[2], argv[3], argv[4]);
+}
+
+DEFUN (ipv6_prefix_list_le,
+       ipv6_prefix_list_le_cmd,
+       "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128>",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1],
+				  argv[2], NULL, argv[3]);
+}
+
+DEFUN (ipv6_prefix_list_le_ge,
+       ipv6_prefix_list_le_ge_cmd,
+       "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128> ge <0-128>",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP6, argv[0], NULL, argv[1],
+				  argv[2], argv[4], argv[3]);
+}
+
+DEFUN (ipv6_prefix_list_seq,
+       ipv6_prefix_list_seq_cmd,
+       "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) (X:X::X:X/M|any)",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Any prefix match.  Same as \"::0/0 le 128\"\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2],
+				  argv[3], NULL, NULL);
+}
+
+DEFUN (ipv6_prefix_list_seq_ge,
+       ipv6_prefix_list_seq_ge_cmd,
+       "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128>",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2],
+				  argv[3], argv[4], NULL);
+}
+
+DEFUN (ipv6_prefix_list_seq_ge_le,
+       ipv6_prefix_list_seq_ge_le_cmd,
+       "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128> le <0-128>",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2],
+				  argv[3], argv[4], argv[5]);
+}
+
+DEFUN (ipv6_prefix_list_seq_le,
+       ipv6_prefix_list_seq_le_cmd,
+       "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128>",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2],
+				  argv[3], NULL, argv[4]);
+}
+
+DEFUN (ipv6_prefix_list_seq_le_ge,
+       ipv6_prefix_list_seq_le_ge_cmd,
+       "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128> ge <0-128>",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_install (vty, AFI_IP6, argv[0], argv[1], argv[2],
+				  argv[3], argv[5], argv[4]);
+}
+
+DEFUN (no_ipv6_prefix_list,
+       no_ipv6_prefix_list_cmd,
+       "no ipv6 prefix-list WORD",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, NULL,
+				    NULL, NULL, NULL);
+}
+
+DEFUN (no_ipv6_prefix_list_prefix,
+       no_ipv6_prefix_list_prefix_cmd,
+       "no ipv6 prefix-list WORD (deny|permit) (X:X::X:X/M|any)",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Any prefix match.  Same as \"::0/0 le 128\"\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1],
+				    argv[2], NULL, NULL);
+}
+
+DEFUN (no_ipv6_prefix_list_ge,
+       no_ipv6_prefix_list_ge_cmd,
+       "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128>",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1],
+				    argv[2], argv[3], NULL);
+}
+
+DEFUN (no_ipv6_prefix_list_ge_le,
+       no_ipv6_prefix_list_ge_le_cmd,
+       "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128> le <0-128>",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1],
+				    argv[2], argv[3], argv[4]);
+}
+
+DEFUN (no_ipv6_prefix_list_le,
+       no_ipv6_prefix_list_le_cmd,
+       "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128>",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1],
+				    argv[2], NULL, argv[3]);
+}
+
+DEFUN (no_ipv6_prefix_list_le_ge,
+       no_ipv6_prefix_list_le_ge_cmd,
+       "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128> ge <0-128>",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], NULL, argv[1],
+				    argv[2], argv[4], argv[3]);
+}
+
+DEFUN (no_ipv6_prefix_list_seq,
+       no_ipv6_prefix_list_seq_cmd,
+       "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) (X:X::X:X/M|any)",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Any prefix match.  Same as \"::0/0 le 128\"\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2],
+				    argv[3], NULL, NULL);
+}
+
+DEFUN (no_ipv6_prefix_list_seq_ge,
+       no_ipv6_prefix_list_seq_ge_cmd,
+       "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128>",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2],
+				    argv[3], argv[4], NULL);
+}
+
+DEFUN (no_ipv6_prefix_list_seq_ge_le,
+       no_ipv6_prefix_list_seq_ge_le_cmd,
+       "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128> le <0-128>",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2],
+				    argv[3], argv[4], argv[5]);
+}
+
+DEFUN (no_ipv6_prefix_list_seq_le,
+       no_ipv6_prefix_list_seq_le_cmd,
+       "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128>",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2],
+				    argv[3], NULL, argv[4]);
+}
+
+DEFUN (no_ipv6_prefix_list_seq_le_ge,
+       no_ipv6_prefix_list_seq_le_ge_cmd,
+       "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128> ge <0-128>",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Maximum prefix length to be matched\n"
+       "Maximum prefix length\n"
+       "Minimum prefix length to be matched\n"
+       "Minimum prefix length\n")
+{
+  return vty_prefix_list_uninstall (vty, AFI_IP6, argv[0], argv[1], argv[2],
+				    argv[3], argv[5], argv[4]);
+}
+
+DEFUN (ipv6_prefix_list_sequence_number,
+       ipv6_prefix_list_sequence_number_cmd,
+       "ipv6 prefix-list sequence-number",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Include/exclude sequence numbers in NVGEN\n")
+{
+  prefix_master_ipv6.seqnum = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_prefix_list_sequence_number,
+       no_ipv6_prefix_list_sequence_number_cmd,
+       "no ipv6 prefix-list sequence-number",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Include/exclude sequence numbers in NVGEN\n")
+{
+  prefix_master_ipv6.seqnum = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (ipv6_prefix_list_description,
+       ipv6_prefix_list_description_cmd,
+       "ipv6 prefix-list WORD description .LINE",
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Prefix-list specific description\n"
+       "Up to 80 characters describing this prefix-list\n")
+{
+  struct prefix_list *plist;
+  struct buffer *b;
+  int i;
+
+  plist = prefix_list_get (AFI_IP6, argv[0]);
+  
+  if (plist->desc)
+    {
+      XFREE (MTYPE_TMP, plist->desc);
+      plist->desc = NULL;
+    }
+
+  /* Below is description get codes. */
+  b = buffer_new (1024);
+  for (i = 1; i < argc; i++)
+    {
+      buffer_putstr (b, (u_char *)argv[i]);
+      buffer_putc (b, ' ');
+    }
+  buffer_putc (b, '\0');
+
+  plist->desc = buffer_getstr (b);
+
+  buffer_free (b);
+
+  return CMD_SUCCESS;
+}       
+
+DEFUN (no_ipv6_prefix_list_description,
+       no_ipv6_prefix_list_description_cmd,
+       "no ipv6 prefix-list WORD description",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Prefix-list specific description\n")
+{
+  return vty_prefix_list_desc_unset (vty, AFI_IP6, argv[0]);
+}
+
+ALIAS (no_ipv6_prefix_list_description,
+       no_ipv6_prefix_list_description_arg_cmd,
+       "no ipv6 prefix-list WORD description .LINE",
+       NO_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "Prefix-list specific description\n"
+       "Up to 80 characters describing this prefix-list\n")
+
+DEFUN (show_ipv6_prefix_list,
+       show_ipv6_prefix_list_cmd,
+       "show ipv6 prefix-list",
+       SHOW_STR
+       IPV6_STR
+       PREFIX_LIST_STR)
+{
+  return vty_show_prefix_list (vty, AFI_IP6, NULL, NULL, normal_display);
+}
+
+DEFUN (show_ipv6_prefix_list_name,
+       show_ipv6_prefix_list_name_cmd,
+       "show ipv6 prefix-list WORD",
+       SHOW_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP6, argv[0], NULL, normal_display);
+}
+
+DEFUN (show_ipv6_prefix_list_name_seq,
+       show_ipv6_prefix_list_name_seq_cmd,
+       "show ipv6 prefix-list WORD seq <1-4294967295>",
+       SHOW_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "sequence number of an entry\n"
+       "Sequence number\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP6, argv[0], argv[1], sequential_display);
+}
+
+DEFUN (show_ipv6_prefix_list_prefix,
+       show_ipv6_prefix_list_prefix_cmd,
+       "show ipv6 prefix-list WORD X:X::X:X/M",
+       SHOW_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+{
+  return vty_show_prefix_list_prefix (vty, AFI_IP6, argv[0], argv[1], normal_display);
+}
+
+DEFUN (show_ipv6_prefix_list_prefix_longer,
+       show_ipv6_prefix_list_prefix_longer_cmd,
+       "show ipv6 prefix-list WORD X:X::X:X/M longer",
+       SHOW_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "Lookup longer prefix\n")
+{
+  return vty_show_prefix_list_prefix (vty, AFI_IP6, argv[0], argv[1], longer_display);
+}
+
+DEFUN (show_ipv6_prefix_list_prefix_first_match,
+       show_ipv6_prefix_list_prefix_first_match_cmd,
+       "show ipv6 prefix-list WORD X:X::X:X/M first-match",
+       SHOW_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
+       "First matched prefix\n")
+{
+  return vty_show_prefix_list_prefix (vty, AFI_IP6, argv[0], argv[1], first_match_display);
+}
+
+DEFUN (show_ipv6_prefix_list_summary,
+       show_ipv6_prefix_list_summary_cmd,
+       "show ipv6 prefix-list summary",
+       SHOW_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Summary of prefix lists\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP6, NULL, NULL, summary_display);
+}
+
+DEFUN (show_ipv6_prefix_list_summary_name,
+       show_ipv6_prefix_list_summary_name_cmd,
+       "show ipv6 prefix-list summary WORD",
+       SHOW_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Summary of prefix lists\n"
+       "Name of a prefix list\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP6, argv[0], NULL, summary_display);
+}
+
+DEFUN (show_ipv6_prefix_list_detail,
+       show_ipv6_prefix_list_detail_cmd,
+       "show ipv6 prefix-list detail",
+       SHOW_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Detail of prefix lists\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP6, NULL, NULL, detail_display);
+}
+
+DEFUN (show_ipv6_prefix_list_detail_name,
+       show_ipv6_prefix_list_detail_name_cmd,
+       "show ipv6 prefix-list detail WORD",
+       SHOW_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Detail of prefix lists\n"
+       "Name of a prefix list\n")
+{
+  return vty_show_prefix_list (vty, AFI_IP6, argv[0], NULL, detail_display);
+}
+
+DEFUN (clear_ipv6_prefix_list,
+       clear_ipv6_prefix_list_cmd,
+       "clear ipv6 prefix-list",
+       CLEAR_STR
+       IPV6_STR
+       PREFIX_LIST_STR)
+{
+  return vty_clear_prefix_list (vty, AFI_IP6, NULL, NULL);
+}
+
+DEFUN (clear_ipv6_prefix_list_name,
+       clear_ipv6_prefix_list_name_cmd,
+       "clear ipv6 prefix-list WORD",
+       CLEAR_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n")
+{
+  return vty_clear_prefix_list (vty, AFI_IP6, argv[0], NULL);
+}
+
+DEFUN (clear_ipv6_prefix_list_name_prefix,
+       clear_ipv6_prefix_list_name_prefix_cmd,
+       "clear ipv6 prefix-list WORD X:X::X:X/M",
+       CLEAR_STR
+       IPV6_STR
+       PREFIX_LIST_STR
+       "Name of a prefix list\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+{
+  return vty_clear_prefix_list (vty, AFI_IP6, argv[0], argv[1]);
+}
+#endif /* HAVE_IPV6 */
+
+/* Configuration write function. */
+int
+config_write_prefix_afi (afi_t afi, struct vty *vty)
+{
+  struct prefix_list *plist;
+  struct prefix_list_entry *pentry;
+  struct prefix_master *master;
+  int write = 0;
+
+  master = prefix_master_get (afi);
+  if (master == NULL)
+    return 0;
+
+  if (! master->seqnum)
+    {
+      vty_out (vty, "no ip%s prefix-list sequence-number%s", 
+	       afi == AFI_IP ? "" : "v6", VTY_NEWLINE);
+      vty_out (vty, "!%s", VTY_NEWLINE);
+    }
+
+  for (plist = master->num.head; plist; plist = plist->next)
+    {
+      if (plist->desc)
+	{
+	  vty_out (vty, "ip%s prefix-list %s description %s%s",
+		   afi == AFI_IP ? "" : "v6",
+		   plist->name, plist->desc, VTY_NEWLINE);
+	  write++;
+	}
+
+      for (pentry = plist->head; pentry; pentry = pentry->next)
+	{
+	  vty_out (vty, "ip%s prefix-list %s ",
+		   afi == AFI_IP ? "" : "v6",
+		   plist->name);
+
+	  if (master->seqnum)
+	    vty_out (vty, "seq %d ", pentry->seq);
+	
+	  vty_out (vty, "%s ", prefix_list_type_str (pentry));
+
+	  if (pentry->any)
+	    vty_out (vty, "any");
+	  else
+	    {
+	      struct prefix *p = &pentry->prefix;
+	      char buf[BUFSIZ];
+
+	      vty_out (vty, "%s/%d",
+		       inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+		       p->prefixlen);
+
+	      if (pentry->ge)
+		vty_out (vty, " ge %d", pentry->ge);
+	      if (pentry->le)
+		vty_out (vty, " le %d", pentry->le);
+	    }
+	  vty_out (vty, "%s", VTY_NEWLINE);
+	  write++;
+	}
+      /* vty_out (vty, "!%s", VTY_NEWLINE); */
+    }
+
+  for (plist = master->str.head; plist; plist = plist->next)
+    {
+      if (plist->desc)
+	{
+	  vty_out (vty, "ip%s prefix-list %s description %s%s",
+		   afi == AFI_IP ? "" : "v6",
+		   plist->name, plist->desc, VTY_NEWLINE);
+	  write++;
+	}
+
+      for (pentry = plist->head; pentry; pentry = pentry->next)
+	{
+	  vty_out (vty, "ip%s prefix-list %s ",
+		   afi == AFI_IP ? "" : "v6",
+		   plist->name);
+
+	  if (master->seqnum)
+	    vty_out (vty, "seq %d ", pentry->seq);
+
+	  vty_out (vty, "%s", prefix_list_type_str (pentry));
+
+	  if (pentry->any)
+	    vty_out (vty, " any");
+	  else
+	    {
+	      struct prefix *p = &pentry->prefix;
+	      char buf[BUFSIZ];
+
+	      vty_out (vty, " %s/%d",
+		       inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+		       p->prefixlen);
+
+	      if (pentry->ge)
+		vty_out (vty, " ge %d", pentry->ge);
+	      if (pentry->le)
+		vty_out (vty, " le %d", pentry->le);
+	    }
+	  vty_out (vty, "%s", VTY_NEWLINE);
+	  write++;
+	}
+    }
+  
+  return write;
+}
+
+int stream_putc (struct stream *, u_char);
+int stream_putl (struct stream *, u_int32_t);
+int stream_put_prefix (struct stream *, struct prefix *);
+
+struct stream *
+prefix_bgp_orf_entry (struct stream *s, struct prefix_list *plist,
+		      u_char init_flag, u_char permit_flag, u_char deny_flag)
+{
+  struct prefix_list_entry *pentry;
+
+  if (! plist)
+    return s;
+
+  for (pentry = plist->head; pentry; pentry = pentry->next)
+    {
+      u_char flag = init_flag;
+      struct prefix *p = &pentry->prefix;
+
+      flag |= (pentry->type == PREFIX_PERMIT ?
+               permit_flag : deny_flag);
+      stream_putc (s, flag);
+      stream_putl (s, (u_int32_t)pentry->seq);
+      stream_putc (s, (u_char)pentry->ge);
+      stream_putc (s, (u_char)pentry->le);
+      stream_put_prefix (s, p);
+    }
+
+  return s;
+}
+
+int
+prefix_bgp_orf_set (char *name, afi_t afi, struct orf_prefix *orfp,
+		    int permit, int set)
+{
+  struct prefix_list *plist;
+  struct prefix_list_entry *pentry;
+
+  /* ge and le value check */ 
+  if (orfp->ge && orfp->ge <= orfp->p.prefixlen)
+    return CMD_WARNING;
+  if (orfp->le && orfp->le <= orfp->p.prefixlen)
+    return CMD_WARNING;
+  if (orfp->le && orfp->ge > orfp->le)
+    return CMD_WARNING;
+
+  if (orfp->ge && orfp->le == (afi == AFI_IP ? 32 : 128))
+    orfp->le = 0;
+
+  plist = prefix_list_get (AFI_ORF_PREFIX, name);
+  if (! plist)
+    return CMD_WARNING;
+
+  if (set)
+    {
+      pentry = prefix_list_entry_make (&orfp->p,
+				       (permit ? PREFIX_PERMIT : PREFIX_DENY),
+				       orfp->seq, orfp->le, orfp->ge, 0);
+
+      if (prefix_entry_dup_check (plist, pentry))
+	{
+	  prefix_list_entry_free (pentry);
+	  return CMD_WARNING;
+	}
+
+      prefix_list_entry_add (plist, pentry);
+    }
+  else
+    {
+      pentry = prefix_list_entry_lookup (plist, &orfp->p,
+					 (permit ? PREFIX_PERMIT : PREFIX_DENY),
+					 orfp->seq, orfp->le, orfp->ge);
+
+      if (! pentry)
+	return CMD_WARNING;
+
+      prefix_list_entry_delete (plist, pentry, 1);
+    }
+
+  return CMD_SUCCESS;
+}
+
+void
+prefix_bgp_orf_remove_all (char *name)
+{
+  struct prefix_list *plist;
+
+  plist = prefix_list_lookup (AFI_ORF_PREFIX, name);
+  if (plist)
+    prefix_list_delete (plist);
+}
+
+/* return prefix count */
+int
+prefix_bgp_show_prefix_list (struct vty *vty, afi_t afi, char *name)
+{
+  struct prefix_list *plist;
+  struct prefix_list_entry *pentry;
+
+  plist = prefix_list_lookup (AFI_ORF_PREFIX, name);
+  if (! plist)
+    return 0;
+
+  if (! vty)
+    return plist->count;
+
+  vty_out (vty, "ip%s prefix-list %s: %d entries%s",
+	   afi == AFI_IP ? "" : "v6",
+	   plist->name, plist->count, VTY_NEWLINE);
+
+  for (pentry = plist->head; pentry; pentry = pentry->next)
+    {
+      struct prefix *p = &pentry->prefix;
+      char buf[BUFSIZ];
+
+      vty_out (vty, "   seq %d %s %s/%d", pentry->seq,
+	       prefix_list_type_str (pentry),
+	       inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+	       p->prefixlen);
+
+      if (pentry->ge)
+	vty_out (vty, " ge %d", pentry->ge);
+      if (pentry->le)
+	vty_out (vty, " le %d", pentry->le);
+
+      vty_out (vty, "%s", VTY_NEWLINE);
+    }
+  return plist->count;
+}
+
+void
+prefix_list_reset_orf ()
+{
+  struct prefix_list *plist;
+  struct prefix_list *next;
+  struct prefix_master *master;
+
+  master = prefix_master_get (AFI_ORF_PREFIX);
+  if (master == NULL)
+    return;
+
+  for (plist = master->num.head; plist; plist = next)
+    {
+      next = plist->next;
+      prefix_list_delete (plist);
+    }
+  for (plist = master->str.head; plist; plist = next)
+    {
+      next = plist->next;
+      prefix_list_delete (plist);
+    }
+
+  assert (master->num.head == NULL);
+  assert (master->num.tail == NULL);
+
+  assert (master->str.head == NULL);
+  assert (master->str.tail == NULL);
+
+  master->seqnum = 1;
+  master->recent = NULL;
+}
+
+
+/* Prefix-list node. */
+struct cmd_node prefix_node =
+{
+  PREFIX_NODE,
+  "",				/* Prefix list has no interface. */
+  1
+};
+
+int
+config_write_prefix_ipv4 (struct vty *vty)
+{
+  return config_write_prefix_afi (AFI_IP, vty);
+}
+
+void
+prefix_list_reset_ipv4 ()
+{
+  struct prefix_list *plist;
+  struct prefix_list *next;
+  struct prefix_master *master;
+
+  master = prefix_master_get (AFI_IP);
+  if (master == NULL)
+    return;
+
+  for (plist = master->num.head; plist; plist = next)
+    {
+      next = plist->next;
+      prefix_list_delete (plist);
+    }
+  for (plist = master->str.head; plist; plist = next)
+    {
+      next = plist->next;
+      prefix_list_delete (plist);
+    }
+
+  assert (master->num.head == NULL);
+  assert (master->num.tail == NULL);
+
+  assert (master->str.head == NULL);
+  assert (master->str.tail == NULL);
+
+  master->seqnum = 1;
+  master->recent = NULL;
+}
+
+void
+prefix_list_init_ipv4 ()
+{
+  install_node (&prefix_node, config_write_prefix_ipv4);
+
+  install_element (CONFIG_NODE, &ip_prefix_list_cmd);
+  install_element (CONFIG_NODE, &ip_prefix_list_ge_cmd);
+  install_element (CONFIG_NODE, &ip_prefix_list_ge_le_cmd);
+  install_element (CONFIG_NODE, &ip_prefix_list_le_cmd);
+  install_element (CONFIG_NODE, &ip_prefix_list_le_ge_cmd);
+  install_element (CONFIG_NODE, &ip_prefix_list_seq_cmd);
+  install_element (CONFIG_NODE, &ip_prefix_list_seq_ge_cmd);
+  install_element (CONFIG_NODE, &ip_prefix_list_seq_ge_le_cmd);
+  install_element (CONFIG_NODE, &ip_prefix_list_seq_le_cmd);
+  install_element (CONFIG_NODE, &ip_prefix_list_seq_le_ge_cmd);
+
+  install_element (CONFIG_NODE, &no_ip_prefix_list_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_prefix_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_ge_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_ge_le_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_le_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_le_ge_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_seq_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_seq_ge_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_seq_ge_le_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_seq_le_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_seq_le_ge_cmd);
+
+  install_element (CONFIG_NODE, &ip_prefix_list_description_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_description_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_description_arg_cmd);
+
+  install_element (CONFIG_NODE, &ip_prefix_list_sequence_number_cmd);
+  install_element (CONFIG_NODE, &no_ip_prefix_list_sequence_number_cmd);
+
+  install_element (VIEW_NODE, &show_ip_prefix_list_cmd);
+  install_element (VIEW_NODE, &show_ip_prefix_list_name_cmd);
+  install_element (VIEW_NODE, &show_ip_prefix_list_name_seq_cmd);
+  install_element (VIEW_NODE, &show_ip_prefix_list_prefix_cmd);
+  install_element (VIEW_NODE, &show_ip_prefix_list_prefix_longer_cmd);
+  install_element (VIEW_NODE, &show_ip_prefix_list_prefix_first_match_cmd);
+  install_element (VIEW_NODE, &show_ip_prefix_list_summary_cmd);
+  install_element (VIEW_NODE, &show_ip_prefix_list_summary_name_cmd);
+  install_element (VIEW_NODE, &show_ip_prefix_list_detail_cmd);
+  install_element (VIEW_NODE, &show_ip_prefix_list_detail_name_cmd);
+
+  install_element (ENABLE_NODE, &show_ip_prefix_list_cmd);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_name_cmd);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_name_seq_cmd);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_cmd);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_longer_cmd);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_first_match_cmd);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_summary_cmd);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_summary_name_cmd);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_detail_cmd);
+  install_element (ENABLE_NODE, &show_ip_prefix_list_detail_name_cmd);
+
+  install_element (ENABLE_NODE, &clear_ip_prefix_list_cmd);
+  install_element (ENABLE_NODE, &clear_ip_prefix_list_name_cmd);
+  install_element (ENABLE_NODE, &clear_ip_prefix_list_name_prefix_cmd);
+}
+
+#ifdef HAVE_IPV6
+/* Prefix-list node. */
+struct cmd_node prefix_ipv6_node =
+{
+  PREFIX_IPV6_NODE,
+  "",				/* Prefix list has no interface. */
+  1
+};
+
+int
+config_write_prefix_ipv6 (struct vty *vty)
+{
+  return config_write_prefix_afi (AFI_IP6, vty);
+}
+
+void
+prefix_list_reset_ipv6 ()
+{
+  struct prefix_list *plist;
+  struct prefix_list *next;
+  struct prefix_master *master;
+
+  master = prefix_master_get (AFI_IP6);
+  if (master == NULL)
+    return;
+
+  for (plist = master->num.head; plist; plist = next)
+    {
+      next = plist->next;
+      prefix_list_delete (plist);
+    }
+  for (plist = master->str.head; plist; plist = next)
+    {
+      next = plist->next;
+      prefix_list_delete (plist);
+    }
+
+  assert (master->num.head == NULL);
+  assert (master->num.tail == NULL);
+
+  assert (master->str.head == NULL);
+  assert (master->str.tail == NULL);
+
+  master->seqnum = 1;
+  master->recent = NULL;
+}
+
+void
+prefix_list_init_ipv6 ()
+{
+  install_node (&prefix_ipv6_node, config_write_prefix_ipv6);
+
+  install_element (CONFIG_NODE, &ipv6_prefix_list_cmd);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_ge_cmd);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_ge_le_cmd);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_le_cmd);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_le_ge_cmd);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_seq_cmd);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_seq_ge_cmd);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_seq_ge_le_cmd);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_seq_le_cmd);
+  install_element (CONFIG_NODE, &ipv6_prefix_list_seq_le_ge_cmd);
+
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_prefix_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_ge_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_ge_le_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_le_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_le_ge_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_ge_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_ge_le_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_le_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_le_ge_cmd);
+
+  install_element (CONFIG_NODE, &ipv6_prefix_list_description_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_description_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_description_arg_cmd);
+
+  install_element (CONFIG_NODE, &ipv6_prefix_list_sequence_number_cmd);
+  install_element (CONFIG_NODE, &no_ipv6_prefix_list_sequence_number_cmd);
+
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_cmd);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_name_cmd);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_name_seq_cmd);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_cmd);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_longer_cmd);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_first_match_cmd);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_summary_cmd);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_summary_name_cmd);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_cmd);
+  install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_name_cmd);
+
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_seq_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_longer_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_first_match_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_name_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_cmd);
+  install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_name_cmd);
+
+  install_element (ENABLE_NODE, &clear_ipv6_prefix_list_cmd);
+  install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_cmd);
+  install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_prefix_cmd);
+}
+#endif /* HAVE_IPV6 */
+
+void
+prefix_list_init ()
+{
+  prefix_list_init_ipv4 ();
+#ifdef HAVE_IPV6
+  prefix_list_init_ipv6 ();
+#endif /* HAVE_IPV6 */
+}
+
+void
+prefix_list_reset ()
+{
+  prefix_list_reset_ipv4 ();
+#ifdef HAVE_IPV6
+  prefix_list_reset_ipv6 ();
+#endif /* HAVE_IPV6 */
+  prefix_list_reset_orf ();
+}
diff --git a/lib/plist.h b/lib/plist.h
new file mode 100644
index 0000000..9a9eb71
--- /dev/null
+++ b/lib/plist.h
@@ -0,0 +1,78 @@
+/*
+ * Prefix list functions.
+ * Copyright (C) 1999 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.
+ */
+
+#define AFI_ORF_PREFIX 65535
+
+enum prefix_list_type 
+{
+  PREFIX_DENY,
+  PREFIX_PERMIT,
+};
+
+enum prefix_name_type
+{
+  PREFIX_TYPE_STRING,
+  PREFIX_TYPE_NUMBER
+};
+
+struct prefix_list
+{
+  char *name;
+  char *desc;
+
+  struct prefix_master *master;
+
+  enum prefix_name_type type;
+
+  int count;
+  int rangecount;
+
+  struct prefix_list_entry *head;
+  struct prefix_list_entry *tail;
+
+  struct prefix_list *next;
+  struct prefix_list *prev;
+};
+
+struct orf_prefix
+{
+  u_int32_t seq;
+  u_char ge;
+  u_char le;
+  struct prefix p;
+};
+
+/* Prototypes. */
+void prefix_list_init (void);
+void prefix_list_reset (void);
+void prefix_list_add_hook (void (*func) (struct prefix_list *));
+void prefix_list_delete_hook (void (*func) (struct prefix_list *));
+
+struct prefix_list *prefix_list_lookup (afi_t, char *);
+enum prefix_list_type prefix_list_apply (struct prefix_list *, void *);
+
+struct stream *
+prefix_bgp_orf_entry (struct stream *, struct prefix_list *,
+                      u_char, u_char, u_char);
+int prefix_bgp_orf_set (char *, afi_t, struct orf_prefix *, int, int);
+void prefix_bgp_orf_remove_all (char *);
+int prefix_bgp_show_prefix_list (struct vty *, afi_t, char *);
diff --git a/lib/prefix.c b/lib/prefix.c
new file mode 100644
index 0000000..61e0f19
--- /dev/null
+++ b/lib/prefix.c
@@ -0,0 +1,696 @@
+/*
+ * Prefix related functions.
+ * Copyright (C) 1997, 98, 99 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.  
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "vty.h"
+#include "sockunion.h"
+#include "memory.h"
+#include "log.h"
+
+/* Maskbit. */
+static u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
+			         0xf8, 0xfc, 0xfe, 0xff};
+
+/* Number of bits in prefix type. */
+#ifndef PNBBY
+#define PNBBY 8
+#endif /* PNBBY */
+
+#define MASKBIT(offset)  ((0xff << (PNBBY - (offset))) & 0xff)
+
+/* Address Famiy Identifier to Address Family converter. */
+int
+afi2family (int afi)
+{
+  if (afi == AFI_IP)
+    return AF_INET;
+#ifdef HAVE_IPV6
+  else if (afi == AFI_IP6)
+    return AF_INET6;
+#endif /* HAVE_IPV6 */
+  return 0;
+}
+
+int
+family2afi (int family)
+{
+  if (family == AF_INET)
+    return AFI_IP;
+#ifdef HAVE_IPV6
+  else if (family == AF_INET6)
+    return AFI_IP6;
+#endif /* HAVE_IPV6 */
+  return 0;
+}
+
+/* If n includes p prefix then return 1 else return 0. */
+int
+prefix_match (struct prefix *n, struct prefix *p)
+{
+  int offset;
+  int shift;
+
+  /* Set both prefix's head pointer. */
+  u_char *np = (u_char *)&n->u.prefix;
+  u_char *pp = (u_char *)&p->u.prefix;
+
+  /* If n's prefix is longer than p's one return 0. */
+  if (n->prefixlen > p->prefixlen)
+    return 0;
+
+  offset = n->prefixlen / PNBBY;
+  shift =  n->prefixlen % PNBBY;
+
+  if (shift)
+    if (maskbit[shift] & (np[offset] ^ pp[offset]))
+      return 0;
+  
+  while (offset--)
+    if (np[offset] != pp[offset])
+      return 0;
+  return 1;
+}
+
+/* Copy prefix from src to dest. */
+void
+prefix_copy (struct prefix *dest, struct prefix *src)
+{
+  dest->family = src->family;
+  dest->prefixlen = src->prefixlen;
+
+  if (src->family == AF_INET)
+    dest->u.prefix4 = src->u.prefix4;
+#ifdef HAVE_IPV6
+  else if (src->family == AF_INET6)
+    dest->u.prefix6 = src->u.prefix6;
+#endif /* HAVE_IPV6 */
+  else if (src->family == AF_UNSPEC)
+    {
+      dest->u.lp.id = src->u.lp.id;
+      dest->u.lp.adv_router = src->u.lp.adv_router;
+    }
+  else
+    {
+      zlog (NULL, LOG_INFO, "prefix_copy(): Unknown address family %d",
+	      src->family);
+      assert (0);
+    }
+}
+
+/* If both prefix structure is same then return 1 else return 0. */
+int
+prefix_same (struct prefix *p1, struct prefix *p2)
+{
+  if (p1->family == p2->family && p1->prefixlen == p2->prefixlen)
+    {
+      if (p1->family == AF_INET)
+	if (IPV4_ADDR_SAME (&p1->u.prefix, &p2->u.prefix))
+	  return 1;
+#ifdef HAVE_IPV6
+      if (p1->family == AF_INET6 )
+	if (IPV6_ADDR_SAME (&p1->u.prefix, &p2->u.prefix))
+	  return 1;
+#endif /* HAVE_IPV6 */
+    }
+  return 0;
+}
+
+/* When both prefix structure is not same, but will be same after
+   applying mask, return 0. otherwise, return 1 */
+int
+prefix_cmp (struct prefix *p1, struct prefix *p2)
+{
+  int offset;
+  int shift;
+
+  /* Set both prefix's head pointer. */
+  u_char *pp1 = (u_char *)&p1->u.prefix;
+  u_char *pp2 = (u_char *)&p2->u.prefix;
+
+  if (p1->family != p2->family || p1->prefixlen != p2->prefixlen)
+    return 1;
+
+  offset = p1->prefixlen / 8;
+  shift = p1->prefixlen % 8;
+
+  if (shift)
+    if (maskbit[shift] & (pp1[offset] ^ pp2[offset]))
+      return 1;
+
+  while (offset--)
+    if (pp1[offset] != pp2[offset])
+      return 1;
+
+  return 0;
+}
+
+/* Return prefix family type string. */
+char *
+prefix_family_str (struct prefix *p)
+{
+  if (p->family == AF_INET)
+    return "inet";
+#ifdef HAVE_IPV6
+  if (p->family == AF_INET6)
+    return "inet6";
+#endif /* HAVE_IPV6 */
+  return "unspec";
+}
+
+/* Allocate new prefix_ipv4 structure. */
+struct prefix_ipv4 *
+prefix_ipv4_new ()
+{
+  struct prefix_ipv4 *p;
+
+  p = XCALLOC (MTYPE_PREFIX_IPV4, sizeof *p);
+  p->family = AF_INET;
+  return p;
+}
+
+/* Free prefix_ipv4 structure. */
+void
+prefix_ipv4_free (struct prefix_ipv4 *p)
+{
+  XFREE (MTYPE_PREFIX_IPV4, p);
+}
+
+/* When string format is invalid return 0. */
+int
+str2prefix_ipv4 (char *str, struct prefix_ipv4 *p)
+{
+  int ret;
+  int plen;
+  char *pnt;
+  char *cp;
+
+  /* Find slash inside string. */
+  pnt = strchr (str, '/');
+
+  /* String doesn't contail slash. */
+  if (pnt == NULL) 
+    {
+      /* Convert string to prefix. */
+      ret = inet_aton (str, &p->prefix);
+      if (ret == 0)
+	return 0;
+
+      /* If address doesn't contain slash we assume it host address. */
+      p->family = AF_INET;
+      p->prefixlen = IPV4_MAX_BITLEN;
+
+      return ret;
+    }
+  else
+    {
+      cp = XMALLOC (MTYPE_TMP, (pnt - str) + 1);
+      strncpy (cp, str, pnt - str);
+      *(cp + (pnt - str)) = '\0';
+      ret = inet_aton (cp, &p->prefix);
+      XFREE (MTYPE_TMP, cp);
+
+      /* Get prefix length. */
+      plen = (u_char) atoi (++pnt);
+      if (plen > 32)
+	return 0;
+
+      p->family = AF_INET;
+      p->prefixlen = plen;
+    }
+
+  return ret;
+}
+
+/* Convert masklen into IP address's netmask. */
+void
+masklen2ip (int masklen, struct in_addr *netmask)
+{
+  u_char *pnt;
+  int bit;
+  int offset;
+
+  memset (netmask, 0, sizeof (struct in_addr));
+  pnt = (unsigned char *) netmask;
+
+  offset = masklen / 8;
+  bit = masklen % 8;
+  
+  while (offset--)
+    *pnt++ = 0xff;
+
+  if (bit)
+    *pnt = maskbit[bit];
+}
+
+/* Convert IP address's netmask into integer. We assume netmask is
+   sequential one. Argument netmask should be network byte order. */
+u_char
+ip_masklen (struct in_addr netmask)
+{
+  u_char len;
+  u_char *pnt;
+  u_char *end;
+  u_char val;
+
+  len = 0;
+  pnt = (u_char *) &netmask;
+  end = pnt + 4;
+
+  while ((*pnt == 0xff) && pnt < end)
+    {
+      len+= 8;
+      pnt++;
+    } 
+
+  if (pnt < end)
+    {
+      val = *pnt;
+      while (val)
+	{
+	  len++;
+	  val <<= 1;
+	}
+    }
+  return len;
+}
+
+/* Apply mask to IPv4 prefix. */
+void
+apply_mask_ipv4 (struct prefix_ipv4 *p)
+{
+  u_char *pnt;
+  int index;
+  int offset;
+
+  index = p->prefixlen / 8;
+
+  if (index < 4)
+    {
+      pnt = (u_char *) &p->prefix;
+      offset = p->prefixlen % 8;
+
+      pnt[index] &= maskbit[offset];
+      index++;
+
+      while (index < 4)
+	pnt[index++] = 0;
+    }
+}
+
+/* If prefix is 0.0.0.0/0 then return 1 else return 0. */
+int
+prefix_ipv4_any (struct prefix_ipv4 *p)
+{
+  return (p->prefix.s_addr == 0 && p->prefixlen == 0);
+}
+
+#ifdef HAVE_IPV6
+
+/* Allocate a new ip version 6 route */
+struct prefix_ipv6 *
+prefix_ipv6_new ()
+{
+  struct prefix_ipv6 *p;
+
+  p = XCALLOC (MTYPE_PREFIX_IPV6, sizeof (struct prefix_ipv6));
+  p->family = AF_INET6;
+  return p;
+}
+
+/* Free prefix for IPv6. */
+void
+prefix_ipv6_free (struct prefix_ipv6 *p)
+{
+  XFREE (MTYPE_PREFIX_IPV6, p);
+}
+
+/* If given string is valid return pin6 else return NULL */
+int
+str2prefix_ipv6 (char *str, struct prefix_ipv6 *p)
+{
+  char *pnt;
+  char *cp;
+  int ret;
+
+  pnt = strchr (str, '/');
+
+  /* If string doesn't contain `/' treat it as host route. */
+  if (pnt == NULL) 
+    {
+      ret = inet_pton (AF_INET6, str, &p->prefix);
+      if (ret != 1)
+	return 0;
+      p->prefixlen = IPV6_MAX_BITLEN;
+    }
+  else 
+    {
+      int plen;
+
+      cp = XMALLOC (0, (pnt - str) + 1);
+      strncpy (cp, str, pnt - str);
+      *(cp + (pnt - str)) = '\0';
+      ret = inet_pton (AF_INET6, cp, &p->prefix);
+      free (cp);
+      if (ret != 1)
+	return 0;
+      plen = (u_char) atoi (++pnt);
+      if (plen > 128)
+	return 0;
+      p->prefixlen = plen;
+    }
+  p->family = AF_INET6;
+
+  return ret;
+}
+
+/* Convert struct in6_addr netmask into integer. */
+int
+ip6_masklen (struct in6_addr netmask)
+{
+  int len = 0;
+  unsigned char val;
+  unsigned char *pnt;
+  
+  pnt = (unsigned char *) & netmask;
+
+  while ((*pnt == 0xff) && len < 128) 
+    {
+      len += 8;
+      pnt++;
+    } 
+  
+  if (len < 128) 
+    {
+      val = *pnt;
+      while (val) 
+	{
+	  len++;
+	  val <<= 1;
+	}
+    }
+  return len;
+}
+
+void
+masklen2ip6 (int masklen, struct in6_addr *netmask)
+{
+  unsigned char *pnt;
+  int bit;
+  int offset;
+
+  memset (netmask, 0, sizeof (struct in6_addr));
+  pnt = (unsigned char *) netmask;
+
+  offset = masklen / 8;
+  bit = masklen % 8;
+
+  while (offset--)
+    *pnt++ = 0xff;
+
+  if (bit)
+    *pnt = maskbit[bit];
+}
+
+void
+apply_mask_ipv6 (struct prefix_ipv6 *p)
+{
+  u_char *pnt;
+  int index;
+  int offset;
+
+  index = p->prefixlen / 8;
+
+  if (index < 16)
+    {
+      pnt = (u_char *) &p->prefix;
+      offset = p->prefixlen % 8;
+
+      pnt[index] &= maskbit[offset];
+      index++;
+
+      while (index < 16)
+	pnt[index++] = 0;
+    }
+}
+
+void
+str2in6_addr (char *str, struct in6_addr *addr)
+{
+  int i;
+  unsigned int x;
+
+  /* %x must point to unsinged int */
+  for (i = 0; i < 16; i++)
+    {
+      sscanf (str + (i * 2), "%02x", &x);
+      addr->s6_addr[i] = x & 0xff;
+    }
+}
+#endif /* HAVE_IPV6 */
+
+void
+apply_mask (struct prefix *p)
+{
+  switch (p->family)
+    {
+      case AF_INET:
+        apply_mask_ipv4 ((struct prefix_ipv4 *)p);
+        break;
+#ifdef HAVE_IPV6
+      case AF_INET6:
+        apply_mask_ipv6 ((struct prefix_ipv6 *)p);
+        break;
+#endif /* HAVE_IPV6 */
+      default:
+        break;
+    }
+  return;
+}
+
+/* Utility function of convert between struct prefix <=> union sockunion */
+struct prefix *
+sockunion2prefix (union sockunion *dest,
+		  union sockunion *mask)
+{
+  if (dest->sa.sa_family == AF_INET)
+    {
+      struct prefix_ipv4 *p;
+
+      p = prefix_ipv4_new ();
+      p->family = AF_INET;
+      p->prefix = dest->sin.sin_addr;
+      p->prefixlen = ip_masklen (mask->sin.sin_addr);
+      return (struct prefix *) p;
+    }
+#ifdef HAVE_IPV6
+  if (dest->sa.sa_family == AF_INET6)
+    {
+      struct prefix_ipv6 *p;
+
+      p = prefix_ipv6_new ();
+      p->family = AF_INET6;
+      p->prefixlen = ip6_masklen (mask->sin6.sin6_addr);
+      memcpy (&p->prefix, &dest->sin6.sin6_addr, sizeof (struct in6_addr));
+      return (struct prefix *) p;
+    }
+#endif /* HAVE_IPV6 */
+  return NULL;
+}
+
+/* Utility function of convert between struct prefix <=> union sockunion */
+struct prefix *
+sockunion2hostprefix (union sockunion *su)
+{
+  if (su->sa.sa_family == AF_INET)
+    {
+      struct prefix_ipv4 *p;
+
+      p = prefix_ipv4_new ();
+      p->family = AF_INET;
+      p->prefix = su->sin.sin_addr;
+      p->prefixlen = IPV4_MAX_BITLEN;
+      return (struct prefix *) p;
+    }
+#ifdef HAVE_IPV6
+  if (su->sa.sa_family == AF_INET6)
+    {
+      struct prefix_ipv6 *p;
+
+      p = prefix_ipv6_new ();
+      p->family = AF_INET6;
+      p->prefixlen = IPV6_MAX_BITLEN;
+      memcpy (&p->prefix, &su->sin6.sin6_addr, sizeof (struct in6_addr));
+      return (struct prefix *) p;
+    }
+#endif /* HAVE_IPV6 */
+  return NULL;
+}
+
+int
+prefix_blen (struct prefix *p)
+{
+  switch (p->family) 
+    {
+    case AF_INET:
+      return IPV4_MAX_BYTELEN;
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      return IPV6_MAX_BYTELEN;
+      break;
+#endif /* HAVE_IPV6 */
+    }
+  return 0;
+}
+
+/* Generic function for conversion string to struct prefix. */
+int
+str2prefix (char *str, struct prefix *p)
+{
+  int ret;
+
+  /* First we try to convert string to struct prefix_ipv4. */
+  ret = str2prefix_ipv4 (str, (struct prefix_ipv4 *) p);
+  if (ret)
+    return ret;
+
+#ifdef HAVE_IPV6
+  /* Next we try to convert string to struct prefix_ipv6. */
+  ret = str2prefix_ipv6 (str, (struct prefix_ipv6 *) p);
+  if (ret)
+    return ret;
+#endif /* HAVE_IPV6 */
+
+  return 0;
+}
+
+int
+prefix2str (struct prefix *p, char *str, int size)
+{
+  char buf[BUFSIZ];
+
+  inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ);
+  snprintf (str, size, "%s/%d", buf, p->prefixlen);
+  return 0;
+}
+
+struct prefix *
+prefix_new ()
+{
+  struct prefix *p;
+
+  p = XCALLOC (MTYPE_PREFIX, sizeof *p);
+  return p;
+}
+
+/* Free prefix structure. */
+void
+prefix_free (struct prefix *p)
+{
+  XFREE (MTYPE_PREFIX, p);
+}
+
+/* Utility function.  Check the string only contains digit
+   character. */
+int
+all_digit (char *str)
+{
+  for (; *str != '\0'; str++)
+    if (!isdigit ((int) *str))
+      return 0;
+  return 1;
+}
+
+/* Utility function to convert ipv4 prefixes to Classful prefixes */
+void apply_classful_mask_ipv4 (struct prefix_ipv4 *p)
+{
+
+  u_int32_t destination;
+  
+  destination = ntohl (p->prefix.s_addr);
+  
+  if (p->prefixlen == 32);
+  /* do nothing for host routes */
+  else if (IN_CLASSC (destination)) 
+    {
+      p->prefixlen=24;
+      apply_mask_ipv4(p);
+    }
+  else if (IN_CLASSB(destination)) 
+    {
+      p->prefixlen=16;
+      apply_mask_ipv4(p);
+    }
+  else 
+    {
+      p->prefixlen=8;
+      apply_mask_ipv4(p);
+    }
+}
+
+/* Utility function to convert ipv4 netmask to prefixes 
+   ex.) "1.1.0.0" "255.255.0.0" => "1.1.0.0/16"
+   ex.) "1.0.0.0" NULL => "1.0.0.0/8"                   */
+int
+netmask_str2prefix_str (char *net_str, char *mask_str, char *prefix_str)
+{
+  struct in_addr network;
+  struct in_addr mask;
+  u_char prefixlen;
+  u_int32_t destination;
+  int ret;
+
+  ret = inet_aton (net_str, &network);
+  if (! ret)
+    return 0;
+
+  if (mask_str)
+    {
+      ret = inet_aton (mask_str, &mask);
+      if (! ret)
+        return 0;
+
+      prefixlen = ip_masklen (mask);
+    }
+  else 
+    {
+      destination = ntohl (network.s_addr);
+
+      if (network.s_addr == 0)
+	prefixlen = 0;
+      else if (IN_CLASSC (destination))
+	prefixlen = 24;
+      else if (IN_CLASSB (destination))
+	prefixlen = 16;
+      else if (IN_CLASSA (destination))
+	prefixlen = 8;
+      else
+	return 0;
+    }
+
+  sprintf (prefix_str, "%s/%d", net_str, prefixlen);
+
+  return 1;
+}
+
diff --git a/lib/prefix.h b/lib/prefix.h
new file mode 100644
index 0000000..7d7cde6
--- /dev/null
+++ b/lib/prefix.h
@@ -0,0 +1,161 @@
+/*
+ * Prefix structure.
+ * Copyright (C) 1998 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 _ZEBRA_PREFIX_H
+#define _ZEBRA_PREFIX_H
+
+/* IPv4 and IPv6 unified prefix structure. */
+struct prefix
+{
+  u_char family;
+  u_char prefixlen;
+  union 
+  {
+    u_char prefix;
+    struct in_addr prefix4;
+#ifdef HAVE_IPV6
+    struct in6_addr prefix6;
+#endif /* HAVE_IPV6 */
+    struct 
+    {
+      struct in_addr id;
+      struct in_addr adv_router;
+    } lp;
+    u_char val[8];
+  } u __attribute__ ((aligned (8)));
+};
+
+/* IPv4 prefix structure. */
+struct prefix_ipv4
+{
+  u_char family;
+  u_char prefixlen;
+  struct in_addr prefix __attribute__ ((aligned (8)));
+};
+
+/* IPv6 prefix structure. */
+#ifdef HAVE_IPV6
+struct prefix_ipv6
+{
+  u_char family;
+  u_char prefixlen;
+  struct in6_addr prefix __attribute__ ((aligned (8)));
+};
+#endif /* HAVE_IPV6 */
+
+struct prefix_ls
+{
+  u_char family;
+  u_char prefixlen;
+  struct in_addr id __attribute__ ((aligned (8)));
+  struct in_addr adv_router;
+};
+
+/* Prefix for routing distinguisher. */
+struct prefix_rd
+{
+  u_char family;
+  u_char prefixlen;
+  u_char val[8] __attribute__ ((aligned (8)));
+};
+
+#ifndef INET_ADDRSTRLEN
+#define INET_ADDRSTRLEN 16
+#endif /* INET_ADDRSTRLEN */
+
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46
+#endif /* INET6_ADDRSTRLEN */
+
+#ifndef INET6_BUFSIZ
+#define INET6_BUFSIZ 51
+#endif /* INET6_BUFSIZ */
+
+/* Max bit/byte length of IPv4 address. */
+#define IPV4_MAX_BYTELEN    4
+#define IPV4_MAX_BITLEN    32
+#define IPV4_MAX_PREFIXLEN 32
+#define IPV4_ADDR_CMP(D,S)   memcmp ((D), (S), IPV4_MAX_BYTELEN)
+#define IPV4_ADDR_SAME(D,S)  (memcmp ((D), (S), IPV4_MAX_BYTELEN) == 0)
+#define IPV4_ADDR_COPY(D,S)  memcpy ((D), (S), IPV4_MAX_BYTELEN)
+
+#define IPV4_NET0(a)    ((((u_int32_t) (a)) & 0xff000000) == 0x00000000)
+#define IPV4_NET127(a)  ((((u_int32_t) (a)) & 0xff000000) == 0x7f000000)
+
+/* Max bit/byte length of IPv6 address. */
+#define IPV6_MAX_BYTELEN    16
+#define IPV6_MAX_BITLEN    128
+#define IPV6_MAX_PREFIXLEN 128
+#define IPV6_ADDR_CMP(D,S)   memcmp ((D), (S), IPV6_MAX_BYTELEN)
+#define IPV6_ADDR_SAME(D,S)  (memcmp ((D), (S), IPV6_MAX_BYTELEN) == 0)
+#define IPV6_ADDR_COPY(D,S)  memcpy ((D), (S), IPV6_MAX_BYTELEN)
+
+/* Count prefix size from mask length */
+#define PSIZE(a) (((a) + 7) / (8))
+
+/* Prefix's family member. */
+#define PREFIX_FAMILY(p)  ((p)->family)
+
+/* Prototypes. */
+int afi2family (int);
+int family2afi (int);
+
+int prefix2str (struct prefix *, char *, int);
+int str2prefix (char *, struct prefix *);
+struct prefix *prefix_new ();
+void prefix_free (struct prefix *p);
+
+struct prefix_ipv4 *prefix_ipv4_new ();
+void prefix_ipv4_free ();
+int str2prefix_ipv4 (char *, struct prefix_ipv4 *);
+void apply_mask_ipv4 (struct prefix_ipv4 *);
+int prefix_blen (struct prefix *);
+u_char ip_masklen (struct in_addr);
+int prefix_ipv4_any (struct prefix_ipv4 *);
+void masklen2ip (int, struct in_addr *);
+void apply_classful_mask_ipv4 (struct prefix_ipv4 *);
+
+char *prefix_family_str (struct prefix *p);
+struct prefix *sockunion2prefix ();
+struct prefix *sockunion2hostprefix ();
+
+#ifdef HAVE_IPV6
+struct prefix_ipv6 *prefix_ipv6_new ();
+void prefix_ipv6_free ();
+struct prefix *str2routev6 (char *);
+int str2prefix_ipv6 (char *str, struct prefix_ipv6 *p);
+void apply_mask_ipv6 (struct prefix_ipv6 *p);
+void str2in6_addr (char *str, struct in6_addr *addr);
+void masklen2ip6 (int masklen, struct in6_addr *netmask);
+int ip6_masklen (struct in6_addr netmask);
+#endif /* HAVE_IPV6 */
+
+void apply_mask (struct prefix *);
+int prefix_match (struct prefix *n, struct prefix *p);
+int prefix_same (struct prefix *, struct prefix *);
+int prefix_cmp (struct prefix *, struct prefix *);
+void prefix_copy (struct prefix *, struct prefix *);
+
+int all_digit (char *);
+int netmask_str2prefix_str (char *, char *, char *);
+
+#endif /* _ZEBRA_PREFIX_H */
diff --git a/lib/print_version.c b/lib/print_version.c
new file mode 100644
index 0000000..6b4064d
--- /dev/null
+++ b/lib/print_version.c
@@ -0,0 +1,31 @@
+/* Print version function.
+ * Copyright (C) 1997, 98 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.  
+ */
+
+#include <zebra.h>
+
+#include "version.h"
+
+void
+print_version (char *progname)
+{
+  printf ("%s version %s (%s)\n", progname, ZEBRA_VERSION, host_name);
+  printf ("Copyright 1996-2001, Kunihiro Ishiguro\n");
+}
diff --git a/lib/regex-gnu.h b/lib/regex-gnu.h
new file mode 100644
index 0000000..d88ab92
--- /dev/null
+++ b/lib/regex-gnu.h
@@ -0,0 +1,542 @@
+/* Definitions for data structures and routines for the regular
+   expression library, version 0.12.
+   Copyright (C) 1985,89,90,91,92,93,95,96,97,98 Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.  Its master source is NOT part of
+   the C library, however.  The master source lives in /gd/gnu/lib.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _REGEX_H
+#define _REGEX_H 1
+
+/* Allow the use in C++ code.  */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* POSIX says that <sys/types.h> must be included (by the caller) before
+   <regex.h>.  */
+
+#if !defined _POSIX_C_SOURCE && !defined _POSIX_SOURCE && defined VMS
+/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
+   should be there.  */
+# include <stddef.h>
+#endif
+
+/* The following two types have to be signed and unsigned integer type
+   wide enough to hold a value of a pointer.  For most ANSI compilers
+   ptrdiff_t and size_t should be likely OK.  Still size of these two
+   types is 2 for Microsoft C.  Ugh... */
+typedef long int s_reg_t;
+typedef unsigned long int active_reg_t;
+
+/* The following bits are used to determine the regexp syntax we
+   recognize.  The set/not-set meanings are chosen so that Emacs syntax
+   remains the value 0.  The bits are given in alphabetical order, and
+   the definitions shifted by one from the previous bit; thus, when we
+   add or remove a bit, only one other definition need change.  */
+typedef unsigned long int reg_syntax_t;
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+   If set, then such a \ quotes the following character.  */
+#define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1)
+
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+     literals.
+   If set, then \+ and \? are operators and + and ? are literals.  */
+#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
+
+/* If this bit is set, then character classes are supported.  They are:
+     [:alpha:], [:upper:], [:lower:],  [:digit:], [:alnum:], [:xdigit:],
+     [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
+   If not set, then character classes are not supported.  */
+#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+     expressions, of course).
+   If this bit is not set, then it depends:
+        ^  is an anchor if it is at the beginning of a regular
+           expression or after an open-group or an alternation operator;
+        $  is an anchor if it is at the end of a regular expression, or
+           before a close-group or an alternation operator.
+
+   This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
+   POSIX draft 11.2 says that * etc. in leading positions is undefined.
+   We already implemented a previous draft which made those constructs
+   invalid, though, so we haven't changed the code back.  */
+#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* If this bit is set, then special characters are always special
+     regardless of where they are in the pattern.
+   If this bit is not set, then special characters are special only in
+     some contexts; otherwise they are ordinary.  Specifically,
+     * + ? and intervals are only special when not after the beginning,
+     open-group, or alternation operator.  */
+#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+     immediately after an alternation or begin-group operator.  */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+   If not set, then it doesn't.  */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+   If not set, then it does.  */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+   If not set, they do.  */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+     interval, depending on RE_NO_BK_BRACES.
+   If not set, \{, \}, {, and } are literals.  */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+   If not set, they are.  */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+   If not set, newline is literal.  */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+     are literals.
+  If not set, then `\{...\}' defines an interval.  */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+   If not set, \(...\) defines a group, and ( and ) are literals.  */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+   If not set, then \<digit> is a back-reference.  */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal.
+   If not set, then \| is an alternation operator, and | is literal.  */
+#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* If this bit is set, then an ending range point collating higher
+     than the starting range point, as in [z-a], is invalid.
+   If not set, then when ending range point collates higher than the
+     starting range point, the range is ignored.  */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+   If not set, then an unmatched ) is invalid.  */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* If this bit is set, succeed as soon as we match the whole pattern,
+   without further backtracking.  */
+#define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1)
+
+/* If this bit is set, do not process the GNU regex operators.
+   If not set, then the GNU regex operators are recognized. */
+#define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1)
+
+/* If this bit is set, turn on internal regex debugging.
+   If not set, and debugging was on, turn it off.
+   This only works if regex.c is compiled -DDEBUG.
+   We define this bit always, so that all that's needed to turn on
+   debugging is to recompile regex.c; the calling code can always have
+   this bit set, and it won't affect anything in the normal case. */
+#define RE_DEBUG (RE_NO_GNU_OPS << 1)
+
+/* This global variable defines the particular regexp syntax to use (for
+   some interfaces).  When a regexp is compiled, the syntax used is
+   stored in the pattern buffer, so changing this does not affect
+   already-compiled regexps.  */
+extern reg_syntax_t re_syntax_options;
+
+/* Define combinations of the above bits for the standard possibilities.
+   (The [[[ comments delimit what gets put into the Texinfo file, so
+   don't delete them!)  */
+/* [[[begin syntaxes]]] */
+#define RE_SYNTAX_EMACS 0
+
+#define RE_SYNTAX_AWK							\
+  (RE_BACKSLASH_ESCAPE_IN_LISTS   | RE_DOT_NOT_NULL			\
+   | RE_NO_BK_PARENS              | RE_NO_BK_REFS			\
+   | RE_NO_BK_VBAR                | RE_NO_EMPTY_RANGES			\
+   | RE_DOT_NEWLINE		  | RE_CONTEXT_INDEP_ANCHORS		\
+   | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS)
+
+#define RE_SYNTAX_GNU_AWK						\
+  ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DEBUG)	\
+   & ~(RE_DOT_NOT_NULL | RE_INTERVALS | RE_CONTEXT_INDEP_OPS))
+
+#define RE_SYNTAX_POSIX_AWK 						\
+  (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS		\
+   | RE_INTERVALS	    | RE_NO_GNU_OPS)
+
+#define RE_SYNTAX_GREP							\
+  (RE_BK_PLUS_QM              | RE_CHAR_CLASSES				\
+   | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS				\
+   | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP							\
+  (RE_CHAR_CLASSES        | RE_CONTEXT_INDEP_ANCHORS			\
+   | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE			\
+   | RE_NEWLINE_ALT       | RE_NO_BK_PARENS				\
+   | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_EGREP						\
+  (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
+
+/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff.  */
+#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
+
+#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax.  */
+#define _RE_SYNTAX_POSIX_COMMON						\
+  (RE_CHAR_CLASSES | RE_DOT_NEWLINE      | RE_DOT_NOT_NULL		\
+   | RE_INTERVALS  | RE_NO_EMPTY_RANGES)
+
+#define RE_SYNTAX_POSIX_BASIC						\
+  (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
+
+/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+   RE_LIMITED_OPS, i.e., \? \+ \| are not recognized.  Actually, this
+   isn't minimal, since other operators, such as \`, aren't disabled.  */
+#define RE_SYNTAX_POSIX_MINIMAL_BASIC					\
+  (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
+
+#define RE_SYNTAX_POSIX_EXTENDED					\
+  (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS			\
+   | RE_CONTEXT_INDEP_OPS  | RE_NO_BK_BRACES				\
+   | RE_NO_BK_PARENS       | RE_NO_BK_VBAR				\
+   | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
+   replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added.  */
+#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED				\
+  (_RE_SYNTAX_POSIX_COMMON  | RE_CONTEXT_INDEP_ANCHORS			\
+   | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES				\
+   | RE_NO_BK_PARENS        | RE_NO_BK_REFS				\
+   | RE_NO_BK_VBAR	    | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+
+/* Maximum number of duplicates an interval can allow.  Some systems
+   (erroneously) define this in other header files, but we want our
+   value, so remove any previous define.  */
+#ifdef RE_DUP_MAX
+# undef RE_DUP_MAX
+#endif
+/* If sizeof(int) == 2, then ((1 << 15) - 1) overflows.  */
+#define RE_DUP_MAX (0x7fff)
+
+
+/* POSIX `cflags' bits (i.e., information for `regcomp').  */
+
+/* If this bit is set, then use extended regular expression syntax.
+   If not set, then use basic regular expression syntax.  */
+#define REG_EXTENDED 1
+
+/* If this bit is set, then ignore case when matching.
+   If not set, then case is significant.  */
+#define REG_ICASE (REG_EXTENDED << 1)
+
+/* If this bit is set, then anchors do not match at newline
+     characters in the string.
+   If not set, then anchors do match at newlines.  */
+#define REG_NEWLINE (REG_ICASE << 1)
+
+/* If this bit is set, then report only success or fail in regexec.
+   If not set, then returns differ between not matching and errors.  */
+#define REG_NOSUB (REG_NEWLINE << 1)
+
+
+/* POSIX `eflags' bits (i.e., information for regexec).  */
+
+/* If this bit is set, then the beginning-of-line operator doesn't match
+     the beginning of the string (presumably because it's not the
+     beginning of a line).
+   If not set, then the beginning-of-line operator does match the
+     beginning of the string.  */
+#define REG_NOTBOL 1
+
+/* Like REG_NOTBOL, except for the end-of-line.  */
+#define REG_NOTEOL (1 << 1)
+
+
+/* If any error codes are removed, changed, or added, update the
+   `re_error_msg' table in regex.c.  */
+typedef enum
+{
+#ifdef _XOPEN_SOURCE
+  REG_ENOSYS = -1,	/* This will never happen for this implementation.  */
+#endif
+
+  REG_NOERROR = 0,	/* Success.  */
+  REG_NOMATCH,		/* Didn't find a match (for regexec).  */
+
+  /* POSIX regcomp return error codes.  (In the order listed in the
+     standard.)  */
+  REG_BADPAT,		/* Invalid pattern.  */
+  REG_ECOLLATE,		/* Not implemented.  */
+  REG_ECTYPE,		/* Invalid character class name.  */
+  REG_EESCAPE,		/* Trailing backslash.  */
+  REG_ESUBREG,		/* Invalid back reference.  */
+  REG_EBRACK,		/* Unmatched left bracket.  */
+  REG_EPAREN,		/* Parenthesis imbalance.  */
+  REG_EBRACE,		/* Unmatched \{.  */
+  REG_BADBR,		/* Invalid contents of \{\}.  */
+  REG_ERANGE,		/* Invalid range end.  */
+  REG_ESPACE,		/* Ran out of memory.  */
+  REG_BADRPT,		/* No preceding re for repetition op.  */
+
+  /* Error codes we've added.  */
+  REG_EEND,		/* Premature end.  */
+  REG_ESIZE,		/* Compiled pattern bigger than 2^16 bytes.  */
+  REG_ERPAREN		/* Unmatched ) or \); not returned from regcomp.  */
+} reg_errcode_t;
+
+/* This data structure represents a compiled pattern.  Before calling
+   the pattern compiler, the fields `buffer', `allocated', `fastmap',
+   `translate', and `no_sub' can be set.  After the pattern has been
+   compiled, the `re_nsub' field is available.  All other fields are
+   private to the regex routines.  */
+
+#ifndef RE_TRANSLATE_TYPE
+# define RE_TRANSLATE_TYPE char *
+#endif
+
+struct re_pattern_buffer
+{
+/* [[[begin pattern_buffer]]] */
+	/* Space that holds the compiled pattern.  It is declared as
+          `unsigned char *' because its elements are
+           sometimes used as array indexes.  */
+  unsigned char *buffer;
+
+	/* Number of bytes to which `buffer' points.  */
+  unsigned long int allocated;
+
+	/* Number of bytes actually used in `buffer'.  */
+  unsigned long int used;
+
+        /* Syntax setting with which the pattern was compiled.  */
+  reg_syntax_t syntax;
+
+        /* Pointer to a fastmap, if any, otherwise zero.  re_search uses
+           the fastmap, if there is one, to skip over impossible
+           starting points for matches.  */
+  char *fastmap;
+
+        /* Either a translate table to apply to all characters before
+           comparing them, or zero for no translation.  The translation
+           is applied to a pattern when it is compiled and to a string
+           when it is matched.  */
+  RE_TRANSLATE_TYPE translate;
+
+	/* Number of subexpressions found by the compiler.  */
+  size_t re_nsub;
+
+        /* Zero if this pattern cannot match the empty string, one else.
+           Well, in truth it's used only in `re_search_2', to see
+           whether or not we should use the fastmap, so we don't set
+           this absolutely perfectly; see `re_compile_fastmap' (the
+           `duplicate' case).  */
+  unsigned can_be_null : 1;
+
+        /* If REGS_UNALLOCATED, allocate space in the `regs' structure
+             for `max (RE_NREGS, re_nsub + 1)' groups.
+           If REGS_REALLOCATE, reallocate space if necessary.
+           If REGS_FIXED, use what's there.  */
+#define REGS_UNALLOCATED 0
+#define REGS_REALLOCATE 1
+#define REGS_FIXED 2
+  unsigned regs_allocated : 2;
+
+        /* Set to zero when `regex_compile' compiles a pattern; set to one
+           by `re_compile_fastmap' if it updates the fastmap.  */
+  unsigned fastmap_accurate : 1;
+
+        /* If set, `re_match_2' does not return information about
+           subexpressions.  */
+  unsigned no_sub : 1;
+
+        /* If set, a beginning-of-line anchor doesn't match at the
+           beginning of the string.  */
+  unsigned not_bol : 1;
+
+        /* Similarly for an end-of-line anchor.  */
+  unsigned not_eol : 1;
+
+        /* If true, an anchor at a newline matches.  */
+  unsigned newline_anchor : 1;
+
+/* [[[end pattern_buffer]]] */
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+/* Type for byte offsets within the string.  POSIX mandates this.  */
+typedef int regoff_t;
+
+
+/* This is the structure we store register match data in.  See
+   regex.texinfo for a full description of what registers match.  */
+struct re_registers
+{
+  unsigned num_regs;
+  regoff_t *start;
+  regoff_t *end;
+};
+
+
+/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
+   `re_match_2' returns information about at least this many registers
+   the first time a `regs' structure is passed.  */
+#ifndef RE_NREGS
+# define RE_NREGS 30
+#endif
+
+
+/* POSIX specification for registers.  Aside from the different names than
+   `re_registers', POSIX uses an array of structures, instead of a
+   structure of arrays.  */
+typedef struct
+{
+  regoff_t rm_so;  /* Byte offset from string's start to substring's start.  */
+  regoff_t rm_eo;  /* Byte offset from string's start to substring's end.  */
+} regmatch_t;
+
+/* Declarations for routines.  */
+
+/* To avoid duplicating every routine declaration -- once with a
+   prototype (if we are ANSI), and once without (if we aren't) -- we
+   use the following macro to declare argument types.  This
+   unfortunately clutters up the declarations a bit, but I think it's
+   worth it.  */
+
+#if __STDC__
+
+# define _RE_ARGS(args) args
+
+#else /* not __STDC__ */
+
+# define _RE_ARGS(args) ()
+
+#endif /* not __STDC__ */
+
+/* Sets the current default syntax to SYNTAX, and return the old syntax.
+   You can also simply assign to the `re_syntax_options' variable.  */
+extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
+
+/* Compile the regular expression PATTERN, with length LENGTH
+   and syntax given by the global `re_syntax_options', into the buffer
+   BUFFER.  Return NULL if successful, and an error string if not.  */
+extern const char *re_compile_pattern
+  _RE_ARGS ((const char *pattern, size_t length,
+             struct re_pattern_buffer *buffer));
+
+
+/* Compile a fastmap for the compiled pattern in BUFFER; used to
+   accelerate searches.  Return 0 if successful and -2 if was an
+   internal error.  */
+extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
+
+
+/* Search in the string STRING (with length LENGTH) for the pattern
+   compiled into BUFFER.  Start searching at position START, for RANGE
+   characters.  Return the starting position of the match, -1 for no
+   match, or -2 for an internal error.  Also return register
+   information in REGS (if REGS and BUFFER->no_sub are nonzero).  */
+extern int re_search
+  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+            int length, int start, int range, struct re_registers *regs));
+
+
+/* Like `re_search', but search in the concatenation of STRING1 and
+   STRING2.  Also, stop searching at index START + STOP.  */
+extern int re_search_2
+  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+             int length1, const char *string2, int length2,
+             int start, int range, struct re_registers *regs, int stop));
+
+
+/* Like `re_search', but return how many characters in STRING the regexp
+   in BUFFER matched, starting at position START.  */
+extern int re_match
+  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+             int length, int start, struct re_registers *regs));
+
+
+/* Relates to `re_match' as `re_search_2' relates to `re_search'.  */
+extern int re_match_2
+  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+             int length1, const char *string2, int length2,
+             int start, struct re_registers *regs, int stop));
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+   ENDS.  Subsequent matches using BUFFER and REGS will use this memory
+   for recording register information.  STARTS and ENDS must be
+   allocated with malloc, and must each be at least `NUM_REGS * sizeof
+   (regoff_t)' bytes long.
+
+   If NUM_REGS == 0, then subsequent matches should allocate their own
+   register data.
+
+   Unless this function is called, the first search or match using
+   PATTERN_BUFFER will allocate its own register data, without
+   freeing the old data.  */
+extern void re_set_registers
+  _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
+             unsigned num_regs, regoff_t *starts, regoff_t *ends));
+
+#if defined _REGEX_RE_COMP || defined _LIBC
+# ifndef _CRAY
+/* 4.2 bsd compatibility.  */
+extern char *re_comp _RE_ARGS ((const char *));
+extern int re_exec _RE_ARGS ((const char *));
+# endif
+#endif
+
+/* POSIX compatibility.  */
+extern int regcomp _RE_ARGS ((regex_t *__preg, const char *__pattern,
+			      int __cflags));
+
+extern int regexec _RE_ARGS ((const regex_t *__preg,
+			      const char *__string, size_t __nmatch,
+			      regmatch_t __pmatch[], int __eflags));
+
+extern size_t regerror _RE_ARGS ((int __errcode, const regex_t *__preg,
+				  char *__errbuf, size_t __errbuf_size));
+
+extern void regfree _RE_ARGS ((regex_t *__preg));
+
+
+#ifdef __cplusplus
+}
+#endif	/* C++ */
+
+#endif /* regex.h */
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
diff --git a/lib/regex.c b/lib/regex.c
new file mode 100644
index 0000000..8c7acd5
--- /dev/null
+++ b/lib/regex.c
@@ -0,0 +1,5891 @@
+/* Extended regular expression matching and search library,
+   version 0.12.
+   (Implements POSIX draft P1003.2/D11.2, except for some of the
+   internationalization features.)
+   Copyright (C) 1993, 94, 95, 96, 97, 98, 99 Free Software Foundation, Inc.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* AIX requires this to be the first thing in the file. */
+#if defined _AIX && !defined REGEX_MALLOC
+  #pragma alloca
+#endif
+
+#undef	_GNU_SOURCE
+#define _GNU_SOURCE
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef PARAMS
+# if defined __GNUC__ || (defined __STDC__ && __STDC__)
+#  define PARAMS(args) args
+# else
+#  define PARAMS(args) ()
+# endif  /* GCC.  */
+#endif  /* Not PARAMS.  */
+
+#if defined STDC_HEADERS && !defined emacs
+# include <stddef.h>
+#else
+/* We need this for `regex.h', and perhaps for the Emacs include files.  */
+# include <sys/types.h>
+#endif
+
+#define WIDE_CHAR_SUPPORT (HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_BTOWC)
+
+/* For platform which support the ISO C amendement 1 functionality we
+   support user defined character classes.  */
+#if defined _LIBC || WIDE_CHAR_SUPPORT
+/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>.  */
+# include <wchar.h>
+# include <wctype.h>
+#endif
+
+#ifdef _LIBC
+/* We have to keep the namespace clean.  */
+# define regfree(preg) __regfree (preg)
+# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef)
+# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags)
+# define regerror(errcode, preg, errbuf, errbuf_size) \
+	__regerror(errcode, preg, errbuf, errbuf_size)
+# define re_set_registers(bu, re, nu, st, en) \
+	__re_set_registers (bu, re, nu, st, en)
+# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \
+	__re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
+# define re_match(bufp, string, size, pos, regs) \
+	__re_match (bufp, string, size, pos, regs)
+# define re_search(bufp, string, size, startpos, range, regs) \
+	__re_search (bufp, string, size, startpos, range, regs)
+# define re_compile_pattern(pattern, length, bufp) \
+	__re_compile_pattern (pattern, length, bufp)
+# define re_set_syntax(syntax) __re_set_syntax (syntax)
+# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \
+	__re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop)
+# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp)
+
+#define btowc __btowc
+#endif
+
+/* This is for other GNU distributions with internationalized messages.  */
+#if HAVE_LIBINTL_H || defined _LIBC
+# include <libintl.h>
+#else
+# define gettext(msgid) (msgid)
+#endif
+
+#ifndef gettext_noop
+/* This define is so xgettext can find the internationalizable
+   strings.  */
+# define gettext_noop(String) String
+#endif
+
+/* The `emacs' switch turns on certain matching commands
+   that make sense only in Emacs. */
+#ifdef emacs
+
+# include "lisp.h"
+# include "buffer.h"
+# include "syntax.h"
+
+#else  /* not emacs */
+
+/* If we are not linking with Emacs proper,
+   we can't use the relocating allocator
+   even if config.h says that we can.  */
+# undef REL_ALLOC
+
+# if defined STDC_HEADERS || defined _LIBC
+#  include <stdlib.h>
+# else
+char *malloc ();
+char *realloc ();
+# endif
+
+/* When used in Emacs's lib-src, we need to get bzero and bcopy somehow.
+   If nothing else has been done, use the method below.  */
+# ifdef INHIBIT_STRING_HEADER
+#  if !(defined HAVE_BZERO && defined HAVE_BCOPY)
+#   if !defined bzero && !defined bcopy
+#    undef INHIBIT_STRING_HEADER
+#   endif
+#  endif
+# endif
+
+/* This is the normal way of making sure we have a bcopy and a bzero.
+   This is used in most programs--a few other programs avoid this
+   by defining INHIBIT_STRING_HEADER.  */
+# ifndef INHIBIT_STRING_HEADER
+#  if defined HAVE_STRING_H || defined STDC_HEADERS || defined _LIBC
+#   include <string.h>
+#   ifndef bzero
+#    ifndef _LIBC
+#     define bzero(s, n)	(memset (s, '\0', n), (s))
+#    else
+#     define bzero(s, n)	__bzero (s, n)
+#    endif
+#   endif
+#  else
+#   include <strings.h>
+#   ifndef memcmp
+#    define memcmp(s1, s2, n)	bcmp (s1, s2, n)
+#   endif
+#   ifndef memcpy
+#    define memcpy(d, s, n)	(bcopy (s, d, n), (d))
+#   endif
+#  endif
+# endif
+
+/* Define the syntax stuff for \<, \>, etc.  */
+
+/* This must be nonzero for the wordchar and notwordchar pattern
+   commands in re_match_2.  */
+# ifndef Sword
+#  define Sword 1
+# endif
+
+# ifdef SWITCH_ENUM_BUG
+#  define SWITCH_ENUM_CAST(x) ((int)(x))
+# else
+#  define SWITCH_ENUM_CAST(x) (x)
+# endif
+
+/* How many characters in the character set.  */
+# define CHAR_SET_SIZE 256
+
+# ifdef SYNTAX_TABLE
+
+extern char *re_syntax_table;
+
+# else /* not SYNTAX_TABLE */
+
+static char re_syntax_table[CHAR_SET_SIZE];
+
+static void
+init_syntax_once ()
+{
+   register int c;
+   static int done;
+
+   if (done)
+     return;
+
+   bzero (re_syntax_table, sizeof re_syntax_table);
+
+   for (c = 'a'; c <= 'z'; c++)
+     re_syntax_table[c] = Sword;
+
+   for (c = 'A'; c <= 'Z'; c++)
+     re_syntax_table[c] = Sword;
+
+   for (c = '0'; c <= '9'; c++)
+     re_syntax_table[c] = Sword;
+
+   re_syntax_table['_'] = Sword;
+
+   done = 1;
+}
+
+# endif /* not SYNTAX_TABLE */
+
+# define SYNTAX(c) re_syntax_table[c]
+
+#endif /* not emacs */
+
+/* Get the interface, including the syntax bits.  */
+#include <regex-gnu.h>
+
+/* isalpha etc. are used for the character classes.  */
+#include <ctype.h>
+
+/* Jim Meyering writes:
+
+   "... Some ctype macros are valid only for character codes that
+   isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when
+   using /bin/cc or gcc but without giving an ansi option).  So, all
+   ctype uses should be through macros like ISPRINT...  If
+   STDC_HEADERS is defined, then autoconf has verified that the ctype
+   macros don't need to be guarded with references to isascii. ...
+   Defining isascii to 1 should let any compiler worth its salt
+   eliminate the && through constant folding."
+   Solaris defines some of these symbols so we must undefine them first.  */
+
+#undef ISASCII
+#if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII)
+# define ISASCII(c) 1
+#else
+# define ISASCII(c) isascii(c)
+#endif
+
+#ifdef isblank
+# define ISBLANK(c) (ISASCII (c) && isblank (c))
+#else
+# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+#endif
+#ifdef isgraph
+# define ISGRAPH(c) (ISASCII (c) && isgraph (c))
+#else
+# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
+#endif
+
+#undef ISPRINT
+#define ISPRINT(c) (ISASCII (c) && isprint (c))
+#define ISDIGIT(c) (ISASCII (c) && isdigit (c))
+#define ISALNUM(c) (ISASCII (c) && isalnum (c))
+#define ISALPHA(c) (ISASCII (c) && isalpha (c))
+#define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
+#define ISLOWER(c) (ISASCII (c) && islower (c))
+#define ISPUNCT(c) (ISASCII (c) && ispunct (c))
+#define ISSPACE(c) (ISASCII (c) && isspace (c))
+#define ISUPPER(c) (ISASCII (c) && isupper (c))
+#define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
+
+#ifdef _tolower
+# define TOLOWER(c) _tolower(c)
+#else
+# define TOLOWER(c) tolower(c)
+#endif
+
+#ifndef NULL
+# define NULL (void *)0
+#endif
+
+/* We remove any previous definition of `SIGN_EXTEND_CHAR',
+   since ours (we hope) works properly with all combinations of
+   machines, compilers, `char' and `unsigned char' argument types.
+   (Per Bothner suggested the basic approach.)  */
+#undef SIGN_EXTEND_CHAR
+#if __STDC__
+# define SIGN_EXTEND_CHAR(c) ((signed char) (c))
+#else  /* not __STDC__ */
+/* As in Harbison and Steele.  */
+# define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128)
+#endif
+
+/* Should we use malloc or alloca?  If REGEX_MALLOC is not defined, we
+   use `alloca' instead of `malloc'.  This is because using malloc in
+   re_search* or re_match* could cause memory leaks when C-g is used in
+   Emacs; also, malloc is slower and causes storage fragmentation.  On
+   the other hand, malloc is more portable, and easier to debug.
+
+   Because we sometimes use alloca, some routines have to be macros,
+   not functions -- `alloca'-allocated space disappears at the end of the
+   function it is called in.  */
+
+#ifdef REGEX_MALLOC
+
+# define REGEX_ALLOCATE malloc
+# define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize)
+# define REGEX_FREE free
+
+#else /* not REGEX_MALLOC  */
+
+/* Emacs already defines alloca, sometimes.  */
+# ifndef alloca
+
+/* Make alloca work the best possible way.  */
+#  ifdef __GNUC__
+#   define alloca __builtin_alloca
+#  else /* not __GNUC__ */
+#   if HAVE_ALLOCA_H
+#    include <alloca.h>
+#   endif /* HAVE_ALLOCA_H */
+#  endif /* not __GNUC__ */
+
+# endif /* not alloca */
+
+# define REGEX_ALLOCATE alloca
+
+/* Assumes a `char *destination' variable.  */
+# define REGEX_REALLOCATE(source, osize, nsize)				\
+  (destination = (char *) alloca (nsize),				\
+   memcpy (destination, source, osize))
+
+/* No need to do anything to free, after alloca.  */
+# define REGEX_FREE(arg) ((void)0) /* Do nothing!  But inhibit gcc warning.  */
+
+#endif /* not REGEX_MALLOC */
+
+/* Define how to allocate the failure stack.  */
+
+#if defined REL_ALLOC && defined REGEX_MALLOC
+
+# define REGEX_ALLOCATE_STACK(size)				\
+  r_alloc (&failure_stack_ptr, (size))
+# define REGEX_REALLOCATE_STACK(source, osize, nsize)		\
+  r_re_alloc (&failure_stack_ptr, (nsize))
+# define REGEX_FREE_STACK(ptr)					\
+  r_alloc_free (&failure_stack_ptr)
+
+#else /* not using relocating allocator */
+
+# ifdef REGEX_MALLOC
+
+#  define REGEX_ALLOCATE_STACK malloc
+#  define REGEX_REALLOCATE_STACK(source, osize, nsize) realloc (source, nsize)
+#  define REGEX_FREE_STACK free
+
+# else /* not REGEX_MALLOC */
+
+#  define REGEX_ALLOCATE_STACK alloca
+
+#  define REGEX_REALLOCATE_STACK(source, osize, nsize)			\
+   REGEX_REALLOCATE (source, osize, nsize)
+/* No need to explicitly free anything.  */
+#  define REGEX_FREE_STACK(arg)
+
+# endif /* not REGEX_MALLOC */
+#endif /* not using relocating allocator */
+
+
+/* True if `size1' is non-NULL and PTR is pointing anywhere inside
+   `string1' or just past its end.  This works if PTR is NULL, which is
+   a good thing.  */
+#define FIRST_STRING_P(ptr) 					\
+  (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
+
+/* (Re)Allocate N items of type T using malloc, or fail.  */
+#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t)))
+#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t)))
+#define RETALLOC_IF(addr, n, t) \
+  if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), t)
+#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t)))
+
+#define BYTEWIDTH 8 /* In bits.  */
+
+#define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
+
+#undef MAX
+#undef MIN
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+typedef char boolean;
+#define false 0
+#define true 1
+
+static int re_match_2_internal PARAMS ((struct re_pattern_buffer *bufp,
+					const char *string1, int size1,
+					const char *string2, int size2,
+					int pos,
+					struct re_registers *regs,
+					int stop));
+
+/* These are the command codes that appear in compiled regular
+   expressions.  Some opcodes are followed by argument bytes.  A
+   command code can specify any interpretation whatsoever for its
+   arguments.  Zero bytes may appear in the compiled regular expression.  */
+
+typedef enum
+{
+  no_op = 0,
+
+  /* Succeed right away--no more backtracking.  */
+  succeed,
+
+        /* Followed by one byte giving n, then by n literal bytes.  */
+  exactn,
+
+        /* Matches any (more or less) character.  */
+  anychar,
+
+        /* Matches any one char belonging to specified set.  First
+           following byte is number of bitmap bytes.  Then come bytes
+           for a bitmap saying which chars are in.  Bits in each byte
+           are ordered low-bit-first.  A character is in the set if its
+           bit is 1.  A character too large to have a bit in the map is
+           automatically not in the set.  */
+  charset,
+
+        /* Same parameters as charset, but match any character that is
+           not one of those specified.  */
+  charset_not,
+
+        /* Start remembering the text that is matched, for storing in a
+           register.  Followed by one byte with the register number, in
+           the range 0 to one less than the pattern buffer's re_nsub
+           field.  Then followed by one byte with the number of groups
+           inner to this one.  (This last has to be part of the
+           start_memory only because we need it in the on_failure_jump
+           of re_match_2.)  */
+  start_memory,
+
+        /* Stop remembering the text that is matched and store it in a
+           memory register.  Followed by one byte with the register
+           number, in the range 0 to one less than `re_nsub' in the
+           pattern buffer, and one byte with the number of inner groups,
+           just like `start_memory'.  (We need the number of inner
+           groups here because we don't have any easy way of finding the
+           corresponding start_memory when we're at a stop_memory.)  */
+  stop_memory,
+
+        /* Match a duplicate of something remembered. Followed by one
+           byte containing the register number.  */
+  duplicate,
+
+        /* Fail unless at beginning of line.  */
+  begline,
+
+        /* Fail unless at end of line.  */
+  endline,
+
+        /* Succeeds if at beginning of buffer (if emacs) or at beginning
+           of string to be matched (if not).  */
+  begbuf,
+
+        /* Analogously, for end of buffer/string.  */
+  endbuf,
+
+        /* Followed by two byte relative address to which to jump.  */
+  jump,
+
+	/* Same as jump, but marks the end of an alternative.  */
+  jump_past_alt,
+
+        /* Followed by two-byte relative address of place to resume at
+           in case of failure.  */
+  on_failure_jump,
+
+        /* Like on_failure_jump, but pushes a placeholder instead of the
+           current string position when executed.  */
+  on_failure_keep_string_jump,
+
+        /* Throw away latest failure point and then jump to following
+           two-byte relative address.  */
+  pop_failure_jump,
+
+        /* Change to pop_failure_jump if know won't have to backtrack to
+           match; otherwise change to jump.  This is used to jump
+           back to the beginning of a repeat.  If what follows this jump
+           clearly won't match what the repeat does, such that we can be
+           sure that there is no use backtracking out of repetitions
+           already matched, then we change it to a pop_failure_jump.
+           Followed by two-byte address.  */
+  maybe_pop_jump,
+
+        /* Jump to following two-byte address, and push a dummy failure
+           point. This failure point will be thrown away if an attempt
+           is made to use it for a failure.  A `+' construct makes this
+           before the first repeat.  Also used as an intermediary kind
+           of jump when compiling an alternative.  */
+  dummy_failure_jump,
+
+	/* Push a dummy failure point and continue.  Used at the end of
+	   alternatives.  */
+  push_dummy_failure,
+
+        /* Followed by two-byte relative address and two-byte number n.
+           After matching N times, jump to the address upon failure.  */
+  succeed_n,
+
+        /* Followed by two-byte relative address, and two-byte number n.
+           Jump to the address N times, then fail.  */
+  jump_n,
+
+        /* Set the following two-byte relative address to the
+           subsequent two-byte number.  The address *includes* the two
+           bytes of number.  */
+  set_number_at,
+
+  wordchar,	/* Matches any word-constituent character.  */
+  notwordchar,	/* Matches any char that is not a word-constituent.  */
+
+  wordbeg,	/* Succeeds if at word beginning.  */
+  wordend,	/* Succeeds if at word end.  */
+
+  wordbound,	/* Succeeds if at a word boundary.  */
+  notwordbound	/* Succeeds if not at a word boundary.  */
+
+#ifdef emacs
+  ,before_dot,	/* Succeeds if before point.  */
+  at_dot,	/* Succeeds if at point.  */
+  after_dot,	/* Succeeds if after point.  */
+
+	/* Matches any character whose syntax is specified.  Followed by
+           a byte which contains a syntax code, e.g., Sword.  */
+  syntaxspec,
+
+	/* Matches any character whose syntax is not that specified.  */
+  notsyntaxspec
+#endif /* emacs */
+} re_opcode_t;
+
+/* Common operations on the compiled pattern.  */
+
+/* Store NUMBER in two contiguous bytes starting at DESTINATION.  */
+
+#define STORE_NUMBER(destination, number)				\
+  do {									\
+    (destination)[0] = (number) & 0377;					\
+    (destination)[1] = (number) >> 8;					\
+  } while (0)
+
+/* Same as STORE_NUMBER, except increment DESTINATION to
+   the byte after where the number is stored.  Therefore, DESTINATION
+   must be an lvalue.  */
+
+#define STORE_NUMBER_AND_INCR(destination, number)			\
+  do {									\
+    STORE_NUMBER (destination, number);					\
+    (destination) += 2;							\
+  } while (0)
+
+/* Put into DESTINATION a number stored in two contiguous bytes starting
+   at SOURCE.  */
+
+#define EXTRACT_NUMBER(destination, source)				\
+  do {									\
+    (destination) = *(source) & 0377;					\
+    (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8;		\
+  } while (0)
+
+#ifdef DEBUG
+static void extract_number _RE_ARGS ((int *dest, unsigned char *source));
+static void
+extract_number (dest, source)
+    int *dest;
+    unsigned char *source;
+{
+  int temp = SIGN_EXTEND_CHAR (*(source + 1));
+  *dest = *source & 0377;
+  *dest += temp << 8;
+}
+
+# ifndef EXTRACT_MACROS /* To debug the macros.  */
+#  undef EXTRACT_NUMBER
+#  define EXTRACT_NUMBER(dest, src) extract_number (&dest, src)
+# endif /* not EXTRACT_MACROS */
+
+#endif /* DEBUG */
+
+/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number.
+   SOURCE must be an lvalue.  */
+
+#define EXTRACT_NUMBER_AND_INCR(destination, source)			\
+  do {									\
+    EXTRACT_NUMBER (destination, source);				\
+    (source) += 2; 							\
+  } while (0)
+
+#ifdef DEBUG
+static void extract_number_and_incr _RE_ARGS ((int *destination,
+					       unsigned char **source));
+static void
+extract_number_and_incr (destination, source)
+    int *destination;
+    unsigned char **source;
+{
+  extract_number (destination, *source);
+  *source += 2;
+}
+
+# ifndef EXTRACT_MACROS
+#  undef EXTRACT_NUMBER_AND_INCR
+#  define EXTRACT_NUMBER_AND_INCR(dest, src) \
+  extract_number_and_incr (&dest, &src)
+# endif /* not EXTRACT_MACROS */
+
+#endif /* DEBUG */
+
+/* If DEBUG is defined, Regex prints many voluminous messages about what
+   it is doing (if the variable `debug' is nonzero).  If linked with the
+   main program in `iregex.c', you can enter patterns and strings
+   interactively.  And if linked with the main program in `main.c' and
+   the other test files, you can run the already-written tests.  */
+
+#ifdef DEBUG
+
+/* We use standard I/O for debugging.  */
+# include <stdio.h>
+
+/* It is useful to test things that ``must'' be true when debugging.  */
+# include <assert.h>
+
+static int debug;
+
+# define DEBUG_STATEMENT(e) e
+# define DEBUG_PRINT1(x) if (debug) printf (x)
+# define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2)
+# define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3)
+# define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4)
+# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) 				\
+  if (debug) print_partial_compiled_pattern (s, e)
+# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)			\
+  if (debug) print_double_string (w, s1, sz1, s2, sz2)
+
+
+/* Print the fastmap in human-readable form.  */
+
+void
+print_fastmap (fastmap)
+    char *fastmap;
+{
+  unsigned was_a_range = 0;
+  unsigned i = 0;
+
+  while (i < (1 << BYTEWIDTH))
+    {
+      if (fastmap[i++])
+	{
+	  was_a_range = 0;
+          putchar (i - 1);
+          while (i < (1 << BYTEWIDTH)  &&  fastmap[i])
+            {
+              was_a_range = 1;
+              i++;
+            }
+	  if (was_a_range)
+            {
+              printf ("-");
+              putchar (i - 1);
+            }
+        }
+    }
+  putchar ('\n');
+}
+
+
+/* Print a compiled pattern string in human-readable form, starting at
+   the START pointer into it and ending just before the pointer END.  */
+
+void
+print_partial_compiled_pattern (start, end)
+    unsigned char *start;
+    unsigned char *end;
+{
+  int mcnt, mcnt2;
+  unsigned char *p1;
+  unsigned char *p = start;
+  unsigned char *pend = end;
+
+  if (start == NULL)
+    {
+      printf ("(null)\n");
+      return;
+    }
+
+  /* Loop over pattern commands.  */
+  while (p < pend)
+    {
+      printf ("%d:\t", p - start);
+
+      switch ((re_opcode_t) *p++)
+	{
+        case no_op:
+          printf ("/no_op");
+          break;
+
+	case exactn:
+	  mcnt = *p++;
+          printf ("/exactn/%d", mcnt);
+          do
+	    {
+              putchar ('/');
+	      putchar (*p++);
+            }
+          while (--mcnt);
+          break;
+
+	case start_memory:
+          mcnt = *p++;
+          printf ("/start_memory/%d/%d", mcnt, *p++);
+          break;
+
+	case stop_memory:
+          mcnt = *p++;
+	  printf ("/stop_memory/%d/%d", mcnt, *p++);
+          break;
+
+	case duplicate:
+	  printf ("/duplicate/%d", *p++);
+	  break;
+
+	case anychar:
+	  printf ("/anychar");
+	  break;
+
+	case charset:
+        case charset_not:
+          {
+            register int c, last = -100;
+	    register int in_range = 0;
+
+	    printf ("/charset [%s",
+	            (re_opcode_t) *(p - 1) == charset_not ? "^" : "");
+
+            assert (p + *p < pend);
+
+            for (c = 0; c < 256; c++)
+	      if (c / 8 < *p
+		  && (p[1 + (c/8)] & (1 << (c % 8))))
+		{
+		  /* Are we starting a range?  */
+		  if (last + 1 == c && ! in_range)
+		    {
+		      putchar ('-');
+		      in_range = 1;
+		    }
+		  /* Have we broken a range?  */
+		  else if (last + 1 != c && in_range)
+              {
+		      putchar (last);
+		      in_range = 0;
+		    }
+
+		  if (! in_range)
+		    putchar (c);
+
+		  last = c;
+              }
+
+	    if (in_range)
+	      putchar (last);
+
+	    putchar (']');
+
+	    p += 1 + *p;
+	  }
+	  break;
+
+	case begline:
+	  printf ("/begline");
+          break;
+
+	case endline:
+          printf ("/endline");
+          break;
+
+	case on_failure_jump:
+          extract_number_and_incr (&mcnt, &p);
+  	  printf ("/on_failure_jump to %d", p + mcnt - start);
+          break;
+
+	case on_failure_keep_string_jump:
+          extract_number_and_incr (&mcnt, &p);
+  	  printf ("/on_failure_keep_string_jump to %d", p + mcnt - start);
+          break;
+
+	case dummy_failure_jump:
+          extract_number_and_incr (&mcnt, &p);
+  	  printf ("/dummy_failure_jump to %d", p + mcnt - start);
+          break;
+
+	case push_dummy_failure:
+          printf ("/push_dummy_failure");
+          break;
+
+        case maybe_pop_jump:
+          extract_number_and_incr (&mcnt, &p);
+  	  printf ("/maybe_pop_jump to %d", p + mcnt - start);
+	  break;
+
+        case pop_failure_jump:
+	  extract_number_and_incr (&mcnt, &p);
+  	  printf ("/pop_failure_jump to %d", p + mcnt - start);
+	  break;
+
+        case jump_past_alt:
+	  extract_number_and_incr (&mcnt, &p);
+  	  printf ("/jump_past_alt to %d", p + mcnt - start);
+	  break;
+
+        case jump:
+	  extract_number_and_incr (&mcnt, &p);
+  	  printf ("/jump to %d", p + mcnt - start);
+	  break;
+
+        case succeed_n:
+          extract_number_and_incr (&mcnt, &p);
+	  p1 = p + mcnt;
+          extract_number_and_incr (&mcnt2, &p);
+	  printf ("/succeed_n to %d, %d times", p1 - start, mcnt2);
+          break;
+
+        case jump_n:
+          extract_number_and_incr (&mcnt, &p);
+	  p1 = p + mcnt;
+          extract_number_and_incr (&mcnt2, &p);
+	  printf ("/jump_n to %d, %d times", p1 - start, mcnt2);
+          break;
+
+        case set_number_at:
+          extract_number_and_incr (&mcnt, &p);
+	  p1 = p + mcnt;
+          extract_number_and_incr (&mcnt2, &p);
+	  printf ("/set_number_at location %d to %d", p1 - start, mcnt2);
+          break;
+
+        case wordbound:
+	  printf ("/wordbound");
+	  break;
+
+	case notwordbound:
+	  printf ("/notwordbound");
+          break;
+
+	case wordbeg:
+	  printf ("/wordbeg");
+	  break;
+
+	case wordend:
+	  printf ("/wordend");
+
+# ifdef emacs
+	case before_dot:
+	  printf ("/before_dot");
+          break;
+
+	case at_dot:
+	  printf ("/at_dot");
+          break;
+
+	case after_dot:
+	  printf ("/after_dot");
+          break;
+
+	case syntaxspec:
+          printf ("/syntaxspec");
+	  mcnt = *p++;
+	  printf ("/%d", mcnt);
+          break;
+
+	case notsyntaxspec:
+          printf ("/notsyntaxspec");
+	  mcnt = *p++;
+	  printf ("/%d", mcnt);
+	  break;
+# endif /* emacs */
+
+	case wordchar:
+	  printf ("/wordchar");
+          break;
+
+	case notwordchar:
+	  printf ("/notwordchar");
+          break;
+
+	case begbuf:
+	  printf ("/begbuf");
+          break;
+
+	case endbuf:
+	  printf ("/endbuf");
+          break;
+
+        default:
+          printf ("?%d", *(p-1));
+	}
+
+      putchar ('\n');
+    }
+
+  printf ("%d:\tend of pattern.\n", p - start);
+}
+
+
+void
+print_compiled_pattern (bufp)
+    struct re_pattern_buffer *bufp;
+{
+  unsigned char *buffer = bufp->buffer;
+
+  print_partial_compiled_pattern (buffer, buffer + bufp->used);
+  printf ("%ld bytes used/%ld bytes allocated.\n",
+	  bufp->used, bufp->allocated);
+
+  if (bufp->fastmap_accurate && bufp->fastmap)
+    {
+      printf ("fastmap: ");
+      print_fastmap (bufp->fastmap);
+    }
+
+  printf ("re_nsub: %d\t", bufp->re_nsub);
+  printf ("regs_alloc: %d\t", bufp->regs_allocated);
+  printf ("can_be_null: %d\t", bufp->can_be_null);
+  printf ("newline_anchor: %d\n", bufp->newline_anchor);
+  printf ("no_sub: %d\t", bufp->no_sub);
+  printf ("not_bol: %d\t", bufp->not_bol);
+  printf ("not_eol: %d\t", bufp->not_eol);
+  printf ("syntax: %lx\n", bufp->syntax);
+  /* Perhaps we should print the translate table?  */
+}
+
+
+void
+print_double_string (where, string1, size1, string2, size2)
+    const char *where;
+    const char *string1;
+    const char *string2;
+    int size1;
+    int size2;
+{
+  int this_char;
+
+  if (where == NULL)
+    printf ("(null)");
+  else
+    {
+      if (FIRST_STRING_P (where))
+        {
+          for (this_char = where - string1; this_char < size1; this_char++)
+            putchar (string1[this_char]);
+
+          where = string2;
+        }
+
+      for (this_char = where - string2; this_char < size2; this_char++)
+        putchar (string2[this_char]);
+    }
+}
+
+void
+printchar (c)
+     int c;
+{
+  putc (c, stderr);
+}
+
+#else /* not DEBUG */
+
+# undef assert
+# define assert(e)
+
+# define DEBUG_STATEMENT(e)
+# define DEBUG_PRINT1(x)
+# define DEBUG_PRINT2(x1, x2)
+# define DEBUG_PRINT3(x1, x2, x3)
+# define DEBUG_PRINT4(x1, x2, x3, x4)
+# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)
+# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)
+
+#endif /* not DEBUG */
+
+/* Set by `re_set_syntax' to the current regexp syntax to recognize.  Can
+   also be assigned to arbitrarily: each pattern buffer stores its own
+   syntax, so it can be changed between regex compilations.  */
+/* This has no initializer because initialized variables in Emacs
+   become read-only after dumping.  */
+reg_syntax_t re_syntax_options;
+
+
+/* Specify the precise syntax of regexps for compilation.  This provides
+   for compatibility for various utilities which historically have
+   different, incompatible syntaxes.
+
+   The argument SYNTAX is a bit mask comprised of the various bits
+   defined in regex.h.  We return the old syntax.  */
+
+reg_syntax_t
+re_set_syntax (syntax)
+    reg_syntax_t syntax;
+{
+  reg_syntax_t ret = re_syntax_options;
+
+  re_syntax_options = syntax;
+#ifdef DEBUG
+  if (syntax & RE_DEBUG)
+    debug = 1;
+  else if (debug) /* was on but now is not */
+    debug = 0;
+#endif /* DEBUG */
+  return ret;
+}
+#ifdef _LIBC
+weak_alias (__re_set_syntax, re_set_syntax)
+#endif
+
+/* This table gives an error message for each of the error codes listed
+   in regex.h.  Obviously the order here has to be same as there.
+   POSIX doesn't require that we do anything for REG_NOERROR,
+   but why not be nice?  */
+
+static const char re_error_msgid[] =
+  {
+#define REG_NOERROR_IDX	0
+    gettext_noop ("Success")	/* REG_NOERROR */
+    "\0"
+#define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success")
+    gettext_noop ("No match")	/* REG_NOMATCH */
+    "\0"
+#define REG_BADPAT_IDX	(REG_NOMATCH_IDX + sizeof "No match")
+    gettext_noop ("Invalid regular expression") /* REG_BADPAT */
+    "\0"
+#define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression")
+    gettext_noop ("Invalid collation character"), /* REG_ECOLLATE */
+    "\0"
+#define REG_ECTYPE_IDX	(REG_ECOLLATE_IDX + sizeof "Invalid collation character")
+    gettext_noop ("Invalid character class name") /* REG_ECTYPE */
+    "\0"
+#define REG_EESCAPE_IDX	(REG_ECTYPE_IDX + sizeof "Invalid character class name")
+    gettext_noop ("Trailing backslash") /* REG_EESCAPE */
+    "\0"
+#define REG_ESUBREG_IDX	(REG_EESCAPE_IDX + sizeof "Trailing backslash")
+    gettext_noop ("Invalid back reference") /* REG_ESUBREG */
+    "\0"
+#define REG_EBRACK_IDX	(REG_ESUBREG_IDX + sizeof "Invalid back reference")
+    gettext_noop ("Unmatched [ or [^")	/* REG_EBRACK */
+    "\0"
+#define REG_EPAREN_IDX	(REG_EBRACK_IDX + sizeof "Unmatched [ or [^")
+    gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */
+    "\0"
+#define REG_EBRACE_IDX	(REG_EPAREN_IDX + sizeof "Unmatched ( or \\(")
+    gettext_noop ("Unmatched \\{") /* REG_EBRACE */
+    "\0"
+#define REG_BADBR_IDX	(REG_EBRACE_IDX + sizeof "Unmatched \\{")
+    gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */
+    "\0"
+#define REG_ERANGE_IDX	(REG_BADBR_IDX + sizeof "Invalid content of \\{\\}")
+    gettext_noop ("Invalid range end")	/* REG_ERANGE */
+    "\0"
+#define REG_ESPACE_IDX	(REG_ERANGE_IDX + sizeof "Invalid range end")
+    gettext_noop ("Memory exhausted") /* REG_ESPACE */
+    "\0"
+#define REG_BADRPT_IDX	(REG_ESPACE_IDX + sizeof "Memory exhausted")
+    gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */
+    "\0"
+#define REG_EEND_IDX	(REG_BADRPT_IDX + sizeof "Invalid preceding regular expression")
+    gettext_noop ("Premature end of regular expression") /* REG_EEND */
+    "\0"
+#define REG_ESIZE_IDX	(REG_EEND_IDX + sizeof "Premature end of regular expression")
+    gettext_noop ("Regular expression too big") /* REG_ESIZE */
+    "\0"
+#define REG_ERPAREN_IDX	(REG_ESIZE_IDX + sizeof "Regular expression too big")
+    gettext_noop ("Unmatched ) or \\)"), /* REG_ERPAREN */
+  };
+
+static const size_t re_error_msgid_idx[] =
+  {
+    REG_NOERROR_IDX,
+    REG_NOMATCH_IDX,
+    REG_BADPAT_IDX,
+    REG_ECOLLATE_IDX,
+    REG_ECTYPE_IDX,
+    REG_EESCAPE_IDX,
+    REG_ESUBREG_IDX,
+    REG_EBRACK_IDX,
+    REG_EPAREN_IDX,
+    REG_EBRACE_IDX,
+    REG_BADBR_IDX,
+    REG_ERANGE_IDX,
+    REG_ESPACE_IDX,
+    REG_BADRPT_IDX,
+    REG_EEND_IDX,
+    REG_ESIZE_IDX,
+    REG_ERPAREN_IDX
+  };
+
+/* Avoiding alloca during matching, to placate r_alloc.  */
+
+/* Define MATCH_MAY_ALLOCATE unless we need to make sure that the
+   searching and matching functions should not call alloca.  On some
+   systems, alloca is implemented in terms of malloc, and if we're
+   using the relocating allocator routines, then malloc could cause a
+   relocation, which might (if the strings being searched are in the
+   ralloc heap) shift the data out from underneath the regexp
+   routines.
+
+   Here's another reason to avoid allocation: Emacs
+   processes input from X in a signal handler; processing X input may
+   call malloc; if input arrives while a matching routine is calling
+   malloc, then we're scrod.  But Emacs can't just block input while
+   calling matching routines; then we don't notice interrupts when
+   they come in.  So, Emacs blocks input around all regexp calls
+   except the matching calls, which it leaves unprotected, in the
+   faith that they will not malloc.  */
+
+/* Normally, this is fine.  */
+#define MATCH_MAY_ALLOCATE
+
+/* When using GNU C, we are not REALLY using the C alloca, no matter
+   what config.h may say.  So don't take precautions for it.  */
+#ifdef __GNUC__
+# undef C_ALLOCA
+#endif
+
+/* The match routines may not allocate if (1) they would do it with malloc
+   and (2) it's not safe for them to use malloc.
+   Note that if REL_ALLOC is defined, matching would not use malloc for the
+   failure stack, but we would still use it for the register vectors;
+   so REL_ALLOC should not affect this.  */
+#if (defined C_ALLOCA || defined REGEX_MALLOC) && defined emacs
+# undef MATCH_MAY_ALLOCATE
+#endif
+
+
+/* Failure stack declarations and macros; both re_compile_fastmap and
+   re_match_2 use a failure stack.  These have to be macros because of
+   REGEX_ALLOCATE_STACK.  */
+
+
+/* Number of failure points for which to initially allocate space
+   when matching.  If this number is exceeded, we allocate more
+   space, so it is not a hard limit.  */
+#ifndef INIT_FAILURE_ALLOC
+# define INIT_FAILURE_ALLOC 5
+#endif
+
+/* Roughly the maximum number of failure points on the stack.  Would be
+   exactly that if always used MAX_FAILURE_ITEMS items each time we failed.
+   This is a variable only so users of regex can assign to it; we never
+   change it ourselves.  */
+
+#ifdef INT_IS_16BIT
+
+# if defined MATCH_MAY_ALLOCATE
+/* 4400 was enough to cause a crash on Alpha OSF/1,
+   whose default stack limit is 2mb.  */
+long int re_max_failures = 4000;
+# else
+long int re_max_failures = 2000;
+# endif
+
+union fail_stack_elt
+{
+  unsigned char *pointer;
+  long int integer;
+};
+
+typedef union fail_stack_elt fail_stack_elt_t;
+
+typedef struct
+{
+  fail_stack_elt_t *stack;
+  unsigned long int size;
+  unsigned long int avail;		/* Offset of next open position.  */
+} fail_stack_type;
+
+#else /* not INT_IS_16BIT */
+
+# if defined MATCH_MAY_ALLOCATE
+/* 4400 was enough to cause a crash on Alpha OSF/1,
+   whose default stack limit is 2mb.  */
+int re_max_failures = 20000;
+# else
+int re_max_failures = 2000;
+# endif
+
+union fail_stack_elt
+{
+  unsigned char *pointer;
+  int integer;
+};
+
+typedef union fail_stack_elt fail_stack_elt_t;
+
+typedef struct
+{
+  fail_stack_elt_t *stack;
+  unsigned size;
+  unsigned avail;			/* Offset of next open position.  */
+} fail_stack_type;
+
+#endif /* INT_IS_16BIT */
+
+#define FAIL_STACK_EMPTY()     (fail_stack.avail == 0)
+#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0)
+#define FAIL_STACK_FULL()      (fail_stack.avail == fail_stack.size)
+
+
+/* Define macros to initialize and free the failure stack.
+   Do `return -2' if the alloc fails.  */
+
+#ifdef MATCH_MAY_ALLOCATE
+# define INIT_FAIL_STACK()						\
+  do {									\
+    fail_stack.stack = (fail_stack_elt_t *)				\
+      REGEX_ALLOCATE_STACK (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \
+									\
+    if (fail_stack.stack == NULL)					\
+      return -2;							\
+									\
+    fail_stack.size = INIT_FAILURE_ALLOC;				\
+    fail_stack.avail = 0;						\
+  } while (0)
+
+# define RESET_FAIL_STACK()  REGEX_FREE_STACK (fail_stack.stack)
+#else
+# define INIT_FAIL_STACK()						\
+  do {									\
+    fail_stack.avail = 0;						\
+  } while (0)
+
+# define RESET_FAIL_STACK()
+#endif
+
+
+/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items.
+
+   Return 1 if succeeds, and 0 if either ran out of memory
+   allocating space for it or it was already too large.
+
+   REGEX_REALLOCATE_STACK requires `destination' be declared.   */
+
+#define DOUBLE_FAIL_STACK(fail_stack)					\
+  ((fail_stack).size > (unsigned) (re_max_failures * MAX_FAILURE_ITEMS)	\
+   ? 0									\
+   : ((fail_stack).stack = (fail_stack_elt_t *)				\
+        REGEX_REALLOCATE_STACK ((fail_stack).stack, 			\
+          (fail_stack).size * sizeof (fail_stack_elt_t),		\
+          ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)),	\
+									\
+      (fail_stack).stack == NULL					\
+      ? 0								\
+      : ((fail_stack).size <<= 1, 					\
+         1)))
+
+
+/* Push pointer POINTER on FAIL_STACK.
+   Return 1 if was able to do so and 0 if ran out of memory allocating
+   space to do so.  */
+#define PUSH_PATTERN_OP(POINTER, FAIL_STACK)				\
+  ((FAIL_STACK_FULL ()							\
+    && !DOUBLE_FAIL_STACK (FAIL_STACK))					\
+   ? 0									\
+   : ((FAIL_STACK).stack[(FAIL_STACK).avail++].pointer = POINTER,	\
+      1))
+
+/* Push a pointer value onto the failure stack.
+   Assumes the variable `fail_stack'.  Probably should only
+   be called from within `PUSH_FAILURE_POINT'.  */
+#define PUSH_FAILURE_POINTER(item)					\
+  fail_stack.stack[fail_stack.avail++].pointer = (unsigned char *) (item)
+
+/* This pushes an integer-valued item onto the failure stack.
+   Assumes the variable `fail_stack'.  Probably should only
+   be called from within `PUSH_FAILURE_POINT'.  */
+#define PUSH_FAILURE_INT(item)					\
+  fail_stack.stack[fail_stack.avail++].integer = (item)
+
+/* Push a fail_stack_elt_t value onto the failure stack.
+   Assumes the variable `fail_stack'.  Probably should only
+   be called from within `PUSH_FAILURE_POINT'.  */
+#define PUSH_FAILURE_ELT(item)					\
+  fail_stack.stack[fail_stack.avail++] =  (item)
+
+/* These three POP... operations complement the three PUSH... operations.
+   All assume that `fail_stack' is nonempty.  */
+#define POP_FAILURE_POINTER() fail_stack.stack[--fail_stack.avail].pointer
+#define POP_FAILURE_INT() fail_stack.stack[--fail_stack.avail].integer
+#define POP_FAILURE_ELT() fail_stack.stack[--fail_stack.avail]
+
+/* Used to omit pushing failure point id's when we're not debugging.  */
+#ifdef DEBUG
+# define DEBUG_PUSH PUSH_FAILURE_INT
+# define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_INT ()
+#else
+# define DEBUG_PUSH(item)
+# define DEBUG_POP(item_addr)
+#endif
+
+
+/* Push the information about the state we will need
+   if we ever fail back to it.
+
+   Requires variables fail_stack, regstart, regend, reg_info, and
+   num_regs_pushed be declared.  DOUBLE_FAIL_STACK requires `destination'
+   be declared.
+
+   Does `return FAILURE_CODE' if runs out of memory.  */
+
+#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code)	\
+  do {									\
+    char *destination;							\
+    /* Must be int, so when we don't save any registers, the arithmetic	\
+       of 0 + -1 isn't done as unsigned.  */				\
+    /* Can't be int, since there is not a shred of a guarantee that int	\
+       is wide enough to hold a value of something to which pointer can	\
+       be assigned */							\
+    active_reg_t this_reg;						\
+    									\
+    DEBUG_STATEMENT (failure_id++);					\
+    DEBUG_STATEMENT (nfailure_points_pushed++);				\
+    DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id);		\
+    DEBUG_PRINT2 ("  Before push, next avail: %d\n", (fail_stack).avail);\
+    DEBUG_PRINT2 ("                     size: %d\n", (fail_stack).size);\
+									\
+    DEBUG_PRINT2 ("  slots needed: %ld\n", NUM_FAILURE_ITEMS);		\
+    DEBUG_PRINT2 ("     available: %d\n", REMAINING_AVAIL_SLOTS);	\
+									\
+    /* Ensure we have enough space allocated for what we will push.  */	\
+    while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS)			\
+      {									\
+        if (!DOUBLE_FAIL_STACK (fail_stack))				\
+          return failure_code;						\
+									\
+        DEBUG_PRINT2 ("\n  Doubled stack; size now: %d\n",		\
+		       (fail_stack).size);				\
+        DEBUG_PRINT2 ("  slots available: %d\n", REMAINING_AVAIL_SLOTS);\
+      }									\
+									\
+    /* Push the info, starting with the registers.  */			\
+    DEBUG_PRINT1 ("\n");						\
+									\
+    if (1)								\
+      for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \
+	   this_reg++)							\
+	{								\
+	  DEBUG_PRINT2 ("  Pushing reg: %lu\n", this_reg);		\
+	  DEBUG_STATEMENT (num_regs_pushed++);				\
+									\
+	  DEBUG_PRINT2 ("    start: %p\n", regstart[this_reg]);		\
+	  PUSH_FAILURE_POINTER (regstart[this_reg]);			\
+									\
+	  DEBUG_PRINT2 ("    end: %p\n", regend[this_reg]);		\
+	  PUSH_FAILURE_POINTER (regend[this_reg]);			\
+									\
+	  DEBUG_PRINT2 ("    info: %p\n      ",				\
+			reg_info[this_reg].word.pointer);		\
+	  DEBUG_PRINT2 (" match_null=%d",				\
+			REG_MATCH_NULL_STRING_P (reg_info[this_reg]));	\
+	  DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg]));	\
+	  DEBUG_PRINT2 (" matched_something=%d",			\
+			MATCHED_SOMETHING (reg_info[this_reg]));	\
+	  DEBUG_PRINT2 (" ever_matched=%d",				\
+			EVER_MATCHED_SOMETHING (reg_info[this_reg]));	\
+	  DEBUG_PRINT1 ("\n");						\
+	  PUSH_FAILURE_ELT (reg_info[this_reg].word);			\
+	}								\
+									\
+    DEBUG_PRINT2 ("  Pushing  low active reg: %ld\n", lowest_active_reg);\
+    PUSH_FAILURE_INT (lowest_active_reg);				\
+									\
+    DEBUG_PRINT2 ("  Pushing high active reg: %ld\n", highest_active_reg);\
+    PUSH_FAILURE_INT (highest_active_reg);				\
+									\
+    DEBUG_PRINT2 ("  Pushing pattern %p:\n", pattern_place);		\
+    DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend);		\
+    PUSH_FAILURE_POINTER (pattern_place);				\
+									\
+    DEBUG_PRINT2 ("  Pushing string %p: `", string_place);		\
+    DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2,   \
+				 size2);				\
+    DEBUG_PRINT1 ("'\n");						\
+    PUSH_FAILURE_POINTER (string_place);				\
+									\
+    DEBUG_PRINT2 ("  Pushing failure id: %u\n", failure_id);		\
+    DEBUG_PUSH (failure_id);						\
+  } while (0)
+
+/* This is the number of items that are pushed and popped on the stack
+   for each register.  */
+#define NUM_REG_ITEMS  3
+
+/* Individual items aside from the registers.  */
+#ifdef DEBUG
+# define NUM_NONREG_ITEMS 5 /* Includes failure point id.  */
+#else
+# define NUM_NONREG_ITEMS 4
+#endif
+
+/* We push at most this many items on the stack.  */
+/* We used to use (num_regs - 1), which is the number of registers
+   this regexp will save; but that was changed to 5
+   to avoid stack overflow for a regexp with lots of parens.  */
+#define MAX_FAILURE_ITEMS (5 * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
+
+/* We actually push this many items.  */
+#define NUM_FAILURE_ITEMS				\
+  (((0							\
+     ? 0 : highest_active_reg - lowest_active_reg + 1)	\
+    * NUM_REG_ITEMS)					\
+   + NUM_NONREG_ITEMS)
+
+/* How many items can still be added to the stack without overflowing it.  */
+#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
+
+
+/* Pops what PUSH_FAIL_STACK pushes.
+
+   We restore into the parameters, all of which should be lvalues:
+     STR -- the saved data position.
+     PAT -- the saved pattern position.
+     LOW_REG, HIGH_REG -- the highest and lowest active registers.
+     REGSTART, REGEND -- arrays of string positions.
+     REG_INFO -- array of information about each subexpression.
+
+   Also assumes the variables `fail_stack' and (if debugging), `bufp',
+   `pend', `string1', `size1', `string2', and `size2'.  */
+
+#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\
+{									\
+  DEBUG_STATEMENT (unsigned failure_id;)				\
+  active_reg_t this_reg;						\
+  const unsigned char *string_temp;					\
+									\
+  assert (!FAIL_STACK_EMPTY ());					\
+									\
+  /* Remove failure points and point to how many regs pushed.  */	\
+  DEBUG_PRINT1 ("POP_FAILURE_POINT:\n");				\
+  DEBUG_PRINT2 ("  Before pop, next avail: %d\n", fail_stack.avail);	\
+  DEBUG_PRINT2 ("                    size: %d\n", fail_stack.size);	\
+									\
+  assert (fail_stack.avail >= NUM_NONREG_ITEMS);			\
+									\
+  DEBUG_POP (&failure_id);						\
+  DEBUG_PRINT2 ("  Popping failure id: %u\n", failure_id);		\
+									\
+  /* If the saved string location is NULL, it came from an		\
+     on_failure_keep_string_jump opcode, and we want to throw away the	\
+     saved NULL, thus retaining our current position in the string.  */	\
+  string_temp = POP_FAILURE_POINTER ();					\
+  if (string_temp != NULL)						\
+    str = (const char *) string_temp;					\
+									\
+  DEBUG_PRINT2 ("  Popping string %p: `", str);				\
+  DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2);	\
+  DEBUG_PRINT1 ("'\n");							\
+									\
+  pat = (unsigned char *) POP_FAILURE_POINTER ();			\
+  DEBUG_PRINT2 ("  Popping pattern %p:\n", pat);			\
+  DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend);			\
+									\
+  /* Restore register info.  */						\
+  high_reg = (active_reg_t) POP_FAILURE_INT ();				\
+  DEBUG_PRINT2 ("  Popping high active reg: %ld\n", high_reg);		\
+									\
+  low_reg = (active_reg_t) POP_FAILURE_INT ();				\
+  DEBUG_PRINT2 ("  Popping  low active reg: %ld\n", low_reg);		\
+									\
+  if (1)								\
+    for (this_reg = high_reg; this_reg >= low_reg; this_reg--)		\
+      {									\
+	DEBUG_PRINT2 ("    Popping reg: %ld\n", this_reg);		\
+									\
+	reg_info[this_reg].word = POP_FAILURE_ELT ();			\
+	DEBUG_PRINT2 ("      info: %p\n",				\
+		      reg_info[this_reg].word.pointer);			\
+									\
+	regend[this_reg] = (const char *) POP_FAILURE_POINTER ();	\
+	DEBUG_PRINT2 ("      end: %p\n", regend[this_reg]);		\
+									\
+	regstart[this_reg] = (const char *) POP_FAILURE_POINTER ();	\
+	DEBUG_PRINT2 ("      start: %p\n", regstart[this_reg]);		\
+      }									\
+  else									\
+    {									\
+      for (this_reg = highest_active_reg; this_reg > high_reg; this_reg--) \
+	{								\
+	  reg_info[this_reg].word.integer = 0;				\
+	  regend[this_reg] = 0;						\
+	  regstart[this_reg] = 0;					\
+	}								\
+      highest_active_reg = high_reg;					\
+    }									\
+									\
+  set_regs_matched_done = 0;						\
+  DEBUG_STATEMENT (nfailure_points_popped++);				\
+} /* POP_FAILURE_POINT */
+
+
+
+/* Structure for per-register (a.k.a. per-group) information.
+   Other register information, such as the
+   starting and ending positions (which are addresses), and the list of
+   inner groups (which is a bits list) are maintained in separate
+   variables.
+
+   We are making a (strictly speaking) nonportable assumption here: that
+   the compiler will pack our bit fields into something that fits into
+   the type of `word', i.e., is something that fits into one item on the
+   failure stack.  */
+
+
+/* Declarations and macros for re_match_2.  */
+
+typedef union
+{
+  fail_stack_elt_t word;
+  struct
+  {
+      /* This field is one if this group can match the empty string,
+         zero if not.  If not yet determined,  `MATCH_NULL_UNSET_VALUE'.  */
+#define MATCH_NULL_UNSET_VALUE 3
+    unsigned match_null_string_p : 2;
+    unsigned is_active : 1;
+    unsigned matched_something : 1;
+    unsigned ever_matched_something : 1;
+  } bits;
+} register_info_type;
+
+#define REG_MATCH_NULL_STRING_P(R)  ((R).bits.match_null_string_p)
+#define IS_ACTIVE(R)  ((R).bits.is_active)
+#define MATCHED_SOMETHING(R)  ((R).bits.matched_something)
+#define EVER_MATCHED_SOMETHING(R)  ((R).bits.ever_matched_something)
+
+
+/* Call this when have matched a real character; it sets `matched' flags
+   for the subexpressions which we are currently inside.  Also records
+   that those subexprs have matched.  */
+#define SET_REGS_MATCHED()						\
+  do									\
+    {									\
+      if (!set_regs_matched_done)					\
+	{								\
+	  active_reg_t r;						\
+	  set_regs_matched_done = 1;					\
+	  for (r = lowest_active_reg; r <= highest_active_reg; r++)	\
+	    {								\
+	      MATCHED_SOMETHING (reg_info[r])				\
+		= EVER_MATCHED_SOMETHING (reg_info[r])			\
+		= 1;							\
+	    }								\
+	}								\
+    }									\
+  while (0)
+
+/* Registers are set to a sentinel when they haven't yet matched.  */
+static char reg_unset_dummy;
+#define REG_UNSET_VALUE (&reg_unset_dummy)
+#define REG_UNSET(e) ((e) == REG_UNSET_VALUE)
+
+/* Subroutine declarations and macros for regex_compile.  */
+
+static reg_errcode_t regex_compile _RE_ARGS ((const char *pattern, size_t size,
+					      reg_syntax_t syntax,
+					      struct re_pattern_buffer *bufp));
+static void store_op1 _RE_ARGS ((re_opcode_t op, unsigned char *loc, int arg));
+static void store_op2 _RE_ARGS ((re_opcode_t op, unsigned char *loc,
+				 int arg1, int arg2));
+static void insert_op1 _RE_ARGS ((re_opcode_t op, unsigned char *loc,
+				  int arg, unsigned char *end));
+static void insert_op2 _RE_ARGS ((re_opcode_t op, unsigned char *loc,
+				  int arg1, int arg2, unsigned char *end));
+static boolean at_begline_loc_p _RE_ARGS ((const char *pattern, const char *p,
+					   reg_syntax_t syntax));
+static boolean at_endline_loc_p _RE_ARGS ((const char *p, const char *pend,
+					   reg_syntax_t syntax));
+static reg_errcode_t compile_range _RE_ARGS ((const char **p_ptr,
+					      const char *pend,
+					      char *translate,
+					      reg_syntax_t syntax,
+					      unsigned char *b));
+
+/* Fetch the next character in the uncompiled pattern---translating it
+   if necessary.  Also cast from a signed character in the constant
+   string passed to us by the user to an unsigned char that we can use
+   as an array index (in, e.g., `translate').  */
+#ifndef PATFETCH
+# define PATFETCH(c)							\
+  do {if (p == pend) return REG_EEND;					\
+    c = (unsigned char) *p++;						\
+    if (translate) c = (unsigned char) translate[c];			\
+  } while (0)
+#endif
+
+/* Fetch the next character in the uncompiled pattern, with no
+   translation.  */
+#define PATFETCH_RAW(c)							\
+  do {if (p == pend) return REG_EEND;					\
+    c = (unsigned char) *p++; 						\
+  } while (0)
+
+/* Go backwards one character in the pattern.  */
+#define PATUNFETCH p--
+
+
+/* If `translate' is non-null, return translate[D], else just D.  We
+   cast the subscript to translate because some data is declared as
+   `char *', to avoid warnings when a string constant is passed.  But
+   when we use a character as a subscript we must make it unsigned.  */
+#ifndef TRANSLATE
+# define TRANSLATE(d) \
+  (translate ? (char) translate[(unsigned char) (d)] : (d))
+#endif
+
+
+/* Macros for outputting the compiled pattern into `buffer'.  */
+
+/* If the buffer isn't allocated when it comes in, use this.  */
+#define INIT_BUF_SIZE  32
+
+/* Make sure we have at least N more bytes of space in buffer.  */
+#define GET_BUFFER_SPACE(n)						\
+    while ((unsigned long) (b - bufp->buffer + (n)) > bufp->allocated)	\
+      EXTEND_BUFFER ()
+
+/* Make sure we have one more byte of buffer space and then add C to it.  */
+#define BUF_PUSH(c)							\
+  do {									\
+    GET_BUFFER_SPACE (1);						\
+    *b++ = (unsigned char) (c);						\
+  } while (0)
+
+
+/* Ensure we have two more bytes of buffer space and then append C1 and C2.  */
+#define BUF_PUSH_2(c1, c2)						\
+  do {									\
+    GET_BUFFER_SPACE (2);						\
+    *b++ = (unsigned char) (c1);					\
+    *b++ = (unsigned char) (c2);					\
+  } while (0)
+
+
+/* As with BUF_PUSH_2, except for three bytes.  */
+#define BUF_PUSH_3(c1, c2, c3)						\
+  do {									\
+    GET_BUFFER_SPACE (3);						\
+    *b++ = (unsigned char) (c1);					\
+    *b++ = (unsigned char) (c2);					\
+    *b++ = (unsigned char) (c3);					\
+  } while (0)
+
+
+/* Store a jump with opcode OP at LOC to location TO.  We store a
+   relative address offset by the three bytes the jump itself occupies.  */
+#define STORE_JUMP(op, loc, to) \
+  store_op1 (op, loc, (int) ((to) - (loc) - 3))
+
+/* Likewise, for a two-argument jump.  */
+#define STORE_JUMP2(op, loc, to, arg) \
+  store_op2 (op, loc, (int) ((to) - (loc) - 3), arg)
+
+/* Like `STORE_JUMP', but for inserting.  Assume `b' is the buffer end.  */
+#define INSERT_JUMP(op, loc, to) \
+  insert_op1 (op, loc, (int) ((to) - (loc) - 3), b)
+
+/* Like `STORE_JUMP2', but for inserting.  Assume `b' is the buffer end.  */
+#define INSERT_JUMP2(op, loc, to, arg) \
+  insert_op2 (op, loc, (int) ((to) - (loc) - 3), arg, b)
+
+
+/* This is not an arbitrary limit: the arguments which represent offsets
+   into the pattern are two bytes long.  So if 2^16 bytes turns out to
+   be too small, many things would have to change.  */
+/* Any other compiler which, like MSC, has allocation limit below 2^16
+   bytes will have to use approach similar to what was done below for
+   MSC and drop MAX_BUF_SIZE a bit.  Otherwise you may end up
+   reallocating to 0 bytes.  Such thing is not going to work too well.
+   You have been warned!!  */
+#if defined _MSC_VER  && !defined WIN32
+/* Microsoft C 16-bit versions limit malloc to approx 65512 bytes.
+   The REALLOC define eliminates a flurry of conversion warnings,
+   but is not required. */
+# define MAX_BUF_SIZE  65500L
+# define REALLOC(p,s) realloc ((p), (size_t) (s))
+#else
+# define MAX_BUF_SIZE (1L << 16)
+# define REALLOC(p,s) realloc ((p), (s))
+#endif
+
+/* Extend the buffer by twice its current size via realloc and
+   reset the pointers that pointed into the old block to point to the
+   correct places in the new one.  If extending the buffer results in it
+   being larger than MAX_BUF_SIZE, then flag memory exhausted.  */
+#define EXTEND_BUFFER()							\
+  do { 									\
+    unsigned char *old_buffer = bufp->buffer;				\
+    if (bufp->allocated == MAX_BUF_SIZE) 				\
+      return REG_ESIZE;							\
+    bufp->allocated <<= 1;						\
+    if (bufp->allocated > MAX_BUF_SIZE)					\
+      bufp->allocated = MAX_BUF_SIZE; 					\
+    bufp->buffer = (unsigned char *) REALLOC (bufp->buffer, bufp->allocated);\
+    if (bufp->buffer == NULL)						\
+      return REG_ESPACE;						\
+    /* If the buffer moved, move all the pointers into it.  */		\
+    if (old_buffer != bufp->buffer)					\
+      {									\
+        b = (b - old_buffer) + bufp->buffer;				\
+        begalt = (begalt - old_buffer) + bufp->buffer;			\
+        if (fixup_alt_jump)						\
+          fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\
+        if (laststart)							\
+          laststart = (laststart - old_buffer) + bufp->buffer;		\
+        if (pending_exact)						\
+          pending_exact = (pending_exact - old_buffer) + bufp->buffer;	\
+      }									\
+  } while (0)
+
+
+/* Since we have one byte reserved for the register number argument to
+   {start,stop}_memory, the maximum number of groups we can report
+   things about is what fits in that byte.  */
+#define MAX_REGNUM 255
+
+/* But patterns can have more than `MAX_REGNUM' registers.  We just
+   ignore the excess.  */
+typedef unsigned regnum_t;
+
+
+/* Macros for the compile stack.  */
+
+/* Since offsets can go either forwards or backwards, this type needs to
+   be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1.  */
+/* int may be not enough when sizeof(int) == 2.  */
+typedef long pattern_offset_t;
+
+typedef struct
+{
+  pattern_offset_t begalt_offset;
+  pattern_offset_t fixup_alt_jump;
+  pattern_offset_t inner_group_offset;
+  pattern_offset_t laststart_offset;
+  regnum_t regnum;
+} compile_stack_elt_t;
+
+
+typedef struct
+{
+  compile_stack_elt_t *stack;
+  unsigned size;
+  unsigned avail;			/* Offset of next open position.  */
+} compile_stack_type;
+
+
+#define INIT_COMPILE_STACK_SIZE 32
+
+#define COMPILE_STACK_EMPTY  (compile_stack.avail == 0)
+#define COMPILE_STACK_FULL  (compile_stack.avail == compile_stack.size)
+
+/* The next available element.  */
+#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
+
+
+/* Set the bit for character C in a list.  */
+#define SET_LIST_BIT(c)                               \
+  (b[((unsigned char) (c)) / BYTEWIDTH]               \
+   |= 1 << (((unsigned char) c) % BYTEWIDTH))
+
+
+/* Get the next unsigned number in the uncompiled pattern.  */
+#define GET_UNSIGNED_NUMBER(num) 					\
+  { if (p != pend)							\
+     {									\
+       PATFETCH (c); 							\
+       while (ISDIGIT (c)) 						\
+         { 								\
+           if (num < 0)							\
+              num = 0;							\
+           num = num * 10 + c - '0'; 					\
+           if (p == pend) 						\
+              break; 							\
+           PATFETCH (c);						\
+         } 								\
+       } 								\
+    }
+
+#if defined _LIBC || WIDE_CHAR_SUPPORT
+/* The GNU C library provides support for user-defined character classes
+   and the functions from ISO C amendement 1.  */
+# ifdef CHARCLASS_NAME_MAX
+#  define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
+# else
+/* This shouldn't happen but some implementation might still have this
+   problem.  Use a reasonable default value.  */
+#  define CHAR_CLASS_MAX_LENGTH 256
+# endif
+
+# ifdef _LIBC
+#  define IS_CHAR_CLASS(string) __wctype (string)
+# else
+#  define IS_CHAR_CLASS(string) wctype (string)
+# endif
+#else
+# define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
+
+# define IS_CHAR_CLASS(string)						\
+   (STREQ (string, "alpha") || STREQ (string, "upper")			\
+    || STREQ (string, "lower") || STREQ (string, "digit")		\
+    || STREQ (string, "alnum") || STREQ (string, "xdigit")		\
+    || STREQ (string, "space") || STREQ (string, "print")		\
+    || STREQ (string, "punct") || STREQ (string, "graph")		\
+    || STREQ (string, "cntrl") || STREQ (string, "blank"))
+#endif
+
+#ifndef MATCH_MAY_ALLOCATE
+
+/* If we cannot allocate large objects within re_match_2_internal,
+   we make the fail stack and register vectors global.
+   The fail stack, we grow to the maximum size when a regexp
+   is compiled.
+   The register vectors, we adjust in size each time we
+   compile a regexp, according to the number of registers it needs.  */
+
+static fail_stack_type fail_stack;
+
+/* Size with which the following vectors are currently allocated.
+   That is so we can make them bigger as needed,
+   but never make them smaller.  */
+static int regs_allocated_size;
+
+static const char **     regstart, **     regend;
+static const char ** old_regstart, ** old_regend;
+static const char **best_regstart, **best_regend;
+static register_info_type *reg_info;
+static const char **reg_dummy;
+static register_info_type *reg_info_dummy;
+
+/* Make the register vectors big enough for NUM_REGS registers,
+   but don't make them smaller.  */
+
+static
+regex_grow_registers (num_regs)
+     int num_regs;
+{
+  if (num_regs > regs_allocated_size)
+    {
+      RETALLOC_IF (regstart,	 num_regs, const char *);
+      RETALLOC_IF (regend,	 num_regs, const char *);
+      RETALLOC_IF (old_regstart, num_regs, const char *);
+      RETALLOC_IF (old_regend,	 num_regs, const char *);
+      RETALLOC_IF (best_regstart, num_regs, const char *);
+      RETALLOC_IF (best_regend,	 num_regs, const char *);
+      RETALLOC_IF (reg_info,	 num_regs, register_info_type);
+      RETALLOC_IF (reg_dummy,	 num_regs, const char *);
+      RETALLOC_IF (reg_info_dummy, num_regs, register_info_type);
+
+      regs_allocated_size = num_regs;
+    }
+}
+
+#endif /* not MATCH_MAY_ALLOCATE */
+
+static boolean group_in_compile_stack _RE_ARGS ((compile_stack_type
+						 compile_stack,
+						 regnum_t regnum));
+
+/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
+   Returns one of error codes defined in `regex.h', or zero for success.
+
+   Assumes the `allocated' (and perhaps `buffer') and `translate'
+   fields are set in BUFP on entry.
+
+   If it succeeds, results are put in BUFP (if it returns an error, the
+   contents of BUFP are undefined):
+     `buffer' is the compiled pattern;
+     `syntax' is set to SYNTAX;
+     `used' is set to the length of the compiled pattern;
+     `fastmap_accurate' is zero;
+     `re_nsub' is the number of subexpressions in PATTERN;
+     `not_bol' and `not_eol' are zero;
+
+   The `fastmap' and `newline_anchor' fields are neither
+   examined nor set.  */
+
+/* Return, freeing storage we allocated.  */
+#define FREE_STACK_RETURN(value)		\
+  return (free (compile_stack.stack), value)
+
+static reg_errcode_t
+regex_compile (pattern, size, syntax, bufp)
+     const char *pattern;
+     size_t size;
+     reg_syntax_t syntax;
+     struct re_pattern_buffer *bufp;
+{
+  /* We fetch characters from PATTERN here.  Even though PATTERN is
+     `char *' (i.e., signed), we declare these variables as unsigned, so
+     they can be reliably used as array indices.  */
+  register unsigned char c, c1;
+
+  /* A random temporary spot in PATTERN.  */
+  const char *p1;
+
+  /* Points to the end of the buffer, where we should append.  */
+  register unsigned char *b;
+
+  /* Keeps track of unclosed groups.  */
+  compile_stack_type compile_stack;
+
+  /* Points to the current (ending) position in the pattern.  */
+  const char *p = pattern;
+  const char *pend = pattern + size;
+
+  /* How to translate the characters in the pattern.  */
+  RE_TRANSLATE_TYPE translate = bufp->translate;
+
+  /* Address of the count-byte of the most recently inserted `exactn'
+     command.  This makes it possible to tell if a new exact-match
+     character can be added to that command or if the character requires
+     a new `exactn' command.  */
+  unsigned char *pending_exact = 0;
+
+  /* Address of start of the most recently finished expression.
+     This tells, e.g., postfix * where to find the start of its
+     operand.  Reset at the beginning of groups and alternatives.  */
+  unsigned char *laststart = 0;
+
+  /* Address of beginning of regexp, or inside of last group.  */
+  unsigned char *begalt;
+
+  /* Place in the uncompiled pattern (i.e., the {) to
+     which to go back if the interval is invalid.  */
+  const char *beg_interval;
+
+  /* Address of the place where a forward jump should go to the end of
+     the containing expression.  Each alternative of an `or' -- except the
+     last -- ends with a forward jump of this sort.  */
+  unsigned char *fixup_alt_jump = 0;
+
+  /* Counts open-groups as they are encountered.  Remembered for the
+     matching close-group on the compile stack, so the same register
+     number is put in the stop_memory as the start_memory.  */
+  regnum_t regnum = 0;
+
+#ifdef DEBUG
+  DEBUG_PRINT1 ("\nCompiling pattern: ");
+  if (debug)
+    {
+      unsigned debug_count;
+
+      for (debug_count = 0; debug_count < size; debug_count++)
+        putchar (pattern[debug_count]);
+      putchar ('\n');
+    }
+#endif /* DEBUG */
+
+  /* Initialize the compile stack.  */
+  compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t);
+  if (compile_stack.stack == NULL)
+    return REG_ESPACE;
+
+  compile_stack.size = INIT_COMPILE_STACK_SIZE;
+  compile_stack.avail = 0;
+
+  /* Initialize the pattern buffer.  */
+  bufp->syntax = syntax;
+  bufp->fastmap_accurate = 0;
+  bufp->not_bol = bufp->not_eol = 0;
+
+  /* Set `used' to zero, so that if we return an error, the pattern
+     printer (for debugging) will think there's no pattern.  We reset it
+     at the end.  */
+  bufp->used = 0;
+
+  /* Always count groups, whether or not bufp->no_sub is set.  */
+  bufp->re_nsub = 0;
+
+#if !defined emacs && !defined SYNTAX_TABLE
+  /* Initialize the syntax table.  */
+   init_syntax_once ();
+#endif
+
+  if (bufp->allocated == 0)
+    {
+      if (bufp->buffer)
+	{ /* If zero allocated, but buffer is non-null, try to realloc
+             enough space.  This loses if buffer's address is bogus, but
+             that is the user's responsibility.  */
+          RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char);
+        }
+      else
+        { /* Caller did not allocate a buffer.  Do it for them.  */
+          bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char);
+        }
+      if (!bufp->buffer) FREE_STACK_RETURN (REG_ESPACE);
+
+      bufp->allocated = INIT_BUF_SIZE;
+    }
+
+  begalt = b = bufp->buffer;
+
+  /* Loop through the uncompiled pattern until we're at the end.  */
+  while (p != pend)
+    {
+      PATFETCH (c);
+
+      switch (c)
+        {
+        case '^':
+          {
+            if (   /* If at start of pattern, it's an operator.  */
+                   p == pattern + 1
+                   /* If context independent, it's an operator.  */
+                || syntax & RE_CONTEXT_INDEP_ANCHORS
+                   /* Otherwise, depends on what's come before.  */
+                || at_begline_loc_p (pattern, p, syntax))
+              BUF_PUSH (begline);
+            else
+              goto normal_char;
+          }
+          break;
+
+
+        case '$':
+          {
+            if (   /* If at end of pattern, it's an operator.  */
+                   p == pend
+                   /* If context independent, it's an operator.  */
+                || syntax & RE_CONTEXT_INDEP_ANCHORS
+                   /* Otherwise, depends on what's next.  */
+                || at_endline_loc_p (p, pend, syntax))
+               BUF_PUSH (endline);
+             else
+               goto normal_char;
+           }
+           break;
+
+
+	case '+':
+        case '?':
+          if ((syntax & RE_BK_PLUS_QM)
+              || (syntax & RE_LIMITED_OPS))
+            goto normal_char;
+        handle_plus:
+        case '*':
+          /* If there is no previous pattern... */
+          if (!laststart)
+            {
+              if (syntax & RE_CONTEXT_INVALID_OPS)
+                FREE_STACK_RETURN (REG_BADRPT);
+              else if (!(syntax & RE_CONTEXT_INDEP_OPS))
+                goto normal_char;
+            }
+
+          {
+            /* Are we optimizing this jump?  */
+            boolean keep_string_p = false;
+
+            /* 1 means zero (many) matches is allowed.  */
+            char zero_times_ok = 0, many_times_ok = 0;
+
+            /* If there is a sequence of repetition chars, collapse it
+               down to just one (the right one).  We can't combine
+               interval operators with these because of, e.g., `a{2}*',
+               which should only match an even number of `a's.  */
+
+            for (;;)
+              {
+                zero_times_ok |= c != '+';
+                many_times_ok |= c != '?';
+
+                if (p == pend)
+                  break;
+
+                PATFETCH (c);
+
+                if (c == '*'
+                    || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?')))
+                  ;
+
+                else if (syntax & RE_BK_PLUS_QM  &&  c == '\\')
+                  {
+                    if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+                    PATFETCH (c1);
+                    if (!(c1 == '+' || c1 == '?'))
+                      {
+                        PATUNFETCH;
+                        PATUNFETCH;
+                        break;
+                      }
+
+                    c = c1;
+                  }
+                else
+                  {
+                    PATUNFETCH;
+                    break;
+                  }
+
+                /* If we get here, we found another repeat character.  */
+               }
+
+            /* Star, etc. applied to an empty pattern is equivalent
+               to an empty pattern.  */
+            if (!laststart)
+              break;
+
+            /* Now we know whether or not zero matches is allowed
+               and also whether or not two or more matches is allowed.  */
+            if (many_times_ok)
+              { /* More than one repetition is allowed, so put in at the
+                   end a backward relative jump from `b' to before the next
+                   jump we're going to put in below (which jumps from
+                   laststart to after this jump).
+
+                   But if we are at the `*' in the exact sequence `.*\n',
+                   insert an unconditional jump backwards to the .,
+                   instead of the beginning of the loop.  This way we only
+                   push a failure point once, instead of every time
+                   through the loop.  */
+                assert (p - 1 > pattern);
+
+                /* Allocate the space for the jump.  */
+                GET_BUFFER_SPACE (3);
+
+                /* We know we are not at the first character of the pattern,
+                   because laststart was nonzero.  And we've already
+                   incremented `p', by the way, to be the character after
+                   the `*'.  Do we have to do something analogous here
+                   for null bytes, because of RE_DOT_NOT_NULL?  */
+                if (TRANSLATE (*(p - 2)) == TRANSLATE ('.')
+		    && zero_times_ok
+                    && p < pend && TRANSLATE (*p) == TRANSLATE ('\n')
+                    && !(syntax & RE_DOT_NEWLINE))
+                  { /* We have .*\n.  */
+                    STORE_JUMP (jump, b, laststart);
+                    keep_string_p = true;
+                  }
+                else
+                  /* Anything else.  */
+                  STORE_JUMP (maybe_pop_jump, b, laststart - 3);
+
+                /* We've added more stuff to the buffer.  */
+                b += 3;
+              }
+
+            /* On failure, jump from laststart to b + 3, which will be the
+               end of the buffer after this jump is inserted.  */
+            GET_BUFFER_SPACE (3);
+            INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump
+                                       : on_failure_jump,
+                         laststart, b + 3);
+            pending_exact = 0;
+            b += 3;
+
+            if (!zero_times_ok)
+              {
+                /* At least one repetition is required, so insert a
+                   `dummy_failure_jump' before the initial
+                   `on_failure_jump' instruction of the loop. This
+                   effects a skip over that instruction the first time
+                   we hit that loop.  */
+                GET_BUFFER_SPACE (3);
+                INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6);
+                b += 3;
+              }
+            }
+	  break;
+
+
+	case '.':
+          laststart = b;
+          BUF_PUSH (anychar);
+          break;
+
+
+        case '[':
+          {
+            boolean had_char_class = false;
+
+            if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+            /* Ensure that we have enough space to push a charset: the
+               opcode, the length count, and the bitset; 34 bytes in all.  */
+	    GET_BUFFER_SPACE (34);
+
+            laststart = b;
+
+            /* We test `*p == '^' twice, instead of using an if
+               statement, so we only need one BUF_PUSH.  */
+            BUF_PUSH (*p == '^' ? charset_not : charset);
+            if (*p == '^')
+              p++;
+
+            /* Remember the first position in the bracket expression.  */
+            p1 = p;
+
+            /* Push the number of bytes in the bitmap.  */
+            BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
+
+            /* Clear the whole map.  */
+            bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
+
+            /* charset_not matches newline according to a syntax bit.  */
+            if ((re_opcode_t) b[-2] == charset_not
+                && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
+              SET_LIST_BIT ('\n');
+
+            /* Read in characters and ranges, setting map bits.  */
+            for (;;)
+              {
+                if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+                PATFETCH (c);
+
+                /* \ might escape characters inside [...] and [^...].  */
+                if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
+                  {
+                    if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+                    PATFETCH (c1);
+                    SET_LIST_BIT (c1);
+                    continue;
+                  }
+
+                /* Could be the end of the bracket expression.  If it's
+                   not (i.e., when the bracket expression is `[]' so
+                   far), the ']' character bit gets set way below.  */
+                if (c == ']' && p != p1 + 1)
+                  break;
+
+                /* Look ahead to see if it's a range when the last thing
+                   was a character class.  */
+                if (had_char_class && c == '-' && *p != ']')
+                  FREE_STACK_RETURN (REG_ERANGE);
+
+                /* Look ahead to see if it's a range when the last thing
+                   was a character: if this is a hyphen not at the
+                   beginning or the end of a list, then it's the range
+                   operator.  */
+                if (c == '-'
+                    && !(p - 2 >= pattern && p[-2] == '[')
+                    && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
+                    && *p != ']')
+                  {
+                    reg_errcode_t ret
+                      = compile_range (&p, pend, translate, syntax, b);
+                    if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
+                  }
+
+                else if (p[0] == '-' && p[1] != ']')
+                  { /* This handles ranges made up of characters only.  */
+                    reg_errcode_t ret;
+
+		    /* Move past the `-'.  */
+                    PATFETCH (c1);
+
+                    ret = compile_range (&p, pend, translate, syntax, b);
+                    if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
+                  }
+
+                /* See if we're at the beginning of a possible character
+                   class.  */
+
+                else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
+                  { /* Leave room for the null.  */
+                    char str[CHAR_CLASS_MAX_LENGTH + 1];
+
+                    PATFETCH (c);
+                    c1 = 0;
+
+                    /* If pattern is `[[:'.  */
+                    if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+                    for (;;)
+                      {
+                        PATFETCH (c);
+                        if ((c == ':' && *p == ']') || p == pend)
+                          break;
+			if (c1 < CHAR_CLASS_MAX_LENGTH)
+			  str[c1++] = c;
+			else
+			  /* This is in any case an invalid class name.  */
+			  str[0] = '\0';
+                      }
+                    str[c1] = '\0';
+
+                    /* If isn't a word bracketed by `[:' and `:]':
+                       undo the ending character, the letters, and leave
+                       the leading `:' and `[' (but set bits for them).  */
+                    if (c == ':' && *p == ']')
+                      {
+#if defined _LIBC || WIDE_CHAR_SUPPORT
+                        boolean is_lower = STREQ (str, "lower");
+                        boolean is_upper = STREQ (str, "upper");
+			wctype_t wt;
+                        int ch;
+
+			wt = IS_CHAR_CLASS (str);
+			if (wt == 0)
+			  FREE_STACK_RETURN (REG_ECTYPE);
+
+                        /* Throw away the ] at the end of the character
+                           class.  */
+                        PATFETCH (c);
+
+                        if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+                        for (ch = 0; ch < 1 << BYTEWIDTH; ++ch)
+			  {
+# ifdef _LIBC
+			    if (__iswctype (__btowc (ch), wt))
+			      SET_LIST_BIT (ch);
+# else
+			    if (iswctype (btowc (ch), wt))
+			      SET_LIST_BIT (ch);
+# endif
+
+			    if (translate && (is_upper || is_lower)
+				&& (ISUPPER (ch) || ISLOWER (ch)))
+			      SET_LIST_BIT (ch);
+			  }
+
+                        had_char_class = true;
+#else
+                        int ch;
+                        boolean is_alnum = STREQ (str, "alnum");
+                        boolean is_alpha = STREQ (str, "alpha");
+                        boolean is_blank = STREQ (str, "blank");
+                        boolean is_cntrl = STREQ (str, "cntrl");
+                        boolean is_digit = STREQ (str, "digit");
+                        boolean is_graph = STREQ (str, "graph");
+                        boolean is_lower = STREQ (str, "lower");
+                        boolean is_print = STREQ (str, "print");
+                        boolean is_punct = STREQ (str, "punct");
+                        boolean is_space = STREQ (str, "space");
+                        boolean is_upper = STREQ (str, "upper");
+                        boolean is_xdigit = STREQ (str, "xdigit");
+
+                        if (!IS_CHAR_CLASS (str))
+			  FREE_STACK_RETURN (REG_ECTYPE);
+
+                        /* Throw away the ] at the end of the character
+                           class.  */
+                        PATFETCH (c);
+
+                        if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+                        for (ch = 0; ch < 1 << BYTEWIDTH; ch++)
+                          {
+			    /* This was split into 3 if's to
+			       avoid an arbitrary limit in some compiler.  */
+                            if (   (is_alnum  && ISALNUM (ch))
+                                || (is_alpha  && ISALPHA (ch))
+                                || (is_blank  && ISBLANK (ch))
+                                || (is_cntrl  && ISCNTRL (ch)))
+			      SET_LIST_BIT (ch);
+			    if (   (is_digit  && ISDIGIT (ch))
+                                || (is_graph  && ISGRAPH (ch))
+                                || (is_lower  && ISLOWER (ch))
+                                || (is_print  && ISPRINT (ch)))
+			      SET_LIST_BIT (ch);
+			    if (   (is_punct  && ISPUNCT (ch))
+                                || (is_space  && ISSPACE (ch))
+                                || (is_upper  && ISUPPER (ch))
+                                || (is_xdigit && ISXDIGIT (ch)))
+			      SET_LIST_BIT (ch);
+			    if (   translate && (is_upper || is_lower)
+				&& (ISUPPER (ch) || ISLOWER (ch)))
+			      SET_LIST_BIT (ch);
+                          }
+                        had_char_class = true;
+#endif	/* libc || wctype.h */
+                      }
+                    else
+                      {
+                        c1++;
+                        while (c1--)
+                          PATUNFETCH;
+                        SET_LIST_BIT ('[');
+                        SET_LIST_BIT (':');
+                        had_char_class = false;
+                      }
+                  }
+                else
+                  {
+                    had_char_class = false;
+                    SET_LIST_BIT (c);
+                  }
+              }
+
+            /* Discard any (non)matching list bytes that are all 0 at the
+               end of the map.  Decrease the map-length byte too.  */
+            while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
+              b[-1]--;
+            b += b[-1];
+          }
+          break;
+
+
+	case '(':
+          if (syntax & RE_NO_BK_PARENS)
+            goto handle_open;
+          else
+            goto normal_char;
+
+
+        case ')':
+          if (syntax & RE_NO_BK_PARENS)
+            goto handle_close;
+          else
+            goto normal_char;
+
+
+        case '\n':
+          if (syntax & RE_NEWLINE_ALT)
+            goto handle_alt;
+          else
+            goto normal_char;
+
+
+	case '|':
+          if (syntax & RE_NO_BK_VBAR)
+            goto handle_alt;
+          else
+            goto normal_char;
+
+
+        case '{':
+           if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES)
+             goto handle_interval;
+           else
+             goto normal_char;
+
+
+        case '\\':
+          if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+          /* Do not translate the character after the \, so that we can
+             distinguish, e.g., \B from \b, even if we normally would
+             translate, e.g., B to b.  */
+          PATFETCH_RAW (c);
+
+          switch (c)
+            {
+            case '(':
+              if (syntax & RE_NO_BK_PARENS)
+                goto normal_backslash;
+
+            handle_open:
+              bufp->re_nsub++;
+              regnum++;
+
+              if (COMPILE_STACK_FULL)
+                {
+                  RETALLOC (compile_stack.stack, compile_stack.size << 1,
+                            compile_stack_elt_t);
+                  if (compile_stack.stack == NULL) return REG_ESPACE;
+
+                  compile_stack.size <<= 1;
+                }
+
+              /* These are the values to restore when we hit end of this
+                 group.  They are all relative offsets, so that if the
+                 whole pattern moves because of realloc, they will still
+                 be valid.  */
+              COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer;
+              COMPILE_STACK_TOP.fixup_alt_jump
+                = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0;
+              COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer;
+              COMPILE_STACK_TOP.regnum = regnum;
+
+              /* We will eventually replace the 0 with the number of
+                 groups inner to this one.  But do not push a
+                 start_memory for groups beyond the last one we can
+                 represent in the compiled pattern.  */
+              if (regnum <= MAX_REGNUM)
+                {
+                  COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2;
+                  BUF_PUSH_3 (start_memory, regnum, 0);
+                }
+
+              compile_stack.avail++;
+
+              fixup_alt_jump = 0;
+              laststart = 0;
+              begalt = b;
+	      /* If we've reached MAX_REGNUM groups, then this open
+		 won't actually generate any code, so we'll have to
+		 clear pending_exact explicitly.  */
+	      pending_exact = 0;
+              break;
+
+
+            case ')':
+              if (syntax & RE_NO_BK_PARENS) goto normal_backslash;
+
+              if (COMPILE_STACK_EMPTY)
+		{
+		  if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+		    goto normal_backslash;
+		  else
+		    FREE_STACK_RETURN (REG_ERPAREN);
+		}
+
+            handle_close:
+              if (fixup_alt_jump)
+                { /* Push a dummy failure point at the end of the
+                     alternative for a possible future
+                     `pop_failure_jump' to pop.  See comments at
+                     `push_dummy_failure' in `re_match_2'.  */
+                  BUF_PUSH (push_dummy_failure);
+
+                  /* We allocated space for this jump when we assigned
+                     to `fixup_alt_jump', in the `handle_alt' case below.  */
+                  STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1);
+                }
+
+              /* See similar code for backslashed left paren above.  */
+              if (COMPILE_STACK_EMPTY)
+		{
+		  if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+		    goto normal_char;
+		  else
+		    FREE_STACK_RETURN (REG_ERPAREN);
+		}
+
+              /* Since we just checked for an empty stack above, this
+                 ``can't happen''.  */
+              assert (compile_stack.avail != 0);
+              {
+                /* We don't just want to restore into `regnum', because
+                   later groups should continue to be numbered higher,
+                   as in `(ab)c(de)' -- the second group is #2.  */
+                regnum_t this_group_regnum;
+
+                compile_stack.avail--;
+                begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset;
+                fixup_alt_jump
+                  = COMPILE_STACK_TOP.fixup_alt_jump
+                    ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1
+                    : 0;
+                laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset;
+                this_group_regnum = COMPILE_STACK_TOP.regnum;
+		/* If we've reached MAX_REGNUM groups, then this open
+		   won't actually generate any code, so we'll have to
+		   clear pending_exact explicitly.  */
+		pending_exact = 0;
+
+                /* We're at the end of the group, so now we know how many
+                   groups were inside this one.  */
+                if (this_group_regnum <= MAX_REGNUM)
+                  {
+                    unsigned char *inner_group_loc
+                      = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset;
+
+                    *inner_group_loc = regnum - this_group_regnum;
+                    BUF_PUSH_3 (stop_memory, this_group_regnum,
+                                regnum - this_group_regnum);
+                  }
+              }
+              break;
+
+
+            case '|':					/* `\|'.  */
+              if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR)
+                goto normal_backslash;
+            handle_alt:
+              if (syntax & RE_LIMITED_OPS)
+                goto normal_char;
+
+              /* Insert before the previous alternative a jump which
+                 jumps to this alternative if the former fails.  */
+              GET_BUFFER_SPACE (3);
+              INSERT_JUMP (on_failure_jump, begalt, b + 6);
+              pending_exact = 0;
+              b += 3;
+
+              /* The alternative before this one has a jump after it
+                 which gets executed if it gets matched.  Adjust that
+                 jump so it will jump to this alternative's analogous
+                 jump (put in below, which in turn will jump to the next
+                 (if any) alternative's such jump, etc.).  The last such
+                 jump jumps to the correct final destination.  A picture:
+                          _____ _____
+                          |   | |   |
+                          |   v |   v
+                         a | b   | c
+
+                 If we are at `b', then fixup_alt_jump right now points to a
+                 three-byte space after `a'.  We'll put in the jump, set
+                 fixup_alt_jump to right after `b', and leave behind three
+                 bytes which we'll fill in when we get to after `c'.  */
+
+              if (fixup_alt_jump)
+                STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
+
+              /* Mark and leave space for a jump after this alternative,
+                 to be filled in later either by next alternative or
+                 when know we're at the end of a series of alternatives.  */
+              fixup_alt_jump = b;
+              GET_BUFFER_SPACE (3);
+              b += 3;
+
+              laststart = 0;
+              begalt = b;
+              break;
+
+
+            case '{':
+              /* If \{ is a literal.  */
+              if (!(syntax & RE_INTERVALS)
+                     /* If we're at `\{' and it's not the open-interval
+                        operator.  */
+                  || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+                  || (p - 2 == pattern  &&  p == pend))
+                goto normal_backslash;
+
+            handle_interval:
+              {
+                /* If got here, then the syntax allows intervals.  */
+
+                /* At least (most) this many matches must be made.  */
+                int lower_bound = -1, upper_bound = -1;
+
+                beg_interval = p - 1;
+
+                if (p == pend)
+                  {
+                    if (syntax & RE_NO_BK_BRACES)
+                      goto unfetch_interval;
+                    else
+                      FREE_STACK_RETURN (REG_EBRACE);
+                  }
+
+                GET_UNSIGNED_NUMBER (lower_bound);
+
+                if (c == ',')
+                  {
+                    GET_UNSIGNED_NUMBER (upper_bound);
+                    if (upper_bound < 0) upper_bound = RE_DUP_MAX;
+                  }
+                else
+                  /* Interval such as `{1}' => match exactly once. */
+                  upper_bound = lower_bound;
+
+                if (lower_bound < 0 || upper_bound > RE_DUP_MAX
+                    || lower_bound > upper_bound)
+                  {
+                    if (syntax & RE_NO_BK_BRACES)
+                      goto unfetch_interval;
+                    else
+                      FREE_STACK_RETURN (REG_BADBR);
+                  }
+
+                if (!(syntax & RE_NO_BK_BRACES))
+                  {
+                    if (c != '\\') FREE_STACK_RETURN (REG_EBRACE);
+
+                    PATFETCH (c);
+                  }
+
+                if (c != '}')
+                  {
+                    if (syntax & RE_NO_BK_BRACES)
+                      goto unfetch_interval;
+                    else
+                      FREE_STACK_RETURN (REG_BADBR);
+                  }
+
+                /* We just parsed a valid interval.  */
+
+                /* If it's invalid to have no preceding re.  */
+                if (!laststart)
+                  {
+                    if (syntax & RE_CONTEXT_INVALID_OPS)
+                      FREE_STACK_RETURN (REG_BADRPT);
+                    else if (syntax & RE_CONTEXT_INDEP_OPS)
+                      laststart = b;
+                    else
+                      goto unfetch_interval;
+                  }
+
+                /* If the upper bound is zero, don't want to succeed at
+                   all; jump from `laststart' to `b + 3', which will be
+                   the end of the buffer after we insert the jump.  */
+                 if (upper_bound == 0)
+                   {
+                     GET_BUFFER_SPACE (3);
+                     INSERT_JUMP (jump, laststart, b + 3);
+                     b += 3;
+                   }
+
+                 /* Otherwise, we have a nontrivial interval.  When
+                    we're all done, the pattern will look like:
+                      set_number_at <jump count> <upper bound>
+                      set_number_at <succeed_n count> <lower bound>
+                      succeed_n <after jump addr> <succeed_n count>
+                      <body of loop>
+                      jump_n <succeed_n addr> <jump count>
+                    (The upper bound and `jump_n' are omitted if
+                    `upper_bound' is 1, though.)  */
+                 else
+                   { /* If the upper bound is > 1, we need to insert
+                        more at the end of the loop.  */
+                     unsigned nbytes = 10 + (upper_bound > 1) * 10;
+
+                     GET_BUFFER_SPACE (nbytes);
+
+                     /* Initialize lower bound of the `succeed_n', even
+                        though it will be set during matching by its
+                        attendant `set_number_at' (inserted next),
+                        because `re_compile_fastmap' needs to know.
+                        Jump to the `jump_n' we might insert below.  */
+                     INSERT_JUMP2 (succeed_n, laststart,
+                                   b + 5 + (upper_bound > 1) * 5,
+                                   lower_bound);
+                     b += 5;
+
+                     /* Code to initialize the lower bound.  Insert
+                        before the `succeed_n'.  The `5' is the last two
+                        bytes of this `set_number_at', plus 3 bytes of
+                        the following `succeed_n'.  */
+                     insert_op2 (set_number_at, laststart, 5, lower_bound, b);
+                     b += 5;
+
+                     if (upper_bound > 1)
+                       { /* More than one repetition is allowed, so
+                            append a backward jump to the `succeed_n'
+                            that starts this interval.
+
+                            When we've reached this during matching,
+                            we'll have matched the interval once, so
+                            jump back only `upper_bound - 1' times.  */
+                         STORE_JUMP2 (jump_n, b, laststart + 5,
+                                      upper_bound - 1);
+                         b += 5;
+
+                         /* The location we want to set is the second
+                            parameter of the `jump_n'; that is `b-2' as
+                            an absolute address.  `laststart' will be
+                            the `set_number_at' we're about to insert;
+                            `laststart+3' the number to set, the source
+                            for the relative address.  But we are
+                            inserting into the middle of the pattern --
+                            so everything is getting moved up by 5.
+                            Conclusion: (b - 2) - (laststart + 3) + 5,
+                            i.e., b - laststart.
+
+                            We insert this at the beginning of the loop
+                            so that if we fail during matching, we'll
+                            reinitialize the bounds.  */
+                         insert_op2 (set_number_at, laststart, b - laststart,
+                                     upper_bound - 1, b);
+                         b += 5;
+                       }
+                   }
+                pending_exact = 0;
+                beg_interval = NULL;
+              }
+              break;
+
+            unfetch_interval:
+              /* If an invalid interval, match the characters as literals.  */
+               assert (beg_interval);
+               p = beg_interval;
+               beg_interval = NULL;
+
+               /* normal_char and normal_backslash need `c'.  */
+               PATFETCH (c);
+
+               if (!(syntax & RE_NO_BK_BRACES))
+                 {
+                   if (p > pattern  &&  p[-1] == '\\')
+                     goto normal_backslash;
+                 }
+               goto normal_char;
+
+#ifdef emacs
+            /* There is no way to specify the before_dot and after_dot
+               operators.  rms says this is ok.  --karl  */
+            case '=':
+              BUF_PUSH (at_dot);
+              break;
+
+            case 's':
+              laststart = b;
+              PATFETCH (c);
+              BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]);
+              break;
+
+            case 'S':
+              laststart = b;
+              PATFETCH (c);
+              BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]);
+              break;
+#endif /* emacs */
+
+
+            case 'w':
+	      if (syntax & RE_NO_GNU_OPS)
+		goto normal_char;
+              laststart = b;
+              BUF_PUSH (wordchar);
+              break;
+
+
+            case 'W':
+	      if (syntax & RE_NO_GNU_OPS)
+		goto normal_char;
+              laststart = b;
+              BUF_PUSH (notwordchar);
+              break;
+
+
+            case '<':
+	      if (syntax & RE_NO_GNU_OPS)
+		goto normal_char;
+              BUF_PUSH (wordbeg);
+              break;
+
+            case '>':
+	      if (syntax & RE_NO_GNU_OPS)
+		goto normal_char;
+              BUF_PUSH (wordend);
+              break;
+
+            case 'b':
+	      if (syntax & RE_NO_GNU_OPS)
+		goto normal_char;
+              BUF_PUSH (wordbound);
+              break;
+
+            case 'B':
+	      if (syntax & RE_NO_GNU_OPS)
+		goto normal_char;
+              BUF_PUSH (notwordbound);
+              break;
+
+            case '`':
+	      if (syntax & RE_NO_GNU_OPS)
+		goto normal_char;
+              BUF_PUSH (begbuf);
+              break;
+
+            case '\'':
+	      if (syntax & RE_NO_GNU_OPS)
+		goto normal_char;
+              BUF_PUSH (endbuf);
+              break;
+
+            case '1': case '2': case '3': case '4': case '5':
+            case '6': case '7': case '8': case '9':
+              if (syntax & RE_NO_BK_REFS)
+                goto normal_char;
+
+              c1 = c - '0';
+
+              if (c1 > regnum)
+                FREE_STACK_RETURN (REG_ESUBREG);
+
+              /* Can't back reference to a subexpression if inside of it.  */
+              if (group_in_compile_stack (compile_stack, (regnum_t) c1))
+                goto normal_char;
+
+              laststart = b;
+              BUF_PUSH_2 (duplicate, c1);
+              break;
+
+
+            case '+':
+            case '?':
+              if (syntax & RE_BK_PLUS_QM)
+                goto handle_plus;
+              else
+                goto normal_backslash;
+
+            default:
+            normal_backslash:
+              /* You might think it would be useful for \ to mean
+                 not to translate; but if we don't translate it
+                 it will never match anything.  */
+              c = TRANSLATE (c);
+              goto normal_char;
+            }
+          break;
+
+
+	default:
+        /* Expects the character in `c'.  */
+	normal_char:
+	      /* If no exactn currently being built.  */
+          if (!pending_exact
+
+              /* If last exactn not at current position.  */
+              || pending_exact + *pending_exact + 1 != b
+
+              /* We have only one byte following the exactn for the count.  */
+	      || *pending_exact == (1 << BYTEWIDTH) - 1
+
+              /* If followed by a repetition operator.  */
+              || *p == '*' || *p == '^'
+	      || ((syntax & RE_BK_PLUS_QM)
+		  ? *p == '\\' && (p[1] == '+' || p[1] == '?')
+		  : (*p == '+' || *p == '?'))
+	      || ((syntax & RE_INTERVALS)
+                  && ((syntax & RE_NO_BK_BRACES)
+		      ? *p == '{'
+                      : (p[0] == '\\' && p[1] == '{'))))
+	    {
+	      /* Start building a new exactn.  */
+
+              laststart = b;
+
+	      BUF_PUSH_2 (exactn, 0);
+	      pending_exact = b - 1;
+            }
+
+	  BUF_PUSH (c);
+          (*pending_exact)++;
+	  break;
+        } /* switch (c) */
+    } /* while p != pend */
+
+
+  /* Through the pattern now.  */
+
+  if (fixup_alt_jump)
+    STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
+
+  if (!COMPILE_STACK_EMPTY)
+    FREE_STACK_RETURN (REG_EPAREN);
+
+  /* If we don't want backtracking, force success
+     the first time we reach the end of the compiled pattern.  */
+  if (syntax & RE_NO_POSIX_BACKTRACKING)
+    BUF_PUSH (succeed);
+
+  free (compile_stack.stack);
+
+  /* We have succeeded; set the length of the buffer.  */
+  bufp->used = b - bufp->buffer;
+
+#ifdef DEBUG
+  if (debug)
+    {
+      DEBUG_PRINT1 ("\nCompiled pattern: \n");
+      print_compiled_pattern (bufp);
+    }
+#endif /* DEBUG */
+
+#ifndef MATCH_MAY_ALLOCATE
+  /* Initialize the failure stack to the largest possible stack.  This
+     isn't necessary unless we're trying to avoid calling alloca in
+     the search and match routines.  */
+  {
+    int num_regs = bufp->re_nsub + 1;
+
+    /* Since DOUBLE_FAIL_STACK refuses to double only if the current size
+       is strictly greater than re_max_failures, the largest possible stack
+       is 2 * re_max_failures failure points.  */
+    if (fail_stack.size < (2 * re_max_failures * MAX_FAILURE_ITEMS))
+      {
+	fail_stack.size = (2 * re_max_failures * MAX_FAILURE_ITEMS);
+
+# ifdef emacs
+	if (! fail_stack.stack)
+	  fail_stack.stack
+	    = (fail_stack_elt_t *) xmalloc (fail_stack.size
+					    * sizeof (fail_stack_elt_t));
+	else
+	  fail_stack.stack
+	    = (fail_stack_elt_t *) xrealloc (fail_stack.stack,
+					     (fail_stack.size
+					      * sizeof (fail_stack_elt_t)));
+# else /* not emacs */
+	if (! fail_stack.stack)
+	  fail_stack.stack
+	    = (fail_stack_elt_t *) malloc (fail_stack.size
+					   * sizeof (fail_stack_elt_t));
+	else
+	  fail_stack.stack
+	    = (fail_stack_elt_t *) realloc (fail_stack.stack,
+					    (fail_stack.size
+					     * sizeof (fail_stack_elt_t)));
+# endif /* not emacs */
+      }
+
+    regex_grow_registers (num_regs);
+  }
+#endif /* not MATCH_MAY_ALLOCATE */
+
+  return REG_NOERROR;
+} /* regex_compile */
+
+/* Subroutines for `regex_compile'.  */
+
+/* Store OP at LOC followed by two-byte integer parameter ARG.  */
+
+static void
+store_op1 (op, loc, arg)
+    re_opcode_t op;
+    unsigned char *loc;
+    int arg;
+{
+  *loc = (unsigned char) op;
+  STORE_NUMBER (loc + 1, arg);
+}
+
+
+/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2.  */
+
+static void
+store_op2 (op, loc, arg1, arg2)
+    re_opcode_t op;
+    unsigned char *loc;
+    int arg1, arg2;
+{
+  *loc = (unsigned char) op;
+  STORE_NUMBER (loc + 1, arg1);
+  STORE_NUMBER (loc + 3, arg2);
+}
+
+
+/* Copy the bytes from LOC to END to open up three bytes of space at LOC
+   for OP followed by two-byte integer parameter ARG.  */
+
+static void
+insert_op1 (op, loc, arg, end)
+    re_opcode_t op;
+    unsigned char *loc;
+    int arg;
+    unsigned char *end;
+{
+  register unsigned char *pfrom = end;
+  register unsigned char *pto = end + 3;
+
+  while (pfrom != loc)
+    *--pto = *--pfrom;
+
+  store_op1 (op, loc, arg);
+}
+
+
+/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2.  */
+
+static void
+insert_op2 (op, loc, arg1, arg2, end)
+    re_opcode_t op;
+    unsigned char *loc;
+    int arg1, arg2;
+    unsigned char *end;
+{
+  register unsigned char *pfrom = end;
+  register unsigned char *pto = end + 5;
+
+  while (pfrom != loc)
+    *--pto = *--pfrom;
+
+  store_op2 (op, loc, arg1, arg2);
+}
+
+
+/* P points to just after a ^ in PATTERN.  Return true if that ^ comes
+   after an alternative or a begin-subexpression.  We assume there is at
+   least one character before the ^.  */
+
+static boolean
+at_begline_loc_p (pattern, p, syntax)
+    const char *pattern, *p;
+    reg_syntax_t syntax;
+{
+  const char *prev = p - 2;
+  boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\';
+
+  return
+       /* After a subexpression?  */
+       (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash))
+       /* After an alternative?  */
+    || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash));
+}
+
+
+/* The dual of at_begline_loc_p.  This one is for $.  We assume there is
+   at least one character after the $, i.e., `P < PEND'.  */
+
+static boolean
+at_endline_loc_p (p, pend, syntax)
+    const char *p, *pend;
+    reg_syntax_t syntax;
+{
+  const char *next = p;
+  boolean next_backslash = *next == '\\';
+  const char *next_next = p + 1 < pend ? p + 1 : 0;
+
+  return
+       /* Before a subexpression?  */
+       (syntax & RE_NO_BK_PARENS ? *next == ')'
+        : next_backslash && next_next && *next_next == ')')
+       /* Before an alternative?  */
+    || (syntax & RE_NO_BK_VBAR ? *next == '|'
+        : next_backslash && next_next && *next_next == '|');
+}
+
+
+/* Returns true if REGNUM is in one of COMPILE_STACK's elements and
+   false if it's not.  */
+
+static boolean
+group_in_compile_stack (compile_stack, regnum)
+    compile_stack_type compile_stack;
+    regnum_t regnum;
+{
+  int this_element;
+
+  for (this_element = compile_stack.avail - 1;
+       this_element >= 0;
+       this_element--)
+    if (compile_stack.stack[this_element].regnum == regnum)
+      return true;
+
+  return false;
+}
+
+
+/* Read the ending character of a range (in a bracket expression) from the
+   uncompiled pattern *P_PTR (which ends at PEND).  We assume the
+   starting character is in `P[-2]'.  (`P[-1]' is the character `-'.)
+   Then we set the translation of all bits between the starting and
+   ending characters (inclusive) in the compiled pattern B.
+
+   Return an error code.
+
+   We use these short variable names so we can use the same macros as
+   `regex_compile' itself.  */
+
+static reg_errcode_t
+compile_range (p_ptr, pend, translate, syntax, b)
+    const char **p_ptr, *pend;
+    RE_TRANSLATE_TYPE translate;
+    reg_syntax_t syntax;
+    unsigned char *b;
+{
+  unsigned this_char;
+
+  const char *p = *p_ptr;
+  unsigned int range_start, range_end;
+
+  if (p == pend)
+    return REG_ERANGE;
+
+  /* Even though the pattern is a signed `char *', we need to fetch
+     with unsigned char *'s; if the high bit of the pattern character
+     is set, the range endpoints will be negative if we fetch using a
+     signed char *.
+
+     We also want to fetch the endpoints without translating them; the
+     appropriate translation is done in the bit-setting loop below.  */
+  /* The SVR4 compiler on the 3B2 had trouble with unsigned const char *.  */
+  range_start = ((const unsigned char *) p)[-2];
+  range_end   = ((const unsigned char *) p)[0];
+
+  /* Have to increment the pointer into the pattern string, so the
+     caller isn't still at the ending character.  */
+  (*p_ptr)++;
+
+  /* If the start is after the end, the range is empty.  */
+  if (range_start > range_end)
+    return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR;
+
+  /* Here we see why `this_char' has to be larger than an `unsigned
+     char' -- the range is inclusive, so if `range_end' == 0xff
+     (assuming 8-bit characters), we would otherwise go into an infinite
+     loop, since all characters <= 0xff.  */
+  for (this_char = range_start; this_char <= range_end; this_char++)
+    {
+      SET_LIST_BIT (TRANSLATE (this_char));
+    }
+
+  return REG_NOERROR;
+}
+
+/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in
+   BUFP.  A fastmap records which of the (1 << BYTEWIDTH) possible
+   characters can start a string that matches the pattern.  This fastmap
+   is used by re_search to skip quickly over impossible starting points.
+
+   The caller must supply the address of a (1 << BYTEWIDTH)-byte data
+   area as BUFP->fastmap.
+
+   We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in
+   the pattern buffer.
+
+   Returns 0 if we succeed, -2 if an internal error.   */
+
+int
+re_compile_fastmap (bufp)
+     struct re_pattern_buffer *bufp;
+{
+  int j, k;
+#ifdef MATCH_MAY_ALLOCATE
+  fail_stack_type fail_stack;
+#endif
+#ifndef REGEX_MALLOC
+  char *destination;
+#endif
+
+  register char *fastmap = bufp->fastmap;
+  unsigned char *pattern = bufp->buffer;
+  unsigned char *p = pattern;
+  register unsigned char *pend = pattern + bufp->used;
+
+#ifdef REL_ALLOC
+  /* This holds the pointer to the failure stack, when
+     it is allocated relocatably.  */
+  fail_stack_elt_t *failure_stack_ptr;
+#endif
+
+  /* Assume that each path through the pattern can be null until
+     proven otherwise.  We set this false at the bottom of switch
+     statement, to which we get only if a particular path doesn't
+     match the empty string.  */
+  boolean path_can_be_null = true;
+
+  /* We aren't doing a `succeed_n' to begin with.  */
+  boolean succeed_n_p = false;
+
+  assert (fastmap != NULL && p != NULL);
+
+  INIT_FAIL_STACK ();
+  bzero (fastmap, 1 << BYTEWIDTH);  /* Assume nothing's valid.  */
+  bufp->fastmap_accurate = 1;	    /* It will be when we're done.  */
+  bufp->can_be_null = 0;
+
+  while (1)
+    {
+      if (p == pend || *p == succeed)
+	{
+	  /* We have reached the (effective) end of pattern.  */
+	  if (!FAIL_STACK_EMPTY ())
+	    {
+	      bufp->can_be_null |= path_can_be_null;
+
+	      /* Reset for next path.  */
+	      path_can_be_null = true;
+
+	      p = fail_stack.stack[--fail_stack.avail].pointer;
+
+	      continue;
+	    }
+	  else
+	    break;
+	}
+
+      /* We should never be about to go beyond the end of the pattern.  */
+      assert (p < pend);
+
+      switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++))
+	{
+
+        /* I guess the idea here is to simply not bother with a fastmap
+           if a backreference is used, since it's too hard to figure out
+           the fastmap for the corresponding group.  Setting
+           `can_be_null' stops `re_search_2' from using the fastmap, so
+           that is all we do.  */
+	case duplicate:
+	  bufp->can_be_null = 1;
+          goto done;
+
+
+      /* Following are the cases which match a character.  These end
+         with `break'.  */
+
+	case exactn:
+          fastmap[p[1]] = 1;
+	  break;
+
+
+        case charset:
+          for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+	    if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
+              fastmap[j] = 1;
+	  break;
+
+
+	case charset_not:
+	  /* Chars beyond end of map must be allowed.  */
+	  for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
+            fastmap[j] = 1;
+
+	  for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+	    if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
+              fastmap[j] = 1;
+          break;
+
+
+	case wordchar:
+	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+	    if (SYNTAX (j) == Sword)
+	      fastmap[j] = 1;
+	  break;
+
+
+	case notwordchar:
+	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+	    if (SYNTAX (j) != Sword)
+	      fastmap[j] = 1;
+	  break;
+
+
+        case anychar:
+	  {
+	    int fastmap_newline = fastmap['\n'];
+
+	    /* `.' matches anything ...  */
+	    for (j = 0; j < (1 << BYTEWIDTH); j++)
+	      fastmap[j] = 1;
+
+	    /* ... except perhaps newline.  */
+	    if (!(bufp->syntax & RE_DOT_NEWLINE))
+	      fastmap['\n'] = fastmap_newline;
+
+	    /* Return if we have already set `can_be_null'; if we have,
+	       then the fastmap is irrelevant.  Something's wrong here.  */
+	    else if (bufp->can_be_null)
+	      goto done;
+
+	    /* Otherwise, have to check alternative paths.  */
+	    break;
+	  }
+
+#ifdef emacs
+        case syntaxspec:
+	  k = *p++;
+	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+	    if (SYNTAX (j) == (enum syntaxcode) k)
+	      fastmap[j] = 1;
+	  break;
+
+
+	case notsyntaxspec:
+	  k = *p++;
+	  for (j = 0; j < (1 << BYTEWIDTH); j++)
+	    if (SYNTAX (j) != (enum syntaxcode) k)
+	      fastmap[j] = 1;
+	  break;
+
+
+      /* All cases after this match the empty string.  These end with
+         `continue'.  */
+
+
+	case before_dot:
+	case at_dot:
+	case after_dot:
+          continue;
+#endif /* emacs */
+
+
+        case no_op:
+        case begline:
+        case endline:
+	case begbuf:
+	case endbuf:
+	case wordbound:
+	case notwordbound:
+	case wordbeg:
+	case wordend:
+        case push_dummy_failure:
+          continue;
+
+
+	case jump_n:
+        case pop_failure_jump:
+	case maybe_pop_jump:
+	case jump:
+        case jump_past_alt:
+	case dummy_failure_jump:
+          EXTRACT_NUMBER_AND_INCR (j, p);
+	  p += j;
+	  if (j > 0)
+	    continue;
+
+          /* Jump backward implies we just went through the body of a
+             loop and matched nothing.  Opcode jumped to should be
+             `on_failure_jump' or `succeed_n'.  Just treat it like an
+             ordinary jump.  For a * loop, it has pushed its failure
+             point already; if so, discard that as redundant.  */
+          if ((re_opcode_t) *p != on_failure_jump
+	      && (re_opcode_t) *p != succeed_n)
+	    continue;
+
+          p++;
+          EXTRACT_NUMBER_AND_INCR (j, p);
+          p += j;
+
+          /* If what's on the stack is where we are now, pop it.  */
+          if (!FAIL_STACK_EMPTY ()
+	      && fail_stack.stack[fail_stack.avail - 1].pointer == p)
+            fail_stack.avail--;
+
+          continue;
+
+
+        case on_failure_jump:
+        case on_failure_keep_string_jump:
+	handle_on_failure_jump:
+          EXTRACT_NUMBER_AND_INCR (j, p);
+
+          /* For some patterns, e.g., `(a?)?', `p+j' here points to the
+             end of the pattern.  We don't want to push such a point,
+             since when we restore it above, entering the switch will
+             increment `p' past the end of the pattern.  We don't need
+             to push such a point since we obviously won't find any more
+             fastmap entries beyond `pend'.  Such a pattern can match
+             the null string, though.  */
+          if (p + j < pend)
+            {
+              if (!PUSH_PATTERN_OP (p + j, fail_stack))
+		{
+		  RESET_FAIL_STACK ();
+		  return -2;
+		}
+            }
+          else
+            bufp->can_be_null = 1;
+
+          if (succeed_n_p)
+            {
+              EXTRACT_NUMBER_AND_INCR (k, p);	/* Skip the n.  */
+              succeed_n_p = false;
+	    }
+
+          continue;
+
+
+	case succeed_n:
+          /* Get to the number of times to succeed.  */
+          p += 2;
+
+          /* Increment p past the n for when k != 0.  */
+          EXTRACT_NUMBER_AND_INCR (k, p);
+          if (k == 0)
+	    {
+              p -= 4;
+  	      succeed_n_p = true;  /* Spaghetti code alert.  */
+              goto handle_on_failure_jump;
+            }
+          continue;
+
+
+	case set_number_at:
+          p += 4;
+          continue;
+
+
+	case start_memory:
+        case stop_memory:
+	  p += 2;
+	  continue;
+
+
+	default:
+          abort (); /* We have listed all the cases.  */
+        } /* switch *p++ */
+
+      /* Getting here means we have found the possible starting
+         characters for one path of the pattern -- and that the empty
+         string does not match.  We need not follow this path further.
+         Instead, look at the next alternative (remembered on the
+         stack), or quit if no more.  The test at the top of the loop
+         does these things.  */
+      path_can_be_null = false;
+      p = pend;
+    } /* while p */
+
+  /* Set `can_be_null' for the last path (also the first path, if the
+     pattern is empty).  */
+  bufp->can_be_null |= path_can_be_null;
+
+ done:
+  RESET_FAIL_STACK ();
+  return 0;
+} /* re_compile_fastmap */
+#ifdef _LIBC
+weak_alias (__re_compile_fastmap, re_compile_fastmap)
+#endif
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+   ENDS.  Subsequent matches using PATTERN_BUFFER and REGS will use
+   this memory for recording register information.  STARTS and ENDS
+   must be allocated using the malloc library routine, and must each
+   be at least NUM_REGS * sizeof (regoff_t) bytes long.
+
+   If NUM_REGS == 0, then subsequent matches should allocate their own
+   register data.
+
+   Unless this function is called, the first search or match using
+   PATTERN_BUFFER will allocate its own register data, without
+   freeing the old data.  */
+
+void
+re_set_registers (bufp, regs, num_regs, starts, ends)
+    struct re_pattern_buffer *bufp;
+    struct re_registers *regs;
+    unsigned num_regs;
+    regoff_t *starts, *ends;
+{
+  if (num_regs)
+    {
+      bufp->regs_allocated = REGS_REALLOCATE;
+      regs->num_regs = num_regs;
+      regs->start = starts;
+      regs->end = ends;
+    }
+  else
+    {
+      bufp->regs_allocated = REGS_UNALLOCATED;
+      regs->num_regs = 0;
+      regs->start = regs->end = (regoff_t *) 0;
+    }
+}
+#ifdef _LIBC
+weak_alias (__re_set_registers, re_set_registers)
+#endif
+
+/* Searching routines.  */
+
+/* Like re_search_2, below, but only one string is specified, and
+   doesn't let you say where to stop matching. */
+
+int
+re_search (bufp, string, size, startpos, range, regs)
+     struct re_pattern_buffer *bufp;
+     const char *string;
+     int size, startpos, range;
+     struct re_registers *regs;
+{
+  return re_search_2 (bufp, NULL, 0, string, size, startpos, range,
+		      regs, size);
+}
+#ifdef _LIBC
+weak_alias (__re_search, re_search)
+#endif
+
+
+/* Using the compiled pattern in BUFP->buffer, first tries to match the
+   virtual concatenation of STRING1 and STRING2, starting first at index
+   STARTPOS, then at STARTPOS + 1, and so on.
+
+   STRING1 and STRING2 have length SIZE1 and SIZE2, respectively.
+
+   RANGE is how far to scan while trying to match.  RANGE = 0 means try
+   only at STARTPOS; in general, the last start tried is STARTPOS +
+   RANGE.
+
+   In REGS, return the indices of the virtual concatenation of STRING1
+   and STRING2 that matched the entire BUFP->buffer and its contained
+   subexpressions.
+
+   Do not consider matching one past the index STOP in the virtual
+   concatenation of STRING1 and STRING2.
+
+   We return either the position in the strings at which the match was
+   found, -1 if no match, or -2 if error (such as failure
+   stack overflow).  */
+
+int
+re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
+     struct re_pattern_buffer *bufp;
+     const char *string1, *string2;
+     int size1, size2;
+     int startpos;
+     int range;
+     struct re_registers *regs;
+     int stop;
+{
+  int val;
+  register char *fastmap = bufp->fastmap;
+  register RE_TRANSLATE_TYPE translate = bufp->translate;
+  int total_size = size1 + size2;
+  int endpos = startpos + range;
+
+  /* Check for out-of-range STARTPOS.  */
+  if (startpos < 0 || startpos > total_size)
+    return -1;
+
+  /* Fix up RANGE if it might eventually take us outside
+     the virtual concatenation of STRING1 and STRING2.
+     Make sure we won't move STARTPOS below 0 or above TOTAL_SIZE.  */
+  if (endpos < 0)
+    range = 0 - startpos;
+  else if (endpos > total_size)
+    range = total_size - startpos;
+
+  /* If the search isn't to be a backwards one, don't waste time in a
+     search for a pattern that must be anchored.  */
+  if (bufp->used > 0 && range > 0
+      && ((re_opcode_t) bufp->buffer[0] == begbuf
+	  /* `begline' is like `begbuf' if it cannot match at newlines.  */
+	  || ((re_opcode_t) bufp->buffer[0] == begline
+	      && !bufp->newline_anchor)))
+    {
+      if (startpos > 0)
+	return -1;
+      else
+	range = 1;
+    }
+
+#ifdef emacs
+  /* In a forward search for something that starts with \=.
+     don't keep searching past point.  */
+  if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == at_dot && range > 0)
+    {
+      range = PT - startpos;
+      if (range <= 0)
+	return -1;
+    }
+#endif /* emacs */
+
+  /* Update the fastmap now if not correct already.  */
+  if (fastmap && !bufp->fastmap_accurate)
+    if (re_compile_fastmap (bufp) == -2)
+      return -2;
+
+  /* Loop through the string, looking for a place to start matching.  */
+  for (;;)
+    {
+      /* If a fastmap is supplied, skip quickly over characters that
+         cannot be the start of a match.  If the pattern can match the
+         null string, however, we don't need to skip characters; we want
+         the first null string.  */
+      if (fastmap && startpos < total_size && !bufp->can_be_null)
+	{
+	  if (range > 0)	/* Searching forwards.  */
+	    {
+	      register const char *d;
+	      register int lim = 0;
+	      int irange = range;
+
+              if (startpos < size1 && startpos + range >= size1)
+                lim = range - (size1 - startpos);
+
+	      d = (startpos >= size1 ? string2 - size1 : string1) + startpos;
+
+              /* Written out as an if-else to avoid testing `translate'
+                 inside the loop.  */
+	      if (translate)
+                while (range > lim
+                       && !fastmap[(unsigned char)
+				   translate[(unsigned char) *d++]])
+                  range--;
+	      else
+                while (range > lim && !fastmap[(unsigned char) *d++])
+                  range--;
+
+	      startpos += irange - range;
+	    }
+	  else				/* Searching backwards.  */
+	    {
+	      register char c = (size1 == 0 || startpos >= size1
+                                 ? string2[startpos - size1]
+                                 : string1[startpos]);
+
+	      if (!fastmap[(unsigned char) TRANSLATE (c)])
+		goto advance;
+	    }
+	}
+
+      /* If can't match the null string, and that's all we have left, fail.  */
+      if (range >= 0 && startpos == total_size && fastmap
+          && !bufp->can_be_null)
+	return -1;
+
+      val = re_match_2_internal (bufp, string1, size1, string2, size2,
+				 startpos, regs, stop);
+#ifndef REGEX_MALLOC
+# ifdef C_ALLOCA
+      alloca (0);
+# endif
+#endif
+
+      if (val >= 0)
+	return startpos;
+
+      if (val == -2)
+	return -2;
+
+    advance:
+      if (!range)
+        break;
+      else if (range > 0)
+        {
+          range--;
+          startpos++;
+        }
+      else
+        {
+          range++;
+          startpos--;
+        }
+    }
+  return -1;
+} /* re_search_2 */
+#ifdef _LIBC
+weak_alias (__re_search_2, re_search_2)
+#endif
+
+/* This converts PTR, a pointer into one of the search strings `string1'
+   and `string2' into an offset from the beginning of that string.  */
+#define POINTER_TO_OFFSET(ptr)			\
+  (FIRST_STRING_P (ptr)				\
+   ? ((regoff_t) ((ptr) - string1))		\
+   : ((regoff_t) ((ptr) - string2 + size1)))
+
+/* Macros for dealing with the split strings in re_match_2.  */
+
+#define MATCHING_IN_FIRST_STRING  (dend == end_match_1)
+
+/* Call before fetching a character with *d.  This switches over to
+   string2 if necessary.  */
+#define PREFETCH()							\
+  while (d == dend)						    	\
+    {									\
+      /* End of string2 => fail.  */					\
+      if (dend == end_match_2) 						\
+        goto fail;							\
+      /* End of string1 => advance to string2.  */ 			\
+      d = string2;						        \
+      dend = end_match_2;						\
+    }
+
+
+/* Test if at very beginning or at very end of the virtual concatenation
+   of `string1' and `string2'.  If only one string, it's `string2'.  */
+#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2)
+#define AT_STRINGS_END(d) ((d) == end2)
+
+
+/* Test if D points to a character which is word-constituent.  We have
+   two special cases to check for: if past the end of string1, look at
+   the first character in string2; and if before the beginning of
+   string2, look at the last character in string1.  */
+#define WORDCHAR_P(d)							\
+  (SYNTAX ((d) == end1 ? *string2					\
+           : (d) == string2 - 1 ? *(end1 - 1) : *(d))			\
+   == Sword)
+
+/* Disabled due to a compiler bug -- see comment at case wordbound */
+#if 0
+/* Test if the character before D and the one at D differ with respect
+   to being word-constituent.  */
+#define AT_WORD_BOUNDARY(d)						\
+  (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)				\
+   || WORDCHAR_P (d - 1) != WORDCHAR_P (d))
+#endif
+
+/* Free everything we malloc.  */
+#ifdef MATCH_MAY_ALLOCATE
+# define FREE_VAR(var) if (var) REGEX_FREE (var); var = NULL
+# define FREE_VARIABLES()						\
+  do {									\
+    REGEX_FREE_STACK (fail_stack.stack);				\
+    FREE_VAR (regstart);						\
+    FREE_VAR (regend);							\
+    FREE_VAR (old_regstart);						\
+    FREE_VAR (old_regend);						\
+    FREE_VAR (best_regstart);						\
+    FREE_VAR (best_regend);						\
+    FREE_VAR (reg_info);						\
+    FREE_VAR (reg_dummy);						\
+    FREE_VAR (reg_info_dummy);						\
+  } while (0)
+#else
+# define FREE_VARIABLES() ((void)0) /* Do nothing!  But inhibit gcc warning. */
+#endif /* not MATCH_MAY_ALLOCATE */
+
+/* These values must meet several constraints.  They must not be valid
+   register values; since we have a limit of 255 registers (because
+   we use only one byte in the pattern for the register number), we can
+   use numbers larger than 255.  They must differ by 1, because of
+   NUM_FAILURE_ITEMS above.  And the value for the lowest register must
+   be larger than the value for the highest register, so we do not try
+   to actually save any registers when none are active.  */
+#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH)
+#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1)
+
+/* Matching routines.  */
+
+#ifndef emacs   /* Emacs never uses this.  */
+/* re_match is like re_match_2 except it takes only a single string.  */
+
+int
+re_match (bufp, string, size, pos, regs)
+     struct re_pattern_buffer *bufp;
+     const char *string;
+     int size, pos;
+     struct re_registers *regs;
+{
+  int result = re_match_2_internal (bufp, NULL, 0, string, size,
+				    pos, regs, size);
+# ifndef REGEX_MALLOC
+#  ifdef C_ALLOCA
+  alloca (0);
+#  endif
+# endif
+  return result;
+}
+# ifdef _LIBC
+weak_alias (__re_match, re_match)
+# endif
+#endif /* not emacs */
+
+static boolean group_match_null_string_p _RE_ARGS ((unsigned char **p,
+						    unsigned char *end,
+						register_info_type *reg_info));
+static boolean alt_match_null_string_p _RE_ARGS ((unsigned char *p,
+						  unsigned char *end,
+						register_info_type *reg_info));
+static boolean common_op_match_null_string_p _RE_ARGS ((unsigned char **p,
+							unsigned char *end,
+						register_info_type *reg_info));
+static int bcmp_translate _RE_ARGS ((const char *s1, const char *s2,
+				     int len, char *translate));
+
+/* re_match_2 matches the compiled pattern in BUFP against the
+   the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
+   and SIZE2, respectively).  We start matching at POS, and stop
+   matching at STOP.
+
+   If REGS is non-null and the `no_sub' field of BUFP is nonzero, we
+   store offsets for the substring each group matched in REGS.  See the
+   documentation for exactly how many groups we fill.
+
+   We return -1 if no match, -2 if an internal error (such as the
+   failure stack overflowing).  Otherwise, we return the length of the
+   matched substring.  */
+
+int
+re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
+     struct re_pattern_buffer *bufp;
+     const char *string1, *string2;
+     int size1, size2;
+     int pos;
+     struct re_registers *regs;
+     int stop;
+{
+  int result = re_match_2_internal (bufp, string1, size1, string2, size2,
+				    pos, regs, stop);
+#ifndef REGEX_MALLOC
+# ifdef C_ALLOCA
+  alloca (0);
+# endif
+#endif
+  return result;
+}
+#ifdef _LIBC
+weak_alias (__re_match_2, re_match_2)
+#endif
+
+/* This is a separate function so that we can force an alloca cleanup
+   afterwards.  */
+static int
+re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
+     struct re_pattern_buffer *bufp;
+     const char *string1, *string2;
+     int size1, size2;
+     int pos;
+     struct re_registers *regs;
+     int stop;
+{
+  /* General temporaries.  */
+  int mcnt;
+  unsigned char *p1;
+
+  /* Just past the end of the corresponding string.  */
+  const char *end1, *end2;
+
+  /* Pointers into string1 and string2, just past the last characters in
+     each to consider matching.  */
+  const char *end_match_1, *end_match_2;
+
+  /* Where we are in the data, and the end of the current string.  */
+  const char *d, *dend;
+
+  /* Where we are in the pattern, and the end of the pattern.  */
+  unsigned char *p = bufp->buffer;
+  register unsigned char *pend = p + bufp->used;
+
+  /* Mark the opcode just after a start_memory, so we can test for an
+     empty subpattern when we get to the stop_memory.  */
+  unsigned char *just_past_start_mem = 0;
+
+  /* We use this to map every character in the string.  */
+  RE_TRANSLATE_TYPE translate = bufp->translate;
+
+  /* Failure point stack.  Each place that can handle a failure further
+     down the line pushes a failure point on this stack.  It consists of
+     restart, regend, and reg_info for all registers corresponding to
+     the subexpressions we're currently inside, plus the number of such
+     registers, and, finally, two char *'s.  The first char * is where
+     to resume scanning the pattern; the second one is where to resume
+     scanning the strings.  If the latter is zero, the failure point is
+     a ``dummy''; if a failure happens and the failure point is a dummy,
+     it gets discarded and the next next one is tried.  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global.  */
+  fail_stack_type fail_stack;
+#endif
+#ifdef DEBUG
+  static unsigned failure_id;
+  unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0;
+#endif
+
+#ifdef REL_ALLOC
+  /* This holds the pointer to the failure stack, when
+     it is allocated relocatably.  */
+  fail_stack_elt_t *failure_stack_ptr;
+#endif
+
+  /* We fill all the registers internally, independent of what we
+     return, for use in backreferences.  The number here includes
+     an element for register zero.  */
+  size_t num_regs = bufp->re_nsub + 1;
+
+  /* The currently active registers.  */
+  active_reg_t lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+  active_reg_t highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+
+  /* Information on the contents of registers. These are pointers into
+     the input strings; they record just what was matched (on this
+     attempt) by a subexpression part of the pattern, that is, the
+     regnum-th regstart pointer points to where in the pattern we began
+     matching and the regnum-th regend points to right after where we
+     stopped matching the regnum-th subexpression.  (The zeroth register
+     keeps track of what the whole pattern matches.)  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
+  const char **regstart, **regend;
+#endif
+
+  /* If a group that's operated upon by a repetition operator fails to
+     match anything, then the register for its start will need to be
+     restored because it will have been set to wherever in the string we
+     are when we last see its open-group operator.  Similarly for a
+     register's end.  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
+  const char **old_regstart, **old_regend;
+#endif
+
+  /* The is_active field of reg_info helps us keep track of which (possibly
+     nested) subexpressions we are currently in. The matched_something
+     field of reg_info[reg_num] helps us tell whether or not we have
+     matched any of the pattern so far this time through the reg_num-th
+     subexpression.  These two fields get reset each time through any
+     loop their register is in.  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global.  */
+  register_info_type *reg_info;
+#endif
+
+  /* The following record the register info as found in the above
+     variables when we find a match better than any we've seen before.
+     This happens as we backtrack through the failure points, which in
+     turn happens only if we have not yet matched the entire string. */
+  unsigned best_regs_set = false;
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
+  const char **best_regstart, **best_regend;
+#endif
+
+  /* Logically, this is `best_regend[0]'.  But we don't want to have to
+     allocate space for that if we're not allocating space for anything
+     else (see below).  Also, we never need info about register 0 for
+     any of the other register vectors, and it seems rather a kludge to
+     treat `best_regend' differently than the rest.  So we keep track of
+     the end of the best match so far in a separate variable.  We
+     initialize this to NULL so that when we backtrack the first time
+     and need to test it, it's not garbage.  */
+  const char *match_end = NULL;
+
+  /* This helps SET_REGS_MATCHED avoid doing redundant work.  */
+  int set_regs_matched_done = 0;
+
+  /* Used when we pop values we don't care about.  */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global.  */
+  const char **reg_dummy;
+  register_info_type *reg_info_dummy;
+#endif
+
+#ifdef DEBUG
+  /* Counts the total number of registers pushed.  */
+  unsigned num_regs_pushed = 0;
+#endif
+
+  DEBUG_PRINT1 ("\n\nEntering re_match_2.\n");
+
+  INIT_FAIL_STACK ();
+
+#ifdef MATCH_MAY_ALLOCATE
+  /* Do not bother to initialize all the register variables if there are
+     no groups in the pattern, as it takes a fair amount of time.  If
+     there are groups, we include space for register 0 (the whole
+     pattern), even though we never use it, since it simplifies the
+     array indexing.  We should fix this.  */
+  if (bufp->re_nsub)
+    {
+      regstart = REGEX_TALLOC (num_regs, const char *);
+      regend = REGEX_TALLOC (num_regs, const char *);
+      old_regstart = REGEX_TALLOC (num_regs, const char *);
+      old_regend = REGEX_TALLOC (num_regs, const char *);
+      best_regstart = REGEX_TALLOC (num_regs, const char *);
+      best_regend = REGEX_TALLOC (num_regs, const char *);
+      reg_info = REGEX_TALLOC (num_regs, register_info_type);
+      reg_dummy = REGEX_TALLOC (num_regs, const char *);
+      reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type);
+
+      if (!(regstart && regend && old_regstart && old_regend && reg_info
+            && best_regstart && best_regend && reg_dummy && reg_info_dummy))
+        {
+          FREE_VARIABLES ();
+          return -2;
+        }
+    }
+  else
+    {
+      /* We must initialize all our variables to NULL, so that
+         `FREE_VARIABLES' doesn't try to free them.  */
+      regstart = regend = old_regstart = old_regend = best_regstart
+        = best_regend = reg_dummy = NULL;
+      reg_info = reg_info_dummy = (register_info_type *) NULL;
+    }
+#endif /* MATCH_MAY_ALLOCATE */
+
+  /* The starting position is bogus.  */
+  if (pos < 0 || pos > size1 + size2)
+    {
+      FREE_VARIABLES ();
+      return -1;
+    }
+
+  /* Initialize subexpression text positions to -1 to mark ones that no
+     start_memory/stop_memory has been seen for. Also initialize the
+     register information struct.  */
+  for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++)
+    {
+      regstart[mcnt] = regend[mcnt]
+        = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE;
+
+      REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE;
+      IS_ACTIVE (reg_info[mcnt]) = 0;
+      MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+      EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+    }
+
+  /* We move `string1' into `string2' if the latter's empty -- but not if
+     `string1' is null.  */
+  if (size2 == 0 && string1 != NULL)
+    {
+      string2 = string1;
+      size2 = size1;
+      string1 = 0;
+      size1 = 0;
+    }
+  end1 = string1 + size1;
+  end2 = string2 + size2;
+
+  /* Compute where to stop matching, within the two strings.  */
+  if (stop <= size1)
+    {
+      end_match_1 = string1 + stop;
+      end_match_2 = string2;
+    }
+  else
+    {
+      end_match_1 = end1;
+      end_match_2 = string2 + stop - size1;
+    }
+
+  /* `p' scans through the pattern as `d' scans through the data.
+     `dend' is the end of the input string that `d' points within.  `d'
+     is advanced into the following input string whenever necessary, but
+     this happens before fetching; therefore, at the beginning of the
+     loop, `d' can be pointing at the end of a string, but it cannot
+     equal `string2'.  */
+  if (size1 > 0 && pos <= size1)
+    {
+      d = string1 + pos;
+      dend = end_match_1;
+    }
+  else
+    {
+      d = string2 + pos - size1;
+      dend = end_match_2;
+    }
+
+  DEBUG_PRINT1 ("The compiled pattern is:\n");
+  DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend);
+  DEBUG_PRINT1 ("The string to match is: `");
+  DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2);
+  DEBUG_PRINT1 ("'\n");
+
+  /* This loops over pattern commands.  It exits by returning from the
+     function if the match is complete, or it drops through if the match
+     fails at this starting point in the input data.  */
+  for (;;)
+    {
+#ifdef _LIBC
+      DEBUG_PRINT2 ("\n%p: ", p);
+#else
+      DEBUG_PRINT2 ("\n0x%x: ", p);
+#endif
+
+      if (p == pend)
+	{ /* End of pattern means we might have succeeded.  */
+          DEBUG_PRINT1 ("end of pattern ... ");
+
+	  /* If we haven't matched the entire string, and we want the
+             longest match, try backtracking.  */
+          if (d != end_match_2)
+	    {
+	      /* 1 if this match ends in the same string (string1 or string2)
+		 as the best previous match.  */
+	      boolean same_str_p = (FIRST_STRING_P (match_end)
+				    == MATCHING_IN_FIRST_STRING);
+	      /* 1 if this match is the best seen so far.  */
+	      boolean best_match_p;
+
+	      /* AIX compiler got confused when this was combined
+		 with the previous declaration.  */
+	      if (same_str_p)
+		best_match_p = d > match_end;
+	      else
+		best_match_p = !MATCHING_IN_FIRST_STRING;
+
+              DEBUG_PRINT1 ("backtracking.\n");
+
+              if (!FAIL_STACK_EMPTY ())
+                { /* More failure points to try.  */
+
+                  /* If exceeds best match so far, save it.  */
+                  if (!best_regs_set || best_match_p)
+                    {
+                      best_regs_set = true;
+                      match_end = d;
+
+                      DEBUG_PRINT1 ("\nSAVING match as best so far.\n");
+
+                      for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++)
+                        {
+                          best_regstart[mcnt] = regstart[mcnt];
+                          best_regend[mcnt] = regend[mcnt];
+                        }
+                    }
+                  goto fail;
+                }
+
+              /* If no failure points, don't restore garbage.  And if
+                 last match is real best match, don't restore second
+                 best one. */
+              else if (best_regs_set && !best_match_p)
+                {
+  	        restore_best_regs:
+                  /* Restore best match.  It may happen that `dend ==
+                     end_match_1' while the restored d is in string2.
+                     For example, the pattern `x.*y.*z' against the
+                     strings `x-' and `y-z-', if the two strings are
+                     not consecutive in memory.  */
+                  DEBUG_PRINT1 ("Restoring best registers.\n");
+
+                  d = match_end;
+                  dend = ((d >= string1 && d <= end1)
+		           ? end_match_1 : end_match_2);
+
+		  for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++)
+		    {
+		      regstart[mcnt] = best_regstart[mcnt];
+		      regend[mcnt] = best_regend[mcnt];
+		    }
+                }
+            } /* d != end_match_2 */
+
+	succeed_label:
+          DEBUG_PRINT1 ("Accepting match.\n");
+
+          /* If caller wants register contents data back, do it.  */
+          if (regs && !bufp->no_sub)
+	    {
+              /* Have the register data arrays been allocated?  */
+              if (bufp->regs_allocated == REGS_UNALLOCATED)
+                { /* No.  So allocate them with malloc.  We need one
+                     extra element beyond `num_regs' for the `-1' marker
+                     GNU code uses.  */
+                  regs->num_regs = MAX (RE_NREGS, num_regs + 1);
+                  regs->start = TALLOC (regs->num_regs, regoff_t);
+                  regs->end = TALLOC (regs->num_regs, regoff_t);
+                  if (regs->start == NULL || regs->end == NULL)
+		    {
+		      FREE_VARIABLES ();
+		      return -2;
+		    }
+                  bufp->regs_allocated = REGS_REALLOCATE;
+                }
+              else if (bufp->regs_allocated == REGS_REALLOCATE)
+                { /* Yes.  If we need more elements than were already
+                     allocated, reallocate them.  If we need fewer, just
+                     leave it alone.  */
+                  if (regs->num_regs < num_regs + 1)
+                    {
+                      regs->num_regs = num_regs + 1;
+                      RETALLOC (regs->start, regs->num_regs, regoff_t);
+                      RETALLOC (regs->end, regs->num_regs, regoff_t);
+                      if (regs->start == NULL || regs->end == NULL)
+			{
+			  FREE_VARIABLES ();
+			  return -2;
+			}
+                    }
+                }
+              else
+		{
+		  /* These braces fend off a "empty body in an else-statement"
+		     warning under GCC when assert expands to nothing.  */
+		  assert (bufp->regs_allocated == REGS_FIXED);
+		}
+
+              /* Convert the pointer data in `regstart' and `regend' to
+                 indices.  Register zero has to be set differently,
+                 since we haven't kept track of any info for it.  */
+              if (regs->num_regs > 0)
+                {
+                  regs->start[0] = pos;
+                  regs->end[0] = (MATCHING_IN_FIRST_STRING
+				  ? ((regoff_t) (d - string1))
+			          : ((regoff_t) (d - string2 + size1)));
+                }
+
+              /* Go through the first `min (num_regs, regs->num_regs)'
+                 registers, since that is all we initialized.  */
+	      for (mcnt = 1; (unsigned) mcnt < MIN (num_regs, regs->num_regs);
+		   mcnt++)
+		{
+                  if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt]))
+                    regs->start[mcnt] = regs->end[mcnt] = -1;
+                  else
+                    {
+		      regs->start[mcnt]
+			= (regoff_t) POINTER_TO_OFFSET (regstart[mcnt]);
+                      regs->end[mcnt]
+			= (regoff_t) POINTER_TO_OFFSET (regend[mcnt]);
+                    }
+		}
+
+              /* If the regs structure we return has more elements than
+                 were in the pattern, set the extra elements to -1.  If
+                 we (re)allocated the registers, this is the case,
+                 because we always allocate enough to have at least one
+                 -1 at the end.  */
+              for (mcnt = num_regs; (unsigned) mcnt < regs->num_regs; mcnt++)
+                regs->start[mcnt] = regs->end[mcnt] = -1;
+	    } /* regs && !bufp->no_sub */
+
+          DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n",
+                        nfailure_points_pushed, nfailure_points_popped,
+                        nfailure_points_pushed - nfailure_points_popped);
+          DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed);
+
+          mcnt = d - pos - (MATCHING_IN_FIRST_STRING
+			    ? string1
+			    : string2 - size1);
+
+          DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
+
+          FREE_VARIABLES ();
+          return mcnt;
+        }
+
+      /* Otherwise match next pattern command.  */
+      switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++))
+	{
+        /* Ignore these.  Used to ignore the n of succeed_n's which
+           currently have n == 0.  */
+        case no_op:
+          DEBUG_PRINT1 ("EXECUTING no_op.\n");
+          break;
+
+	case succeed:
+          DEBUG_PRINT1 ("EXECUTING succeed.\n");
+	  goto succeed_label;
+
+        /* Match the next n pattern characters exactly.  The following
+           byte in the pattern defines n, and the n bytes after that
+           are the characters to match.  */
+	case exactn:
+	  mcnt = *p++;
+          DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt);
+
+          /* This is written out as an if-else so we don't waste time
+             testing `translate' inside the loop.  */
+          if (translate)
+	    {
+	      do
+		{
+		  PREFETCH ();
+		  if ((unsigned char) translate[(unsigned char) *d++]
+		      != (unsigned char) *p++)
+                    goto fail;
+		}
+	      while (--mcnt);
+	    }
+	  else
+	    {
+	      do
+		{
+		  PREFETCH ();
+		  if (*d++ != (char) *p++) goto fail;
+		}
+	      while (--mcnt);
+	    }
+	  SET_REGS_MATCHED ();
+          break;
+
+
+        /* Match any character except possibly a newline or a null.  */
+	case anychar:
+          DEBUG_PRINT1 ("EXECUTING anychar.\n");
+
+          PREFETCH ();
+
+          if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n')
+              || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000'))
+	    goto fail;
+
+          SET_REGS_MATCHED ();
+          DEBUG_PRINT2 ("  Matched `%d'.\n", *d);
+          d++;
+	  break;
+
+
+	case charset:
+	case charset_not:
+	  {
+	    register unsigned char c;
+	    boolean not = (re_opcode_t) *(p - 1) == charset_not;
+
+            DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : "");
+
+	    PREFETCH ();
+	    c = TRANSLATE (*d); /* The character to match.  */
+
+            /* Cast to `unsigned' instead of `unsigned char' in case the
+               bit list is a full 32 bytes long.  */
+	    if (c < (unsigned) (*p * BYTEWIDTH)
+		&& p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+	      not = !not;
+
+	    p += 1 + *p;
+
+	    if (!not) goto fail;
+
+	    SET_REGS_MATCHED ();
+            d++;
+	    break;
+	  }
+
+
+        /* The beginning of a group is represented by start_memory.
+           The arguments are the register number in the next byte, and the
+           number of groups inner to this one in the next.  The text
+           matched within the group is recorded (in the internal
+           registers data structure) under the register number.  */
+        case start_memory:
+	  DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]);
+
+          /* Find out if this group can match the empty string.  */
+	  p1 = p;		/* To send to group_match_null_string_p.  */
+
+          if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE)
+            REG_MATCH_NULL_STRING_P (reg_info[*p])
+              = group_match_null_string_p (&p1, pend, reg_info);
+
+          /* Save the position in the string where we were the last time
+             we were at this open-group operator in case the group is
+             operated upon by a repetition operator, e.g., with `(a*)*b'
+             against `ab'; then we want to ignore where we are now in
+             the string in case this attempt to match fails.  */
+          old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
+                             ? REG_UNSET (regstart[*p]) ? d : regstart[*p]
+                             : regstart[*p];
+	  DEBUG_PRINT2 ("  old_regstart: %d\n",
+			 POINTER_TO_OFFSET (old_regstart[*p]));
+
+          regstart[*p] = d;
+	  DEBUG_PRINT2 ("  regstart: %d\n", POINTER_TO_OFFSET (regstart[*p]));
+
+          IS_ACTIVE (reg_info[*p]) = 1;
+          MATCHED_SOMETHING (reg_info[*p]) = 0;
+
+	  /* Clear this whenever we change the register activity status.  */
+	  set_regs_matched_done = 0;
+
+          /* This is the new highest active register.  */
+          highest_active_reg = *p;
+
+          /* If nothing was active before, this is the new lowest active
+             register.  */
+          if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+            lowest_active_reg = *p;
+
+          /* Move past the register number and inner group count.  */
+          p += 2;
+	  just_past_start_mem = p;
+
+          break;
+
+
+        /* The stop_memory opcode represents the end of a group.  Its
+           arguments are the same as start_memory's: the register
+           number, and the number of inner groups.  */
+	case stop_memory:
+	  DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]);
+
+          /* We need to save the string position the last time we were at
+             this close-group operator in case the group is operated
+             upon by a repetition operator, e.g., with `((a*)*(b*)*)*'
+             against `aba'; then we want to ignore where we are now in
+             the string in case this attempt to match fails.  */
+          old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
+                           ? REG_UNSET (regend[*p]) ? d : regend[*p]
+			   : regend[*p];
+	  DEBUG_PRINT2 ("      old_regend: %d\n",
+			 POINTER_TO_OFFSET (old_regend[*p]));
+
+          regend[*p] = d;
+	  DEBUG_PRINT2 ("      regend: %d\n", POINTER_TO_OFFSET (regend[*p]));
+
+          /* This register isn't active anymore.  */
+          IS_ACTIVE (reg_info[*p]) = 0;
+
+	  /* Clear this whenever we change the register activity status.  */
+	  set_regs_matched_done = 0;
+
+          /* If this was the only register active, nothing is active
+             anymore.  */
+          if (lowest_active_reg == highest_active_reg)
+            {
+              lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+              highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+            }
+          else
+            { /* We must scan for the new highest active register, since
+                 it isn't necessarily one less than now: consider
+                 (a(b)c(d(e)f)g).  When group 3 ends, after the f), the
+                 new highest active register is 1.  */
+              unsigned char r = *p - 1;
+              while (r > 0 && !IS_ACTIVE (reg_info[r]))
+                r--;
+
+              /* If we end up at register zero, that means that we saved
+                 the registers as the result of an `on_failure_jump', not
+                 a `start_memory', and we jumped to past the innermost
+                 `stop_memory'.  For example, in ((.)*) we save
+                 registers 1 and 2 as a result of the *, but when we pop
+                 back to the second ), we are at the stop_memory 1.
+                 Thus, nothing is active.  */
+	      if (r == 0)
+                {
+                  lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+                  highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+                }
+              else
+                highest_active_reg = r;
+            }
+
+          /* If just failed to match something this time around with a
+             group that's operated on by a repetition operator, try to
+             force exit from the ``loop'', and restore the register
+             information for this group that we had before trying this
+             last match.  */
+          if ((!MATCHED_SOMETHING (reg_info[*p])
+               || just_past_start_mem == p - 1)
+	      && (p + 2) < pend)
+            {
+              boolean is_a_jump_n = false;
+
+              p1 = p + 2;
+              mcnt = 0;
+              switch ((re_opcode_t) *p1++)
+                {
+                  case jump_n:
+		    is_a_jump_n = true;
+                  case pop_failure_jump:
+		  case maybe_pop_jump:
+		  case jump:
+		  case dummy_failure_jump:
+                    EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+		    if (is_a_jump_n)
+		      p1 += 2;
+                    break;
+
+                  default:
+                    /* do nothing */ ;
+                }
+	      p1 += mcnt;
+
+              /* If the next operation is a jump backwards in the pattern
+	         to an on_failure_jump right before the start_memory
+                 corresponding to this stop_memory, exit from the loop
+                 by forcing a failure after pushing on the stack the
+                 on_failure_jump's jump in the pattern, and d.  */
+              if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump
+                  && (re_opcode_t) p1[3] == start_memory && p1[4] == *p)
+		{
+                  /* If this group ever matched anything, then restore
+                     what its registers were before trying this last
+                     failed match, e.g., with `(a*)*b' against `ab' for
+                     regstart[1], and, e.g., with `((a*)*(b*)*)*'
+                     against `aba' for regend[3].
+
+                     Also restore the registers for inner groups for,
+                     e.g., `((a*)(b*))*' against `aba' (register 3 would
+                     otherwise get trashed).  */
+
+                  if (EVER_MATCHED_SOMETHING (reg_info[*p]))
+		    {
+		      unsigned r;
+
+                      EVER_MATCHED_SOMETHING (reg_info[*p]) = 0;
+
+		      /* Restore this and inner groups' (if any) registers.  */
+                      for (r = *p; r < (unsigned) *p + (unsigned) *(p + 1);
+			   r++)
+                        {
+                          regstart[r] = old_regstart[r];
+
+                          /* xx why this test?  */
+                          if (old_regend[r] >= regstart[r])
+                            regend[r] = old_regend[r];
+                        }
+                    }
+		  p1++;
+                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+                  PUSH_FAILURE_POINT (p1 + mcnt, d, -2);
+
+                  goto fail;
+                }
+            }
+
+          /* Move past the register number and the inner group count.  */
+          p += 2;
+          break;
+
+
+	/* \<digit> has been turned into a `duplicate' command which is
+           followed by the numeric value of <digit> as the register number.  */
+        case duplicate:
+	  {
+	    register const char *d2, *dend2;
+	    int regno = *p++;   /* Get which register to match against.  */
+	    DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
+
+	    /* Can't back reference a group which we've never matched.  */
+            if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno]))
+              goto fail;
+
+            /* Where in input to try to start matching.  */
+            d2 = regstart[regno];
+
+            /* Where to stop matching; if both the place to start and
+               the place to stop matching are in the same string, then
+               set to the place to stop, otherwise, for now have to use
+               the end of the first string.  */
+
+            dend2 = ((FIRST_STRING_P (regstart[regno])
+		      == FIRST_STRING_P (regend[regno]))
+		     ? regend[regno] : end_match_1);
+	    for (;;)
+	      {
+		/* If necessary, advance to next segment in register
+                   contents.  */
+		while (d2 == dend2)
+		  {
+		    if (dend2 == end_match_2) break;
+		    if (dend2 == regend[regno]) break;
+
+                    /* End of string1 => advance to string2. */
+                    d2 = string2;
+                    dend2 = regend[regno];
+		  }
+		/* At end of register contents => success */
+		if (d2 == dend2) break;
+
+		/* If necessary, advance to next segment in data.  */
+		PREFETCH ();
+
+		/* How many characters left in this segment to match.  */
+		mcnt = dend - d;
+
+		/* Want how many consecutive characters we can match in
+                   one shot, so, if necessary, adjust the count.  */
+                if (mcnt > dend2 - d2)
+		  mcnt = dend2 - d2;
+
+		/* Compare that many; failure if mismatch, else move
+                   past them.  */
+		if (translate
+                    ? bcmp_translate (d, d2, mcnt, translate)
+                    : memcmp (d, d2, mcnt))
+		  goto fail;
+		d += mcnt, d2 += mcnt;
+
+		/* Do this because we've match some characters.  */
+		SET_REGS_MATCHED ();
+	      }
+	  }
+	  break;
+
+
+        /* begline matches the empty string at the beginning of the string
+           (unless `not_bol' is set in `bufp'), and, if
+           `newline_anchor' is set, after newlines.  */
+	case begline:
+          DEBUG_PRINT1 ("EXECUTING begline.\n");
+
+          if (AT_STRINGS_BEG (d))
+            {
+              if (!bufp->not_bol) break;
+            }
+          else if (d[-1] == '\n' && bufp->newline_anchor)
+            {
+              break;
+            }
+          /* In all other cases, we fail.  */
+          goto fail;
+
+
+        /* endline is the dual of begline.  */
+	case endline:
+          DEBUG_PRINT1 ("EXECUTING endline.\n");
+
+          if (AT_STRINGS_END (d))
+            {
+              if (!bufp->not_eol) break;
+            }
+
+          /* We have to ``prefetch'' the next character.  */
+          else if ((d == end1 ? *string2 : *d) == '\n'
+                   && bufp->newline_anchor)
+            {
+              break;
+            }
+          goto fail;
+
+
+	/* Match at the very beginning of the data.  */
+        case begbuf:
+          DEBUG_PRINT1 ("EXECUTING begbuf.\n");
+          if (AT_STRINGS_BEG (d))
+            break;
+          goto fail;
+
+
+	/* Match at the very end of the data.  */
+        case endbuf:
+          DEBUG_PRINT1 ("EXECUTING endbuf.\n");
+	  if (AT_STRINGS_END (d))
+	    break;
+          goto fail;
+
+
+        /* on_failure_keep_string_jump is used to optimize `.*\n'.  It
+           pushes NULL as the value for the string on the stack.  Then
+           `pop_failure_point' will keep the current value for the
+           string, instead of restoring it.  To see why, consider
+           matching `foo\nbar' against `.*\n'.  The .* matches the foo;
+           then the . fails against the \n.  But the next thing we want
+           to do is match the \n against the \n; if we restored the
+           string value, we would be back at the foo.
+
+           Because this is used only in specific cases, we don't need to
+           check all the things that `on_failure_jump' does, to make
+           sure the right things get saved on the stack.  Hence we don't
+           share its code.  The only reason to push anything on the
+           stack at all is that otherwise we would have to change
+           `anychar's code to do something besides goto fail in this
+           case; that seems worse than this.  */
+        case on_failure_keep_string_jump:
+          DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump");
+
+          EXTRACT_NUMBER_AND_INCR (mcnt, p);
+#ifdef _LIBC
+          DEBUG_PRINT3 (" %d (to %p):\n", mcnt, p + mcnt);
+#else
+          DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt);
+#endif
+
+          PUSH_FAILURE_POINT (p + mcnt, NULL, -2);
+          break;
+
+
+	/* Uses of on_failure_jump:
+
+           Each alternative starts with an on_failure_jump that points
+           to the beginning of the next alternative.  Each alternative
+           except the last ends with a jump that in effect jumps past
+           the rest of the alternatives.  (They really jump to the
+           ending jump of the following alternative, because tensioning
+           these jumps is a hassle.)
+
+           Repeats start with an on_failure_jump that points past both
+           the repetition text and either the following jump or
+           pop_failure_jump back to this on_failure_jump.  */
+	case on_failure_jump:
+        on_failure:
+          DEBUG_PRINT1 ("EXECUTING on_failure_jump");
+
+          EXTRACT_NUMBER_AND_INCR (mcnt, p);
+#ifdef _LIBC
+          DEBUG_PRINT3 (" %d (to %p)", mcnt, p + mcnt);
+#else
+          DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt);
+#endif
+
+          /* If this on_failure_jump comes right before a group (i.e.,
+             the original * applied to a group), save the information
+             for that group and all inner ones, so that if we fail back
+             to this point, the group's information will be correct.
+             For example, in \(a*\)*\1, we need the preceding group,
+             and in \(zz\(a*\)b*\)\2, we need the inner group.  */
+
+          /* We can't use `p' to check ahead because we push
+             a failure point to `p + mcnt' after we do this.  */
+          p1 = p;
+
+          /* We need to skip no_op's before we look for the
+             start_memory in case this on_failure_jump is happening as
+             the result of a completed succeed_n, as in \(a\)\{1,3\}b\1
+             against aba.  */
+          while (p1 < pend && (re_opcode_t) *p1 == no_op)
+            p1++;
+
+          if (p1 < pend && (re_opcode_t) *p1 == start_memory)
+            {
+              /* We have a new highest active register now.  This will
+                 get reset at the start_memory we are about to get to,
+                 but we will have saved all the registers relevant to
+                 this repetition op, as described above.  */
+              highest_active_reg = *(p1 + 1) + *(p1 + 2);
+              if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+                lowest_active_reg = *(p1 + 1);
+            }
+
+          DEBUG_PRINT1 (":\n");
+          PUSH_FAILURE_POINT (p + mcnt, d, -2);
+          break;
+
+
+        /* A smart repeat ends with `maybe_pop_jump'.
+	   We change it to either `pop_failure_jump' or `jump'.  */
+        case maybe_pop_jump:
+          EXTRACT_NUMBER_AND_INCR (mcnt, p);
+          DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt);
+          {
+	    register unsigned char *p2 = p;
+
+            /* Compare the beginning of the repeat with what in the
+               pattern follows its end. If we can establish that there
+               is nothing that they would both match, i.e., that we
+               would have to backtrack because of (as in, e.g., `a*a')
+               then we can change to pop_failure_jump, because we'll
+               never have to backtrack.
+
+               This is not true in the case of alternatives: in
+               `(a|ab)*' we do need to backtrack to the `ab' alternative
+               (e.g., if the string was `ab').  But instead of trying to
+               detect that here, the alternative has put on a dummy
+               failure point which is what we will end up popping.  */
+
+	    /* Skip over open/close-group commands.
+	       If what follows this loop is a ...+ construct,
+	       look at what begins its body, since we will have to
+	       match at least one of that.  */
+	    while (1)
+	      {
+		if (p2 + 2 < pend
+		    && ((re_opcode_t) *p2 == stop_memory
+			|| (re_opcode_t) *p2 == start_memory))
+		  p2 += 3;
+		else if (p2 + 6 < pend
+			 && (re_opcode_t) *p2 == dummy_failure_jump)
+		  p2 += 6;
+		else
+		  break;
+	      }
+
+	    p1 = p + mcnt;
+	    /* p1[0] ... p1[2] are the `on_failure_jump' corresponding
+	       to the `maybe_finalize_jump' of this case.  Examine what
+	       follows.  */
+
+            /* If we're at the end of the pattern, we can change.  */
+            if (p2 == pend)
+	      {
+		/* Consider what happens when matching ":\(.*\)"
+		   against ":/".  I don't really understand this code
+		   yet.  */
+  	        p[-3] = (unsigned char) pop_failure_jump;
+                DEBUG_PRINT1
+                  ("  End of pattern: change to `pop_failure_jump'.\n");
+              }
+
+            else if ((re_opcode_t) *p2 == exactn
+		     || (bufp->newline_anchor && (re_opcode_t) *p2 == endline))
+	      {
+		register unsigned char c
+                  = *p2 == (unsigned char) endline ? '\n' : p2[2];
+
+                if ((re_opcode_t) p1[3] == exactn && p1[5] != c)
+                  {
+  		    p[-3] = (unsigned char) pop_failure_jump;
+                    DEBUG_PRINT3 ("  %c != %c => pop_failure_jump.\n",
+                                  c, p1[5]);
+                  }
+
+		else if ((re_opcode_t) p1[3] == charset
+			 || (re_opcode_t) p1[3] == charset_not)
+		  {
+		    int not = (re_opcode_t) p1[3] == charset_not;
+
+		    if (c < (unsigned char) (p1[4] * BYTEWIDTH)
+			&& p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+		      not = !not;
+
+                    /* `not' is equal to 1 if c would match, which means
+                        that we can't change to pop_failure_jump.  */
+		    if (!not)
+                      {
+  		        p[-3] = (unsigned char) pop_failure_jump;
+                        DEBUG_PRINT1 ("  No match => pop_failure_jump.\n");
+                      }
+		  }
+	      }
+            else if ((re_opcode_t) *p2 == charset)
+	      {
+#ifdef DEBUG
+		register unsigned char c
+                  = *p2 == (unsigned char) endline ? '\n' : p2[2];
+#endif
+
+#if 0
+                if ((re_opcode_t) p1[3] == exactn
+		    && ! ((int) p2[1] * BYTEWIDTH > (int) p1[5]
+			  && (p2[2 + p1[5] / BYTEWIDTH]
+			      & (1 << (p1[5] % BYTEWIDTH)))))
+#else
+                if ((re_opcode_t) p1[3] == exactn
+		    && ! ((int) p2[1] * BYTEWIDTH > (int) p1[4]
+			  && (p2[2 + p1[4] / BYTEWIDTH]
+			      & (1 << (p1[4] % BYTEWIDTH)))))
+#endif
+                  {
+  		    p[-3] = (unsigned char) pop_failure_jump;
+                    DEBUG_PRINT3 ("  %c != %c => pop_failure_jump.\n",
+                                  c, p1[5]);
+                  }
+
+		else if ((re_opcode_t) p1[3] == charset_not)
+		  {
+		    int idx;
+		    /* We win if the charset_not inside the loop
+		       lists every character listed in the charset after.  */
+		    for (idx = 0; idx < (int) p2[1]; idx++)
+		      if (! (p2[2 + idx] == 0
+			     || (idx < (int) p1[4]
+				 && ((p2[2 + idx] & ~ p1[5 + idx]) == 0))))
+			break;
+
+		    if (idx == p2[1])
+                      {
+  		        p[-3] = (unsigned char) pop_failure_jump;
+                        DEBUG_PRINT1 ("  No match => pop_failure_jump.\n");
+                      }
+		  }
+		else if ((re_opcode_t) p1[3] == charset)
+		  {
+		    int idx;
+		    /* We win if the charset inside the loop
+		       has no overlap with the one after the loop.  */
+		    for (idx = 0;
+			 idx < (int) p2[1] && idx < (int) p1[4];
+			 idx++)
+		      if ((p2[2 + idx] & p1[5 + idx]) != 0)
+			break;
+
+		    if (idx == p2[1] || idx == p1[4])
+                      {
+  		        p[-3] = (unsigned char) pop_failure_jump;
+                        DEBUG_PRINT1 ("  No match => pop_failure_jump.\n");
+                      }
+		  }
+	      }
+	  }
+	  p -= 2;		/* Point at relative address again.  */
+	  if ((re_opcode_t) p[-1] != pop_failure_jump)
+	    {
+	      p[-1] = (unsigned char) jump;
+              DEBUG_PRINT1 ("  Match => jump.\n");
+	      goto unconditional_jump;
+	    }
+        /* Note fall through.  */
+
+
+	/* The end of a simple repeat has a pop_failure_jump back to
+           its matching on_failure_jump, where the latter will push a
+           failure point.  The pop_failure_jump takes off failure
+           points put on by this pop_failure_jump's matching
+           on_failure_jump; we got through the pattern to here from the
+           matching on_failure_jump, so didn't fail.  */
+        case pop_failure_jump:
+          {
+            /* We need to pass separate storage for the lowest and
+               highest registers, even though we don't care about the
+               actual values.  Otherwise, we will restore only one
+               register from the stack, since lowest will == highest in
+               `pop_failure_point'.  */
+            active_reg_t dummy_low_reg, dummy_high_reg;
+            unsigned char *pdummy;
+            const char *sdummy;
+
+            DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n");
+            POP_FAILURE_POINT (sdummy, pdummy,
+                               dummy_low_reg, dummy_high_reg,
+                               reg_dummy, reg_dummy, reg_info_dummy);
+          }
+	  /* Note fall through.  */
+
+	unconditional_jump:
+#ifdef _LIBC
+	  DEBUG_PRINT2 ("\n%p: ", p);
+#else
+	  DEBUG_PRINT2 ("\n0x%x: ", p);
+#endif
+          /* Note fall through.  */
+
+        /* Unconditionally jump (without popping any failure points).  */
+        case jump:
+	  EXTRACT_NUMBER_AND_INCR (mcnt, p);	/* Get the amount to jump.  */
+          DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt);
+	  p += mcnt;				/* Do the jump.  */
+#ifdef _LIBC
+          DEBUG_PRINT2 ("(to %p).\n", p);
+#else
+          DEBUG_PRINT2 ("(to 0x%x).\n", p);
+#endif
+	  break;
+
+
+        /* We need this opcode so we can detect where alternatives end
+           in `group_match_null_string_p' et al.  */
+        case jump_past_alt:
+          DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n");
+          goto unconditional_jump;
+
+
+        /* Normally, the on_failure_jump pushes a failure point, which
+           then gets popped at pop_failure_jump.  We will end up at
+           pop_failure_jump, also, and with a pattern of, say, `a+', we
+           are skipping over the on_failure_jump, so we have to push
+           something meaningless for pop_failure_jump to pop.  */
+        case dummy_failure_jump:
+          DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n");
+          /* It doesn't matter what we push for the string here.  What
+             the code at `fail' tests is the value for the pattern.  */
+          PUSH_FAILURE_POINT (NULL, NULL, -2);
+          goto unconditional_jump;
+
+
+        /* At the end of an alternative, we need to push a dummy failure
+           point in case we are followed by a `pop_failure_jump', because
+           we don't want the failure point for the alternative to be
+           popped.  For example, matching `(a|ab)*' against `aab'
+           requires that we match the `ab' alternative.  */
+        case push_dummy_failure:
+          DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n");
+          /* See comments just above at `dummy_failure_jump' about the
+             two zeroes.  */
+          PUSH_FAILURE_POINT (NULL, NULL, -2);
+          break;
+
+        /* Have to succeed matching what follows at least n times.
+           After that, handle like `on_failure_jump'.  */
+        case succeed_n:
+          EXTRACT_NUMBER (mcnt, p + 2);
+          DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt);
+
+          assert (mcnt >= 0);
+          /* Originally, this is how many times we HAVE to succeed.  */
+          if (mcnt > 0)
+            {
+               mcnt--;
+	       p += 2;
+               STORE_NUMBER_AND_INCR (p, mcnt);
+#ifdef _LIBC
+               DEBUG_PRINT3 ("  Setting %p to %d.\n", p - 2, mcnt);
+#else
+               DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p - 2, mcnt);
+#endif
+            }
+	  else if (mcnt == 0)
+            {
+#ifdef _LIBC
+              DEBUG_PRINT2 ("  Setting two bytes from %p to no_op.\n", p+2);
+#else
+              DEBUG_PRINT2 ("  Setting two bytes from 0x%x to no_op.\n", p+2);
+#endif
+	      p[2] = (unsigned char) no_op;
+              p[3] = (unsigned char) no_op;
+              goto on_failure;
+            }
+          break;
+
+        case jump_n:
+          EXTRACT_NUMBER (mcnt, p + 2);
+          DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt);
+
+          /* Originally, this is how many times we CAN jump.  */
+          if (mcnt)
+            {
+               mcnt--;
+               STORE_NUMBER (p + 2, mcnt);
+#ifdef _LIBC
+               DEBUG_PRINT3 ("  Setting %p to %d.\n", p + 2, mcnt);
+#else
+               DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p + 2, mcnt);
+#endif
+	       goto unconditional_jump;
+            }
+          /* If don't have to jump any more, skip over the rest of command.  */
+	  else
+	    p += 4;
+          break;
+
+	case set_number_at:
+	  {
+            DEBUG_PRINT1 ("EXECUTING set_number_at.\n");
+
+            EXTRACT_NUMBER_AND_INCR (mcnt, p);
+            p1 = p + mcnt;
+            EXTRACT_NUMBER_AND_INCR (mcnt, p);
+#ifdef _LIBC
+            DEBUG_PRINT3 ("  Setting %p to %d.\n", p1, mcnt);
+#else
+            DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p1, mcnt);
+#endif
+	    STORE_NUMBER (p1, mcnt);
+            break;
+          }
+
+#if 0
+	/* The DEC Alpha C compiler 3.x generates incorrect code for the
+	   test  WORDCHAR_P (d - 1) != WORDCHAR_P (d)  in the expansion of
+	   AT_WORD_BOUNDARY, so this code is disabled.  Expanding the
+	   macro and introducing temporary variables works around the bug.  */
+
+	case wordbound:
+	  DEBUG_PRINT1 ("EXECUTING wordbound.\n");
+	  if (AT_WORD_BOUNDARY (d))
+	    break;
+	  goto fail;
+
+	case notwordbound:
+	  DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
+	  if (AT_WORD_BOUNDARY (d))
+	    goto fail;
+	  break;
+#else
+	case wordbound:
+	{
+	  boolean prevchar, thischar;
+
+	  DEBUG_PRINT1 ("EXECUTING wordbound.\n");
+	  if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d))
+	    break;
+
+	  prevchar = WORDCHAR_P (d - 1);
+	  thischar = WORDCHAR_P (d);
+	  if (prevchar != thischar)
+	    break;
+	  goto fail;
+	}
+
+      case notwordbound:
+	{
+	  boolean prevchar, thischar;
+
+	  DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
+	  if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d))
+	    goto fail;
+
+	  prevchar = WORDCHAR_P (d - 1);
+	  thischar = WORDCHAR_P (d);
+	  if (prevchar != thischar)
+	    goto fail;
+	  break;
+	}
+#endif
+
+	case wordbeg:
+          DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
+	  if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1)))
+	    break;
+          goto fail;
+
+	case wordend:
+          DEBUG_PRINT1 ("EXECUTING wordend.\n");
+	  if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1)
+              && (!WORDCHAR_P (d) || AT_STRINGS_END (d)))
+	    break;
+          goto fail;
+
+#ifdef emacs
+  	case before_dot:
+          DEBUG_PRINT1 ("EXECUTING before_dot.\n");
+ 	  if (PTR_CHAR_POS ((unsigned char *) d) >= point)
+  	    goto fail;
+  	  break;
+
+  	case at_dot:
+          DEBUG_PRINT1 ("EXECUTING at_dot.\n");
+ 	  if (PTR_CHAR_POS ((unsigned char *) d) != point)
+  	    goto fail;
+  	  break;
+
+  	case after_dot:
+          DEBUG_PRINT1 ("EXECUTING after_dot.\n");
+          if (PTR_CHAR_POS ((unsigned char *) d) <= point)
+  	    goto fail;
+  	  break;
+
+	case syntaxspec:
+          DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
+	  mcnt = *p++;
+	  goto matchsyntax;
+
+        case wordchar:
+          DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n");
+	  mcnt = (int) Sword;
+        matchsyntax:
+	  PREFETCH ();
+	  /* Can't use *d++ here; SYNTAX may be an unsafe macro.  */
+	  d++;
+	  if (SYNTAX (d[-1]) != (enum syntaxcode) mcnt)
+	    goto fail;
+          SET_REGS_MATCHED ();
+	  break;
+
+	case notsyntaxspec:
+          DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt);
+	  mcnt = *p++;
+	  goto matchnotsyntax;
+
+        case notwordchar:
+          DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n");
+	  mcnt = (int) Sword;
+        matchnotsyntax:
+	  PREFETCH ();
+	  /* Can't use *d++ here; SYNTAX may be an unsafe macro.  */
+	  d++;
+	  if (SYNTAX (d[-1]) == (enum syntaxcode) mcnt)
+	    goto fail;
+	  SET_REGS_MATCHED ();
+          break;
+
+#else /* not emacs */
+	case wordchar:
+          DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n");
+	  PREFETCH ();
+          if (!WORDCHAR_P (d))
+            goto fail;
+	  SET_REGS_MATCHED ();
+          d++;
+	  break;
+
+	case notwordchar:
+          DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
+	  PREFETCH ();
+	  if (WORDCHAR_P (d))
+            goto fail;
+          SET_REGS_MATCHED ();
+          d++;
+	  break;
+#endif /* not emacs */
+
+        default:
+          abort ();
+	}
+      continue;  /* Successfully executed one pattern command; keep going.  */
+
+
+    /* We goto here if a matching operation fails. */
+    fail:
+      if (!FAIL_STACK_EMPTY ())
+	{ /* A restart point is known.  Restore to that state.  */
+          DEBUG_PRINT1 ("\nFAIL:\n");
+          POP_FAILURE_POINT (d, p,
+                             lowest_active_reg, highest_active_reg,
+                             regstart, regend, reg_info);
+
+          /* If this failure point is a dummy, try the next one.  */
+          if (!p)
+	    goto fail;
+
+          /* If we failed to the end of the pattern, don't examine *p.  */
+	  assert (p <= pend);
+          if (p < pend)
+            {
+              boolean is_a_jump_n = false;
+
+              /* If failed to a backwards jump that's part of a repetition
+                 loop, need to pop this failure point and use the next one.  */
+              switch ((re_opcode_t) *p)
+                {
+                case jump_n:
+                  is_a_jump_n = true;
+                case maybe_pop_jump:
+                case pop_failure_jump:
+                case jump:
+                  p1 = p + 1;
+                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+                  p1 += mcnt;
+
+                  if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n)
+                      || (!is_a_jump_n
+                          && (re_opcode_t) *p1 == on_failure_jump))
+                    goto fail;
+                  break;
+                default:
+                  /* do nothing */ ;
+                }
+            }
+
+          if (d >= string1 && d <= end1)
+	    dend = end_match_1;
+        }
+      else
+        break;   /* Matching at this starting point really fails.  */
+    } /* for (;;) */
+
+  if (best_regs_set)
+    goto restore_best_regs;
+
+  FREE_VARIABLES ();
+
+  return -1;         			/* Failure to match.  */
+} /* re_match_2 */
+
+/* Subroutine definitions for re_match_2.  */
+
+
+/* We are passed P pointing to a register number after a start_memory.
+
+   Return true if the pattern up to the corresponding stop_memory can
+   match the empty string, and false otherwise.
+
+   If we find the matching stop_memory, sets P to point to one past its number.
+   Otherwise, sets P to an undefined byte less than or equal to END.
+
+   We don't handle duplicates properly (yet).  */
+
+static boolean
+group_match_null_string_p (p, end, reg_info)
+    unsigned char **p, *end;
+    register_info_type *reg_info;
+{
+  int mcnt;
+  /* Point to after the args to the start_memory.  */
+  unsigned char *p1 = *p + 2;
+
+  while (p1 < end)
+    {
+      /* Skip over opcodes that can match nothing, and return true or
+	 false, as appropriate, when we get to one that can't, or to the
+         matching stop_memory.  */
+
+      switch ((re_opcode_t) *p1)
+        {
+        /* Could be either a loop or a series of alternatives.  */
+        case on_failure_jump:
+          p1++;
+          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+
+          /* If the next operation is not a jump backwards in the
+	     pattern.  */
+
+	  if (mcnt >= 0)
+	    {
+              /* Go through the on_failure_jumps of the alternatives,
+                 seeing if any of the alternatives cannot match nothing.
+                 The last alternative starts with only a jump,
+                 whereas the rest start with on_failure_jump and end
+                 with a jump, e.g., here is the pattern for `a|b|c':
+
+                 /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6
+                 /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3
+                 /exactn/1/c
+
+                 So, we have to first go through the first (n-1)
+                 alternatives and then deal with the last one separately.  */
+
+
+              /* Deal with the first (n-1) alternatives, which start
+                 with an on_failure_jump (see above) that jumps to right
+                 past a jump_past_alt.  */
+
+              while ((re_opcode_t) p1[mcnt-3] == jump_past_alt)
+                {
+                  /* `mcnt' holds how many bytes long the alternative
+                     is, including the ending `jump_past_alt' and
+                     its number.  */
+
+                  if (!alt_match_null_string_p (p1, p1 + mcnt - 3,
+				                      reg_info))
+                    return false;
+
+                  /* Move to right after this alternative, including the
+		     jump_past_alt.  */
+                  p1 += mcnt;
+
+                  /* Break if it's the beginning of an n-th alternative
+                     that doesn't begin with an on_failure_jump.  */
+                  if ((re_opcode_t) *p1 != on_failure_jump)
+                    break;
+
+		  /* Still have to check that it's not an n-th
+		     alternative that starts with an on_failure_jump.  */
+		  p1++;
+                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+                  if ((re_opcode_t) p1[mcnt-3] != jump_past_alt)
+                    {
+		      /* Get to the beginning of the n-th alternative.  */
+                      p1 -= 3;
+                      break;
+                    }
+                }
+
+              /* Deal with the last alternative: go back and get number
+                 of the `jump_past_alt' just before it.  `mcnt' contains
+                 the length of the alternative.  */
+              EXTRACT_NUMBER (mcnt, p1 - 2);
+
+              if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info))
+                return false;
+
+              p1 += mcnt;	/* Get past the n-th alternative.  */
+            } /* if mcnt > 0 */
+          break;
+
+
+        case stop_memory:
+	  assert (p1[1] == **p);
+          *p = p1 + 2;
+          return true;
+
+
+        default:
+          if (!common_op_match_null_string_p (&p1, end, reg_info))
+            return false;
+        }
+    } /* while p1 < end */
+
+  return false;
+} /* group_match_null_string_p */
+
+
+/* Similar to group_match_null_string_p, but doesn't deal with alternatives:
+   It expects P to be the first byte of a single alternative and END one
+   byte past the last. The alternative can contain groups.  */
+
+static boolean
+alt_match_null_string_p (p, end, reg_info)
+    unsigned char *p, *end;
+    register_info_type *reg_info;
+{
+  int mcnt;
+  unsigned char *p1 = p;
+
+  while (p1 < end)
+    {
+      /* Skip over opcodes that can match nothing, and break when we get
+         to one that can't.  */
+
+      switch ((re_opcode_t) *p1)
+        {
+	/* It's a loop.  */
+        case on_failure_jump:
+          p1++;
+          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+          p1 += mcnt;
+          break;
+
+	default:
+          if (!common_op_match_null_string_p (&p1, end, reg_info))
+            return false;
+        }
+    }  /* while p1 < end */
+
+  return true;
+} /* alt_match_null_string_p */
+
+
+/* Deals with the ops common to group_match_null_string_p and
+   alt_match_null_string_p.
+
+   Sets P to one after the op and its arguments, if any.  */
+
+static boolean
+common_op_match_null_string_p (p, end, reg_info)
+    unsigned char **p, *end;
+    register_info_type *reg_info;
+{
+  int mcnt;
+  boolean ret;
+  int reg_no;
+  unsigned char *p1 = *p;
+
+  switch ((re_opcode_t) *p1++)
+    {
+    case no_op:
+    case begline:
+    case endline:
+    case begbuf:
+    case endbuf:
+    case wordbeg:
+    case wordend:
+    case wordbound:
+    case notwordbound:
+#ifdef emacs
+    case before_dot:
+    case at_dot:
+    case after_dot:
+#endif
+      break;
+
+    case start_memory:
+      reg_no = *p1;
+      assert (reg_no > 0 && reg_no <= MAX_REGNUM);
+      ret = group_match_null_string_p (&p1, end, reg_info);
+
+      /* Have to set this here in case we're checking a group which
+         contains a group and a back reference to it.  */
+
+      if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE)
+        REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret;
+
+      if (!ret)
+        return false;
+      break;
+
+    /* If this is an optimized succeed_n for zero times, make the jump.  */
+    case jump:
+      EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+      if (mcnt >= 0)
+        p1 += mcnt;
+      else
+        return false;
+      break;
+
+    case succeed_n:
+      /* Get to the number of times to succeed.  */
+      p1 += 2;
+      EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+
+      if (mcnt == 0)
+        {
+          p1 -= 4;
+          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+          p1 += mcnt;
+        }
+      else
+        return false;
+      break;
+
+    case duplicate:
+      if (!REG_MATCH_NULL_STRING_P (reg_info[*p1]))
+        return false;
+      break;
+
+    case set_number_at:
+      p1 += 4;
+
+    default:
+      /* All other opcodes mean we cannot match the empty string.  */
+      return false;
+  }
+
+  *p = p1;
+  return true;
+} /* common_op_match_null_string_p */
+
+
+/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN
+   bytes; nonzero otherwise.  */
+
+static int
+bcmp_translate (s1, s2, len, translate)
+     const char *s1, *s2;
+     register int len;
+     RE_TRANSLATE_TYPE translate;
+{
+  register const unsigned char *p1 = (const unsigned char *) s1;
+  register const unsigned char *p2 = (const unsigned char *) s2;
+  while (len)
+    {
+      if (translate[*p1++] != translate[*p2++]) return 1;
+      len--;
+    }
+  return 0;
+}
+
+/* Entry points for GNU code.  */
+
+/* re_compile_pattern is the GNU regular expression compiler: it
+   compiles PATTERN (of length SIZE) and puts the result in BUFP.
+   Returns 0 if the pattern was valid, otherwise an error string.
+
+   Assumes the `allocated' (and perhaps `buffer') and `translate' fields
+   are set in BUFP on entry.
+
+   We call regex_compile to do the actual compilation.  */
+
+const char *
+re_compile_pattern (pattern, length, bufp)
+     const char *pattern;
+     size_t length;
+     struct re_pattern_buffer *bufp;
+{
+  reg_errcode_t ret;
+
+  /* GNU code is written to assume at least RE_NREGS registers will be set
+     (and at least one extra will be -1).  */
+  bufp->regs_allocated = REGS_UNALLOCATED;
+
+  /* And GNU code determines whether or not to get register information
+     by passing null for the REGS argument to re_match, etc., not by
+     setting no_sub.  */
+  bufp->no_sub = 0;
+
+  /* Match anchors at newline.  */
+  bufp->newline_anchor = 1;
+
+  ret = regex_compile (pattern, length, re_syntax_options, bufp);
+
+  if (!ret)
+    return NULL;
+  return gettext (re_error_msgid + re_error_msgid_idx[(int) ret]);
+}
+#ifdef _LIBC
+weak_alias (__re_compile_pattern, re_compile_pattern)
+#endif
+
+/* Entry points compatible with 4.2 BSD regex library.  We don't define
+   them unless specifically requested.  */
+
+#if defined _REGEX_RE_COMP || defined _LIBC
+
+/* BSD has one and only one pattern buffer.  */
+static struct re_pattern_buffer re_comp_buf;
+
+char *
+#ifdef _LIBC
+/* Make these definitions weak in libc, so POSIX programs can redefine
+   these names if they don't use our functions, and still use
+   regcomp/regexec below without link errors.  */
+weak_function
+#endif
+re_comp (s)
+    const char *s;
+{
+  reg_errcode_t ret;
+
+  if (!s)
+    {
+      if (!re_comp_buf.buffer)
+	return gettext ("No previous regular expression");
+      return 0;
+    }
+
+  if (!re_comp_buf.buffer)
+    {
+      re_comp_buf.buffer = (unsigned char *) malloc (200);
+      if (re_comp_buf.buffer == NULL)
+        return (char *) gettext (re_error_msgid
+				 + re_error_msgid_idx[(int) REG_ESPACE]);
+      re_comp_buf.allocated = 200;
+
+      re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH);
+      if (re_comp_buf.fastmap == NULL)
+	return (char *) gettext (re_error_msgid
+				 + re_error_msgid_idx[(int) REG_ESPACE]);
+    }
+
+  /* Since `re_exec' always passes NULL for the `regs' argument, we
+     don't need to initialize the pattern buffer fields which affect it.  */
+
+  /* Match anchors at newlines.  */
+  re_comp_buf.newline_anchor = 1;
+
+  ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
+
+  if (!ret)
+    return NULL;
+
+  /* Yes, we're discarding `const' here if !HAVE_LIBINTL.  */
+  return (char *) gettext (re_error_msgid + re_error_msgid_idx[(int) ret]);
+}
+
+
+int
+#ifdef _LIBC
+weak_function
+#endif
+re_exec (s)
+    const char *s;
+{
+  const int len = strlen (s);
+  return
+    0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0);
+}
+
+#endif /* _REGEX_RE_COMP */
+
+/* POSIX.2 functions.  Don't define these for Emacs.  */
+
+#ifndef emacs
+
+/* regcomp takes a regular expression as a string and compiles it.
+
+   PREG is a regex_t *.  We do not expect any fields to be initialized,
+   since POSIX says we shouldn't.  Thus, we set
+
+     `buffer' to the compiled pattern;
+     `used' to the length of the compiled pattern;
+     `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
+       REG_EXTENDED bit in CFLAGS is set; otherwise, to
+       RE_SYNTAX_POSIX_BASIC;
+     `newline_anchor' to REG_NEWLINE being set in CFLAGS;
+     `fastmap' to an allocated space for the fastmap;
+     `fastmap_accurate' to zero;
+     `re_nsub' to the number of subexpressions in PATTERN.
+
+   PATTERN is the address of the pattern string.
+
+   CFLAGS is a series of bits which affect compilation.
+
+     If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
+     use POSIX basic syntax.
+
+     If REG_NEWLINE is set, then . and [^...] don't match newline.
+     Also, regexec will try a match beginning after every newline.
+
+     If REG_ICASE is set, then we considers upper- and lowercase
+     versions of letters to be equivalent when matching.
+
+     If REG_NOSUB is set, then when PREG is passed to regexec, that
+     routine will report only success or failure, and nothing about the
+     registers.
+
+   It returns 0 if it succeeds, nonzero if it doesn't.  (See regex.h for
+   the return codes and their meanings.)  */
+
+int
+regcomp (preg, pattern, cflags)
+    regex_t *preg;
+    const char *pattern;
+    int cflags;
+{
+  reg_errcode_t ret;
+  reg_syntax_t syntax
+    = (cflags & REG_EXTENDED) ?
+      RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC;
+
+  /* regex_compile will allocate the space for the compiled pattern.  */
+  preg->buffer = 0;
+  preg->allocated = 0;
+  preg->used = 0;
+
+  /* Try to allocate space for the fastmap.  */
+  preg->fastmap = (char *) malloc (1 << BYTEWIDTH);
+
+  if (cflags & REG_ICASE)
+    {
+      unsigned i;
+
+      preg->translate
+	= (RE_TRANSLATE_TYPE) malloc (CHAR_SET_SIZE
+				      * sizeof (*(RE_TRANSLATE_TYPE)0));
+      if (preg->translate == NULL)
+        return (int) REG_ESPACE;
+
+      /* Map uppercase characters to corresponding lowercase ones.  */
+      for (i = 0; i < CHAR_SET_SIZE; i++)
+        preg->translate[i] = ISUPPER (i) ? TOLOWER (i) : i;
+    }
+  else
+    preg->translate = NULL;
+
+  /* If REG_NEWLINE is set, newlines are treated differently.  */
+  if (cflags & REG_NEWLINE)
+    { /* REG_NEWLINE implies neither . nor [^...] match newline.  */
+      syntax &= ~RE_DOT_NEWLINE;
+      syntax |= RE_HAT_LISTS_NOT_NEWLINE;
+      /* It also changes the matching behavior.  */
+      preg->newline_anchor = 1;
+    }
+  else
+    preg->newline_anchor = 0;
+
+  preg->no_sub = !!(cflags & REG_NOSUB);
+
+  /* POSIX says a null character in the pattern terminates it, so we
+     can use strlen here in compiling the pattern.  */
+  ret = regex_compile (pattern, strlen (pattern), syntax, preg);
+
+  /* POSIX doesn't distinguish between an unmatched open-group and an
+     unmatched close-group: both are REG_EPAREN.  */
+  if (ret == REG_ERPAREN) ret = REG_EPAREN;
+
+  if (ret == REG_NOERROR && preg->fastmap)
+    {
+      /* Compute the fastmap now, since regexec cannot modify the pattern
+	 buffer.  */
+      if (re_compile_fastmap (preg) == -2)
+	{
+	  /* Some error occured while computing the fastmap, just forget
+	     about it.  */
+	  free (preg->fastmap);
+	  preg->fastmap = NULL;
+	}
+    }
+
+  return (int) ret;
+}
+#ifdef _LIBC
+weak_alias (__regcomp, regcomp)
+#endif
+
+
+/* regexec searches for a given pattern, specified by PREG, in the
+   string STRING.
+
+   If NMATCH is zero or REG_NOSUB was set in the cflags argument to
+   `regcomp', we ignore PMATCH.  Otherwise, we assume PMATCH has at
+   least NMATCH elements, and we set them to the offsets of the
+   corresponding matched substrings.
+
+   EFLAGS specifies `execution flags' which affect matching: if
+   REG_NOTBOL is set, then ^ does not match at the beginning of the
+   string; if REG_NOTEOL is set, then $ does not match at the end.
+
+   We return 0 if we find a match and REG_NOMATCH if not.  */
+
+int
+regexec (preg, string, nmatch, pmatch, eflags)
+    const regex_t *preg;
+    const char *string;
+    size_t nmatch;
+    regmatch_t pmatch[];
+    int eflags;
+{
+  int ret;
+  struct re_registers regs;
+  regex_t private_preg;
+  int len = strlen (string);
+  boolean want_reg_info = !preg->no_sub && nmatch > 0;
+
+  private_preg = *preg;
+
+  private_preg.not_bol = !!(eflags & REG_NOTBOL);
+  private_preg.not_eol = !!(eflags & REG_NOTEOL);
+
+  /* The user has told us exactly how many registers to return
+     information about, via `nmatch'.  We have to pass that on to the
+     matching routines.  */
+  private_preg.regs_allocated = REGS_FIXED;
+
+  if (want_reg_info)
+    {
+      regs.num_regs = nmatch;
+      regs.start = TALLOC (nmatch * 2, regoff_t);
+      if (regs.start == NULL)
+        return (int) REG_NOMATCH;
+      regs.end = regs.start + nmatch;
+    }
+
+  /* Perform the searching operation.  */
+  ret = re_search (&private_preg, string, len,
+                   /* start: */ 0, /* range: */ len,
+                   want_reg_info ? &regs : (struct re_registers *) 0);
+
+  /* Copy the register information to the POSIX structure.  */
+  if (want_reg_info)
+    {
+      if (ret >= 0)
+        {
+          unsigned r;
+
+          for (r = 0; r < nmatch; r++)
+            {
+              pmatch[r].rm_so = regs.start[r];
+              pmatch[r].rm_eo = regs.end[r];
+            }
+        }
+
+      /* If we needed the temporary register info, free the space now.  */
+      free (regs.start);
+    }
+
+  /* We want zero return to mean success, unlike `re_search'.  */
+  return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
+}
+#ifdef _LIBC
+weak_alias (__regexec, regexec)
+#endif
+
+
+/* Returns a message corresponding to an error code, ERRCODE, returned
+   from either regcomp or regexec.   We don't use PREG here.  */
+
+size_t
+regerror (errcode, preg, errbuf, errbuf_size)
+    int errcode;
+    const regex_t *preg;
+    char *errbuf;
+    size_t errbuf_size;
+{
+  const char *msg;
+  size_t msg_size;
+
+  if (errcode < 0
+      || errcode >= (int) (sizeof (re_error_msgid_idx)
+			   / sizeof (re_error_msgid_idx[0])))
+    /* Only error codes returned by the rest of the code should be passed
+       to this routine.  If we are given anything else, or if other regex
+       code generates an invalid error code, then the program has a bug.
+       Dump core so we can fix it.  */
+    abort ();
+
+  msg = gettext (re_error_msgid + re_error_msgid_idx[errcode]);
+
+  msg_size = strlen (msg) + 1; /* Includes the null.  */
+
+  if (errbuf_size != 0)
+    {
+      if (msg_size > errbuf_size)
+        {
+#if defined HAVE_MEMPCPY || defined _LIBC
+	  *((char *) __mempcpy (errbuf, msg, errbuf_size - 1)) = '\0';
+#else
+          memcpy (errbuf, msg, errbuf_size - 1);
+          errbuf[errbuf_size - 1] = 0;
+#endif
+        }
+      else
+        memcpy (errbuf, msg, msg_size);
+    }
+
+  return msg_size;
+}
+#ifdef _LIBC
+weak_alias (__regerror, regerror)
+#endif
+
+
+/* Free dynamically allocated space used by PREG.  */
+
+void
+regfree (preg)
+    regex_t *preg;
+{
+  if (preg->buffer != NULL)
+    free (preg->buffer);
+  preg->buffer = NULL;
+
+  preg->allocated = 0;
+  preg->used = 0;
+
+  if (preg->fastmap != NULL)
+    free (preg->fastmap);
+  preg->fastmap = NULL;
+  preg->fastmap_accurate = 0;
+
+  if (preg->translate != NULL)
+    free (preg->translate);
+  preg->translate = NULL;
+}
+#ifdef _LIBC
+weak_alias (__regfree, regfree)
+#endif
+
+#endif /* not emacs  */
diff --git a/lib/routemap.c b/lib/routemap.c
new file mode 100644
index 0000000..b000f2f
--- /dev/null
+++ b/lib/routemap.c
@@ -0,0 +1,1077 @@
+/* Route map function.
+   Copyright (C) 1998, 1999 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.  */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "memory.h"
+#include "vector.h"
+#include "prefix.h"
+#include "routemap.h"
+#include "command.h"
+
+/* Vector for route match rules. */
+static vector route_match_vec;
+
+/* Vector for route set rules. */
+static vector route_set_vec;
+
+/* Route map rule. This rule has both `match' rule and `set' rule. */
+struct route_map_rule
+{
+  /* Rule type. */
+  struct route_map_rule_cmd *cmd;
+
+  /* For pretty printing. */
+  char *rule_str;
+
+  /* Pre-compiled match rule. */
+  void *value;
+
+  /* Linked list. */
+  struct route_map_rule *next;
+  struct route_map_rule *prev;
+};
+
+/* Making route map list. */
+struct route_map_list
+{
+  struct route_map *head;
+  struct route_map *tail;
+
+  void (*add_hook) (char *);
+  void (*delete_hook) (char *);
+  void (*event_hook) (route_map_event_t, char *); 
+};
+
+/* Master list of route map. */
+static struct route_map_list route_map_master = { NULL, NULL, NULL, NULL };
+
+static void
+route_map_rule_delete (struct route_map_rule_list *,
+		       struct route_map_rule *);
+
+static void
+route_map_index_delete (struct route_map_index *, int);
+
+/* New route map allocation. Please note route map's name must be
+   specified. */
+static struct route_map *
+route_map_new (char *name)
+{
+  struct route_map *new;
+
+  new =  XCALLOC (MTYPE_ROUTE_MAP, sizeof (struct route_map));
+  new->name = XSTRDUP (MTYPE_ROUTE_MAP_NAME, name);
+  return new;
+}
+
+/* Add new name to route_map. */
+static struct route_map *
+route_map_add (char *name)
+{
+  struct route_map *map;
+  struct route_map_list *list;
+
+  map = route_map_new (name);
+  list = &route_map_master;
+    
+  map->next = NULL;
+  map->prev = list->tail;
+  if (list->tail)
+    list->tail->next = map;
+  else
+    list->head = map;
+  list->tail = map;
+
+  /* Execute hook. */
+  if (route_map_master.add_hook)
+    (*route_map_master.add_hook) (name);
+
+  return map;
+}
+
+/* Route map delete from list. */
+static void
+route_map_delete (struct route_map *map)
+{
+  struct route_map_list *list;
+  struct route_map_index *index;
+  char *name;
+  
+  while ((index = map->head) != NULL)
+    route_map_index_delete (index, 0);
+
+  name = map->name;
+
+  list = &route_map_master;
+
+  if (map->next)
+    map->next->prev = map->prev;
+  else
+    list->tail = map->prev;
+
+  if (map->prev)
+    map->prev->next = map->next;
+  else
+    list->head = map->next;
+
+  XFREE (MTYPE_ROUTE_MAP, map);
+
+  /* Execute deletion hook. */
+  if (route_map_master.delete_hook)
+    (*route_map_master.delete_hook) (name);
+
+  if (name)
+    XFREE (MTYPE_ROUTE_MAP_NAME, name);
+
+}
+
+/* Lookup route map by route map name string. */
+struct route_map *
+route_map_lookup_by_name (char *name)
+{
+  struct route_map *map;
+
+  for (map = route_map_master.head; map; map = map->next)
+    if (strcmp (map->name, name) == 0)
+      return map;
+  return NULL;
+}
+
+/* Lookup route map.  If there isn't route map create one and return
+   it. */
+struct route_map *
+route_map_get (char *name)
+{
+  struct route_map *map;
+
+  map = route_map_lookup_by_name (name);
+  if (map == NULL)
+    map = route_map_add (name);
+  return map;
+}
+
+/* Return route map's type string. */
+static char *
+route_map_type_str (enum route_map_type type)
+{
+  switch (type)
+    {
+    case RMAP_PERMIT:
+      return "permit";
+      break;
+    case RMAP_DENY:
+      return "deny";
+      break;
+    default:
+      return "";
+      break;
+    }
+}
+
+int
+route_map_empty (struct route_map *map)
+{
+  if (map->head == NULL && map->tail == NULL)
+    return 1;
+  else
+    return 0;
+}
+
+/* For debug. */
+void
+route_map_print ()
+{
+  struct route_map *map;
+  struct route_map_index *index;
+  struct route_map_rule *rule;
+
+  for (map = route_map_master.head; map; map = map->next)
+    for (index = map->head; index; index = index->next)
+      {
+	printf ("route-map %s %s %d\n", 
+		map->name,
+		route_map_type_str (index->type),
+		index->pref);
+	for (rule = index->match_list.head; rule; rule = rule->next)
+	  printf (" match %s %s\n", rule->cmd->str, rule->rule_str);
+	for (rule = index->set_list.head; rule; rule = rule->next)
+	  printf (" set %s %s\n", rule->cmd->str, rule->rule_str);
+	if (index->exitpolicy == RMAP_GOTO)
+	  printf (" on-match goto %d\n", index->nextpref);
+	if (index->exitpolicy == RMAP_NEXT)
+	  printf (" on-match next\n");
+      }
+}
+
+/* New route map allocation. Please note route map's name must be
+   specified. */
+struct route_map_index *
+route_map_index_new ()
+{
+  struct route_map_index *new;
+
+  new =  XCALLOC (MTYPE_ROUTE_MAP_INDEX, sizeof (struct route_map_index));
+  new->exitpolicy = RMAP_EXIT; /* Default to Cisco-style */
+  return new;
+}
+
+/* Free route map index. */
+static void
+route_map_index_delete (struct route_map_index *index, int notify)
+{
+  struct route_map_rule *rule;
+
+  /* Free route match. */
+  while ((rule = index->match_list.head) != NULL)
+    route_map_rule_delete (&index->match_list, rule);
+
+  /* Free route set. */
+  while ((rule = index->set_list.head) != NULL)
+    route_map_rule_delete (&index->set_list, rule);
+
+  /* Remove index from route map list. */
+  if (index->next)
+    index->next->prev = index->prev;
+  else
+    index->map->tail = index->prev;
+
+  if (index->prev)
+    index->prev->next = index->next;
+  else
+    index->map->head = index->next;
+
+    /* Execute event hook. */
+  if (route_map_master.event_hook && notify)
+    (*route_map_master.event_hook) (RMAP_EVENT_INDEX_DELETED,
+				    index->map->name);
+
+  XFREE (MTYPE_ROUTE_MAP_INDEX, index);
+}
+
+/* Lookup index from route map. */
+struct route_map_index *
+route_map_index_lookup (struct route_map *map, enum route_map_type type,
+			int pref)
+{
+  struct route_map_index *index;
+
+  for (index = map->head; index; index = index->next)
+    if ((index->type == type || type == RMAP_ANY)
+	&& index->pref == pref)
+      return index;
+  return NULL;
+}
+
+/* Add new index to route map. */
+struct route_map_index *
+route_map_index_add (struct route_map *map, enum route_map_type type,
+		     int pref)
+{
+  struct route_map_index *index;
+  struct route_map_index *point;
+
+  /* Allocate new route map inex. */
+  index = route_map_index_new ();
+  index->map = map;
+  index->type = type;
+  index->pref = pref;
+  
+  /* Compare preference. */
+  for (point = map->head; point; point = point->next)
+    if (point->pref >= pref)
+      break;
+
+  if (map->head == NULL)
+    {
+      map->head = map->tail = index;
+    }
+  else if (point == NULL)
+    {
+      index->prev = map->tail;
+      map->tail->next = index;
+      map->tail = index;
+    }
+  else if (point == map->head)
+    {
+      index->next = map->head;
+      map->head->prev = index;
+      map->head = index;
+    }
+  else
+    {
+      index->next = point;
+      index->prev = point->prev;
+      if (point->prev)
+	point->prev->next = index;
+      point->prev = index;
+    }
+
+  /* Execute event hook. */
+  if (route_map_master.event_hook)
+    (*route_map_master.event_hook) (RMAP_EVENT_INDEX_ADDED,
+				    map->name);
+
+  return index;
+}
+
+/* Get route map index. */
+struct route_map_index *
+route_map_index_get (struct route_map *map, enum route_map_type type, 
+		     int pref)
+{
+  struct route_map_index *index;
+
+  index = route_map_index_lookup (map, RMAP_ANY, pref);
+  if (index && index->type != type)
+    {
+      /* Delete index from route map. */
+      route_map_index_delete (index, 1);
+      index = NULL;
+    }
+  if (index == NULL)
+    index = route_map_index_add (map, type, pref);
+  return index;
+}
+
+/* New route map rule */
+struct route_map_rule *
+route_map_rule_new ()
+{
+  struct route_map_rule *new;
+
+  new = XCALLOC (MTYPE_ROUTE_MAP_RULE, sizeof (struct route_map_rule));
+  return new;
+}
+
+/* Install rule command to the match list. */
+void
+route_map_install_match (struct route_map_rule_cmd *cmd)
+{
+  vector_set (route_match_vec, cmd);
+}
+
+/* Install rule command to the set list. */
+void
+route_map_install_set (struct route_map_rule_cmd *cmd)
+{
+  vector_set (route_set_vec, cmd);
+}
+
+/* Lookup rule command from match list. */
+struct route_map_rule_cmd *
+route_map_lookup_match (char *name)
+{
+  int i;
+  struct route_map_rule_cmd *rule;
+
+  for (i = 0; i < vector_max (route_match_vec); i++)
+    if ((rule = vector_slot (route_match_vec, i)) != NULL)
+      if (strcmp (rule->str, name) == 0)
+	return rule;
+  return NULL;
+}
+
+/* Lookup rule command from set list. */
+struct route_map_rule_cmd *
+route_map_lookup_set (char *name)
+{
+  int i;
+  struct route_map_rule_cmd *rule;
+
+  for (i = 0; i < vector_max (route_set_vec); i++)
+    if ((rule = vector_slot (route_set_vec, i)) != NULL)
+      if (strcmp (rule->str, name) == 0)
+	return rule;
+  return NULL;
+}
+
+/* Add match and set rule to rule list. */
+static void
+route_map_rule_add (struct route_map_rule_list *list,
+		    struct route_map_rule *rule)
+{
+  rule->next = NULL;
+  rule->prev = list->tail;
+  if (list->tail)
+    list->tail->next = rule;
+  else
+    list->head = rule;
+  list->tail = rule;
+}
+
+/* Delete rule from rule list. */
+static void
+route_map_rule_delete (struct route_map_rule_list *list,
+		       struct route_map_rule *rule)
+{
+  if (rule->cmd->func_free)
+    (*rule->cmd->func_free) (rule->value);
+
+  if (rule->rule_str)
+    XFREE (MTYPE_ROUTE_MAP_RULE_STR, rule->rule_str);
+
+  if (rule->next)
+    rule->next->prev = rule->prev;
+  else
+    list->tail = rule->prev;
+  if (rule->prev)
+    rule->prev->next = rule->next;
+  else
+    list->head = rule->next;
+
+  XFREE (MTYPE_ROUTE_MAP_RULE, rule);
+}
+
+/* strcmp wrapper function which don't crush even argument is NULL. */
+int
+rulecmp (char *dst, char *src)
+{
+  if (dst == NULL)
+    {
+      if (src ==  NULL)
+	return 0;
+      else
+	return 1;
+    }
+  else
+    {
+      if (src == NULL)
+	return 1;
+      else
+	return strcmp (dst, src);
+    }
+  return 1;
+}
+
+/* Add match statement to route map. */
+int
+route_map_add_match (struct route_map_index *index, char *match_name,
+		     char *match_arg)
+{
+  struct route_map_rule *rule;
+  struct route_map_rule *next;
+  struct route_map_rule_cmd *cmd;
+  void *compile;
+  int replaced = 0;
+
+  /* First lookup rule for add match statement. */
+  cmd = route_map_lookup_match (match_name);
+  if (cmd == NULL)
+    return RMAP_RULE_MISSING;
+
+  /* Next call compile function for this match statement. */
+  if (cmd->func_compile)
+    {
+      compile= (*cmd->func_compile)(match_arg);
+      if (compile == NULL)
+	return RMAP_COMPILE_ERROR;
+    }
+  else
+    compile = NULL;
+
+  /* If argument is completely same ignore it. */
+  for (rule = index->match_list.head; rule; rule = next)
+    {
+      next = rule->next;
+      if (rule->cmd == cmd)
+	{	
+	  route_map_rule_delete (&index->match_list, rule);
+	  replaced = 1;
+	}
+    }
+
+  /* Add new route map match rule. */
+  rule = route_map_rule_new ();
+  rule->cmd = cmd;
+  rule->value = compile;
+  if (match_arg)
+    rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, match_arg);
+  else
+    rule->rule_str = NULL;
+
+  /* Add new route match rule to linked list. */
+  route_map_rule_add (&index->match_list, rule);
+
+  /* Execute event hook. */
+  if (route_map_master.event_hook)
+    (*route_map_master.event_hook) (replaced ?
+				    RMAP_EVENT_MATCH_REPLACED:
+				    RMAP_EVENT_MATCH_ADDED,
+				    index->map->name);
+
+  return 0;
+}
+
+/* Delete specified route match rule. */
+int
+route_map_delete_match (struct route_map_index *index, char *match_name,
+			char *match_arg)
+{
+  struct route_map_rule *rule;
+  struct route_map_rule_cmd *cmd;
+
+  cmd = route_map_lookup_match (match_name);
+  if (cmd == NULL)
+    return 1;
+  
+  for (rule = index->match_list.head; rule; rule = rule->next)
+    if (rule->cmd == cmd && 
+	(rulecmp (rule->rule_str, match_arg) == 0 || match_arg == NULL))
+      {
+	route_map_rule_delete (&index->match_list, rule);
+	/* Execute event hook. */
+	if (route_map_master.event_hook)
+	  (*route_map_master.event_hook) (RMAP_EVENT_MATCH_DELETED,
+					  index->map->name);
+	return 0;
+      }
+  /* Can't find matched rule. */
+  return 1;
+}
+
+/* Add route-map set statement to the route map. */
+int
+route_map_add_set (struct route_map_index *index, char *set_name,
+		   char *set_arg)
+{
+  struct route_map_rule *rule;
+  struct route_map_rule *next;
+  struct route_map_rule_cmd *cmd;
+  void *compile;
+  int replaced = 0;
+
+  cmd = route_map_lookup_set (set_name);
+  if (cmd == NULL)
+    return RMAP_RULE_MISSING;
+
+  /* Next call compile function for this match statement. */
+  if (cmd->func_compile)
+    {
+      compile= (*cmd->func_compile)(set_arg);
+      if (compile == NULL)
+	return RMAP_COMPILE_ERROR;
+    }
+  else
+    compile = NULL;
+
+ /* Add by WJL. if old set command of same kind exist, delete it first
+    to ensure only one set command of same kind exist under a
+    route_map_index. */
+  for (rule = index->set_list.head; rule; rule = next)
+    {
+      next = rule->next;
+      if (rule->cmd == cmd)
+	{
+	  route_map_rule_delete (&index->set_list, rule);
+	  replaced = 1;
+	}
+    }
+
+  /* Add new route map match rule. */
+  rule = route_map_rule_new ();
+  rule->cmd = cmd;
+  rule->value = compile;
+  if (set_arg)
+    rule->rule_str = XSTRDUP (MTYPE_ROUTE_MAP_RULE_STR, set_arg);
+  else
+    rule->rule_str = NULL;
+
+  /* Add new route match rule to linked list. */
+  route_map_rule_add (&index->set_list, rule);
+
+  /* Execute event hook. */
+  if (route_map_master.event_hook)
+    (*route_map_master.event_hook) (replaced ?
+				    RMAP_EVENT_SET_REPLACED:
+				    RMAP_EVENT_SET_ADDED,
+				    index->map->name);
+  return 0;
+}
+
+/* Delete route map set rule. */
+int
+route_map_delete_set (struct route_map_index *index, char *set_name,
+			char *set_arg)
+{
+  struct route_map_rule *rule;
+  struct route_map_rule_cmd *cmd;
+
+  cmd = route_map_lookup_set (set_name);
+  if (cmd == NULL)
+    return 1;
+  
+  for (rule = index->set_list.head; rule; rule = rule->next)
+    if ((rule->cmd == cmd) &&
+         (rulecmp (rule->rule_str, set_arg) == 0 || set_arg == NULL))
+      {
+        route_map_rule_delete (&index->set_list, rule);
+	/* Execute event hook. */
+	if (route_map_master.event_hook)
+	  (*route_map_master.event_hook) (RMAP_EVENT_SET_DELETED,
+					  index->map->name);
+        return 0;
+      }
+  /* Can't find matched rule. */
+  return 1;
+}
+
+/* Apply route map's each index to the object. */
+/*
+** The matrix for a route-map looks like this:
+** (note, this includes the description for the "NEXT"
+** and "GOTO" frobs now
+**
+**            Match   |   No Match
+**                    |
+**  permit      a     |      c
+**                    |
+**  ------------------+---------------
+**                    |
+**  deny        b     |      d
+**                    |
+**
+** a)   Apply Set statements, accept route
+**      If NEXT is specified, goto NEXT statement
+**      If GOTO is specified, goto the first clause where pref > nextpref
+**      If nothing is specified, do as Cisco and finish
+** b)   Finish route-map processing, and deny route
+** c) & d)   Goto Next index
+**
+** If we get no matches after we've processed all updates, then the route
+** is dropped too.
+**
+** Some notes on the new "NEXT" and "GOTO"
+**   on-match next    - If this clause is matched, then the set statements
+**                      are executed and then we drop through to the next clause
+**   on-match goto n  - If this clause is matched, then the set statments
+**                      are executed and then we goto the nth clause, or the
+**                      first clause greater than this. In order to ensure
+**                      route-maps *always* exit, you cannot jump backwards.
+**                      Sorry ;)
+**
+** We need to make sure our route-map processing matches the above
+*/
+route_map_result_t
+route_map_apply_index (struct route_map_index *index, struct prefix *prefix,
+                       route_map_object_t type, void *object)
+{
+  int ret;
+  struct route_map_rule *match;
+  struct route_map_rule *set;
+  
+  /* Check all match rule and if there is no match rule return 0. */
+  for (match = index->match_list.head; match; match = match->next)
+    {
+      /* Try each match statement in turn. If any return something
+       other than RM_MATCH then we don't need to check anymore and can
+       return */
+      ret = (*match->cmd->func_apply)(match->value, prefix, type, object);
+      if (ret != RMAP_MATCH)
+	return ret;
+    }
+
+  /* We get here if all match statements matched From the matrix
+   above, if this is PERMIT we go on and apply the SET functions.  If
+   we're deny, we return indicating we matched a deny */
+
+  /* Apply set statement to the object. */
+  if (index->type == RMAP_PERMIT)
+    {
+      for (set = index->set_list.head; set; set = set->next)
+	{
+	  ret = (*set->cmd->func_apply)(set->value, prefix, type, object);
+	}
+      return RMAP_MATCH;
+    }
+  else 
+    {
+      return RMAP_DENYMATCH;
+    }
+  /* Should not get here! */
+  return RMAP_MATCH;
+}
+
+/* Apply route map to the object. */
+route_map_result_t
+route_map_apply (struct route_map *map, struct prefix *prefix, 
+		 route_map_object_t type, void *object)
+{
+  int ret = 0;
+  struct route_map_index *index;
+
+  if (map == NULL)
+    return RMAP_DENYMATCH;
+
+  for (index = map->head; index; index = index->next)
+    {
+      /* Apply this index. End here if we get a RM_NOMATCH */
+      ret = route_map_apply_index (index, prefix, type, object);
+
+      if (ret != RMAP_NOMATCH)
+	{
+	  /* We now have to handle the NEXT and GOTO clauses */
+	  if(index->exitpolicy == RMAP_EXIT)
+	    return ret;
+	  if(index->exitpolicy == RMAP_GOTO)
+	    {
+	      /* Find the next clause to jump to */
+	      struct route_map_index *next;
+
+	      next = index->next;
+	      while (next && next->pref < index->nextpref)
+		{
+		  index = next;
+		  next = next->next;
+		}
+	      if (next == NULL)
+		{
+		  /* No clauses match! */
+		  return ret;
+		}
+	    }
+	  /* Otherwise, we fall through as it was a NEXT */
+	}
+    }
+  /* Finally route-map does not match at all. */
+  return RMAP_DENYMATCH;
+}
+
+void
+route_map_add_hook (void (*func) (char *))
+{
+  route_map_master.add_hook = func;
+}
+
+void
+route_map_delete_hook (void (*func) (char *))
+{
+  route_map_master.delete_hook = func;
+}
+
+void
+route_map_event_hook (void (*func) (route_map_event_t, char *))
+{
+  route_map_master.event_hook = func;
+}
+
+void
+route_map_init ()
+{
+  /* Make vector for match and set. */
+  route_match_vec = vector_init (1);
+  route_set_vec = vector_init (1);
+}
+
+/* VTY related functions. */
+DEFUN (route_map,
+       route_map_cmd,
+       "route-map WORD (deny|permit) <1-65535>",
+       "Create route-map or enter route-map command mode\n"
+       "Route map tag\n"
+       "Route map denies set operations\n"
+       "Route map permits set operations\n"
+       "Sequence to insert to/delete from existing route-map entry\n")
+{
+  int permit;
+  unsigned long pref;
+  struct route_map *map;
+  struct route_map_index *index;
+  char *endptr = NULL;
+
+  /* Permit check. */
+  if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
+    permit = RMAP_PERMIT;
+  else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
+    permit = RMAP_DENY;
+  else
+    {
+      vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Preference check. */
+  pref = strtoul (argv[2], &endptr, 10);
+  if (pref == ULONG_MAX || *endptr != '\0')
+    {
+      vty_out (vty, "the fourth field must be positive integer%s",
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  if (pref == 0 || pref > 65535)
+    {
+      vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Get route map. */
+  map = route_map_get (argv[0]);
+  index = route_map_index_get (map, permit, pref);
+
+  vty->index = index;
+  vty->node = RMAP_NODE;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_route_map_all,
+       no_route_map_all_cmd,
+       "no route-map WORD",
+       NO_STR
+       "Create route-map or enter route-map command mode\n"
+       "Route map tag\n")
+{
+  struct route_map *map;
+
+  map = route_map_lookup_by_name (argv[0]);
+  if (map == NULL)
+    {
+      vty_out (vty, "%% Could not find route-map %s%s",
+	       argv[0], VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  route_map_delete (map);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_route_map,
+       no_route_map_cmd,
+       "no route-map WORD (deny|permit) <1-65535>",
+       NO_STR
+       "Create route-map or enter route-map command mode\n"
+       "Route map tag\n"
+       "Route map denies set operations\n"
+       "Route map permits set operations\n"
+       "Sequence to insert to/delete from existing route-map entry\n")
+{
+  int permit;
+  unsigned long pref;
+  struct route_map *map;
+  struct route_map_index *index;
+  char *endptr = NULL;
+
+  /* Permit check. */
+  if (strncmp (argv[1], "permit", strlen (argv[1])) == 0)
+    permit = RMAP_PERMIT;
+  else if (strncmp (argv[1], "deny", strlen (argv[1])) == 0)
+    permit = RMAP_DENY;
+  else
+    {
+      vty_out (vty, "the third field must be [permit|deny]%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Preference. */
+  pref = strtoul (argv[2], &endptr, 10);
+  if (pref == ULONG_MAX || *endptr != '\0')
+    {
+      vty_out (vty, "the fourth field must be positive integer%s",
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  if (pref == 0 || pref > 65535)
+    {
+      vty_out (vty, "the fourth field must be <1-65535>%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Existence check. */
+  map = route_map_lookup_by_name (argv[0]);
+  if (map == NULL)
+    {
+      vty_out (vty, "%% Could not find route-map %s%s",
+	       argv[0], VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Lookup route map index. */
+  index = route_map_index_lookup (map, permit, pref);
+  if (index == NULL)
+    {
+      vty_out (vty, "%% Could not find route-map entry %s %s%s", 
+	       argv[0], argv[2], VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Delete index from route map. */
+  route_map_index_delete (index, 1);
+
+  /* If this route rule is the last one, delete route map itself. */
+  if (route_map_empty (map))
+    route_map_delete (map);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (rmap_onmatch_next,
+       rmap_onmatch_next_cmd,
+       "on-match next",
+       "Exit policy on matches\n"
+       "Next clause\n")
+{
+  struct route_map_index *index;
+
+  index = vty->index;
+
+  if (index)
+    index->exitpolicy = RMAP_NEXT;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rmap_onmatch_next,
+       no_rmap_onmatch_next_cmd,
+       "no on-match next",
+       NO_STR
+       "Exit policy on matches\n"
+       "Next clause\n")
+{
+  struct route_map_index *index;
+
+  index = vty->index;
+  
+  if (index)
+    index->exitpolicy = RMAP_EXIT;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (rmap_onmatch_goto,
+       rmap_onmatch_goto_cmd,
+       "on-match goto <1-65535>",
+       "Exit policy on matches\n"
+       "Goto Clause number\n"
+       "Number\n")
+{
+  struct route_map_index *index;
+  int d = 0;
+
+  if (argv[0])
+    d = atoi(argv[0]);
+
+  index = vty->index;
+  if (index)
+    {
+      if (d <= index->pref)
+	{
+	  /* Can't allow you to do that, Dave */
+	  vty_out (vty, "can't jump backwards in route-maps%s", 
+		   VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+      else
+	{
+	  index->exitpolicy = RMAP_GOTO;
+	  index->nextpref = d;
+	}
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rmap_onmatch_goto,
+       no_rmap_onmatch_goto_cmd,
+       "no on-match goto",
+       NO_STR
+       "Exit policy on matches\n"
+       "Next clause\n")
+{
+  struct route_map_index *index;
+
+  index = vty->index;
+
+  if (index)
+    index->exitpolicy = RMAP_EXIT;
+  
+  return CMD_SUCCESS;
+}
+
+/* Configuration write function. */
+int
+route_map_config_write (struct vty *vty)
+{
+  struct route_map *map;
+  struct route_map_index *index;
+  struct route_map_rule *rule;
+  int first = 1;
+  int write = 0;
+
+  for (map = route_map_master.head; map; map = map->next)
+    for (index = map->head; index; index = index->next)
+      {
+	if (!first)
+	  vty_out (vty, "!%s", VTY_NEWLINE);
+	else
+	  first = 0;
+
+	vty_out (vty, "route-map %s %s %d%s", 
+		 map->name,
+		 route_map_type_str (index->type),
+		 index->pref, VTY_NEWLINE);
+
+	for (rule = index->match_list.head; rule; rule = rule->next)
+	  vty_out (vty, " match %s %s%s", rule->cmd->str, 
+		   rule->rule_str ? rule->rule_str : "",
+		   VTY_NEWLINE);
+
+	for (rule = index->set_list.head; rule; rule = rule->next)
+	  vty_out (vty, " set %s %s%s", rule->cmd->str,
+		   rule->rule_str ? rule->rule_str : "",
+		   VTY_NEWLINE);
+	if (index->exitpolicy == RMAP_GOTO)
+	  vty_out (vty, " on-match goto %d%s", index->nextpref,
+		   VTY_NEWLINE);
+	if (index->exitpolicy == RMAP_NEXT)
+	  vty_out (vty," on-match next%s", VTY_NEWLINE);
+	
+	write++;
+      }
+  return write;
+}
+
+/* Route map node structure. */
+struct cmd_node rmap_node =
+{
+  RMAP_NODE,
+  "%s(config-route-map)# ",
+  1
+};
+
+/* Initialization of route map vector. */
+void
+route_map_init_vty ()
+{
+  /* Install route map top node. */
+  install_node (&rmap_node, route_map_config_write);
+
+  /* Install route map commands. */
+  install_default (RMAP_NODE);
+  install_element (CONFIG_NODE, &route_map_cmd);
+  install_element (CONFIG_NODE, &no_route_map_cmd);
+  install_element (CONFIG_NODE, &no_route_map_all_cmd);
+
+  /* Install the on-match stuff */
+  install_element (RMAP_NODE, &route_map_cmd);
+  install_element (RMAP_NODE, &rmap_onmatch_next_cmd);
+  install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd);
+  install_element (RMAP_NODE, &rmap_onmatch_goto_cmd);
+  install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd);
+}
diff --git a/lib/routemap.h b/lib/routemap.h
new file mode 100644
index 0000000..e37f1e7
--- /dev/null
+++ b/lib/routemap.h
@@ -0,0 +1,194 @@
+/* Route map function.
+ * Copyright (C) 1998 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 _ZEBRA_ROUTEMAP_H
+#define _ZEBRA_ROUTEMAP_H
+
+/* Route map's type. */
+enum route_map_type
+{
+  RMAP_PERMIT,
+  RMAP_DENY,
+  RMAP_ANY
+};
+
+typedef enum 
+{
+  RMAP_MATCH,
+  RMAP_DENYMATCH,
+  RMAP_NOMATCH,
+  RMAP_ERROR,
+  RMAP_OKAY
+} route_map_result_t;
+
+typedef enum
+{
+  RMAP_RIP,
+  RMAP_RIPNG,
+  RMAP_OSPF,
+  RMAP_OSPF6,
+  RMAP_BGP
+} route_map_object_t;
+
+typedef enum
+{
+  RMAP_EXIT,
+  RMAP_GOTO,
+  RMAP_NEXT
+} route_map_end_t;
+
+typedef enum
+{
+  RMAP_EVENT_SET_ADDED,
+  RMAP_EVENT_SET_DELETED,
+  RMAP_EVENT_SET_REPLACED,
+  RMAP_EVENT_MATCH_ADDED,
+  RMAP_EVENT_MATCH_DELETED,
+  RMAP_EVENT_MATCH_REPLACED,
+  RMAP_EVENT_INDEX_ADDED,
+  RMAP_EVENT_INDEX_DELETED
+} route_map_event_t;
+
+/* Route map rule structure for matching and setting. */
+struct route_map_rule_cmd
+{
+  /* Route map rule name (e.g. as-path, metric) */
+  char *str;
+
+  /* Function for value set or match. */
+  route_map_result_t (*func_apply)(void *, struct prefix *, 
+				   route_map_object_t, void *);
+
+  /* Compile argument and return result as void *. */
+  void *(*func_compile)(char *);
+
+  /* Free allocated value by func_compile (). */
+  void (*func_free)(void *);
+};
+
+/* Route map apply error. */
+enum
+{
+  /* Route map rule is missing. */
+  RMAP_RULE_MISSING = 1,
+
+  /* Route map rule can't compile */
+  RMAP_COMPILE_ERROR
+};
+
+/* Route map rule list. */
+struct route_map_rule_list
+{
+  struct route_map_rule *head;
+  struct route_map_rule *tail;
+};
+
+/* Route map index structure. */
+struct route_map_index
+{
+  struct route_map *map;
+
+  /* Preference of this route map rule. */
+  int pref;
+
+  /* Route map type permit or deny. */
+  enum route_map_type type;			
+
+  /* Do we follow old rules, or hop forward? */
+  route_map_end_t exitpolicy;
+
+  /* If we're using "GOTO", to where do we go? */
+  int nextpref;
+
+  /* Matching rule list. */
+  struct route_map_rule_list match_list;
+  struct route_map_rule_list set_list;
+
+  /* Make linked list. */
+  struct route_map_index *next;
+  struct route_map_index *prev;
+};
+
+/* Route map list structure. */
+struct route_map
+{
+  /* Name of route map. */
+  char *name;
+
+  /* Route map's rule. */
+  struct route_map_index *head;
+  struct route_map_index *tail;
+
+  /* Make linked list. */
+  struct route_map *next;
+  struct route_map *prev;
+};
+
+/* Prototypes. */
+void route_map_init ();
+void route_map_init_vty ();
+
+/* Add match statement to route map. */
+int
+route_map_add_match (struct route_map_index *index,
+		     char *match_name,
+		     char *match_arg);
+
+/* Delete specified route match rule. */
+int
+route_map_delete_match (struct route_map_index *index,
+			char *match_name,
+			char *match_arg);
+
+/* Add route-map set statement to the route map. */
+int
+route_map_add_set (struct route_map_index *index, 
+		   char *set_name,
+		   char *set_arg);
+
+/* Delete route map set rule. */
+int
+route_map_delete_set (struct route_map_index *index, char *set_name,
+                      char *set_arg);
+
+/* Install rule command to the match list. */
+void
+route_map_install_match (struct route_map_rule_cmd *cmd);
+
+/* Install rule command to the set list. */
+void
+route_map_install_set (struct route_map_rule_cmd *cmd);
+
+/* Lookup route map by name. */
+struct route_map *
+route_map_lookup_by_name (char *name);
+
+/* Apply route map to the object. */
+route_map_result_t
+route_map_apply (struct route_map *map, struct prefix *, 
+		 route_map_object_t object_type, void *object);
+
+void route_map_add_hook (void (*func) (char *));
+void route_map_delete_hook (void (*func) (char *));
+void route_map_event_hook (void (*func) (route_map_event_t, char *));
+
+
+#endif /* _ZEBRA_ROUTEMAP_H */
diff --git a/lib/smux.c b/lib/smux.c
new file mode 100644
index 0000000..32f8c8f
--- /dev/null
+++ b/lib/smux.c
@@ -0,0 +1,1501 @@
+/* SNMP support
+ * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
+ *
+ * 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>
+
+#ifdef HAVE_SNMP
+
+#include <asn1.h>
+#include <snmp.h>
+#include <snmp_impl.h>
+
+#include "smux.h"
+#include "log.h"
+#include "thread.h"
+#include "linklist.h"
+#include "command.h"
+#include "version.h"
+#include "memory.h"
+#include "sockunion.h"
+
+#define min(A,B) ((A) < (B) ? (A) : (B))
+
+enum smux_event {SMUX_SCHEDULE, SMUX_CONNECT, SMUX_READ};
+
+void smux_event (enum smux_event, int);
+
+
+/* SMUX socket. */
+int smux_sock = -1;
+
+/* SMUX subtree list. */
+struct list *treelist;
+
+/* SMUX oid. */
+oid *smux_oid;
+size_t smux_oid_len;
+
+/* SMUX default oid. */
+oid *smux_default_oid;
+size_t smux_default_oid_len;
+
+/* SMUX password. */
+char *smux_passwd;
+char *smux_default_passwd = "";
+
+/* SMUX read threads. */
+struct thread *smux_read_thread;
+
+/* SMUX connect thrads. */
+struct thread *smux_connect_thread;
+
+/* SMUX debug flag. */
+int debug_smux = 0;
+
+/* SMUX failure count. */
+int fail = 0;
+
+/* SMUX node. */
+struct cmd_node smux_node =
+{
+  SMUX_NODE,
+  ""                            /* SMUX has no interface. */
+};
+
+void *
+oid_copy (void *dest, void *src, size_t size)
+{
+  return memcpy (dest, src, size * sizeof (oid));
+}
+
+void
+oid2in_addr (oid oid[], int len, struct in_addr *addr)
+{
+  int i;
+  u_char *pnt;
+  
+  if (len == 0)
+    return;
+
+  pnt = (u_char *) addr;
+
+  for (i = 0; i < len; i++)
+    *pnt++ = oid[i];
+}
+
+void
+oid_copy_addr (oid oid[], struct in_addr *addr, int len)
+{
+  int i;
+  u_char *pnt;
+  
+  if (len == 0)
+    return;
+
+  pnt = (u_char *) addr;
+
+  for (i = 0; i < len; i++)
+    oid[i] = *pnt++;
+}
+
+int
+oid_compare (oid *o1, int o1_len, oid *o2, int o2_len)
+{
+  int i;
+
+  for (i = 0; i < min (o1_len, o2_len); i++)
+    {
+      if (o1[i] < o2[i])
+	return -1;
+      else if (o1[i] > o2[i])
+	return 1;
+    }
+  if (o1_len < o2_len)
+    return -1;
+  if (o1_len > o2_len)
+    return 1;
+
+  return 0;
+}
+
+int
+oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len)
+{
+  int i;
+
+  for (i = 0; i < min (o1_len, o2_len); i++)
+    {
+      if (o1[i] < o2[i])
+	return -1;
+      else if (o1[i] > o2[i])
+	return 1;
+    }
+  if (o1_len < o2_len)
+    return -1;
+
+  return 0;
+}
+
+void
+smux_oid_dump (char *prefix, oid *oid, size_t oid_len)
+{
+  int i;
+  int first = 1;
+  char buf[MAX_OID_LEN * 3];
+
+  buf[0] = '\0';
+
+  for (i = 0; i < oid_len; i++)
+    {
+      sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) oid[i]);
+      first = 0;
+    }
+  zlog_info ("%s: %s", prefix, buf);
+}
+
+int
+smux_socket ()
+{
+  int ret;
+#ifdef HAVE_IPV6
+  struct addrinfo hints, *res0, *res;
+  int gai;
+#else
+  struct sockaddr_in serv;
+  struct servent *sp;
+#endif
+  int sock = 0;
+
+#ifdef HAVE_IPV6
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = PF_UNSPEC;
+  hints.ai_socktype = SOCK_STREAM;
+  gai = getaddrinfo(NULL, "smux", &hints, &res0);
+  if (gai == EAI_SERVICE)
+    {
+      char servbuf[NI_MAXSERV];
+      sprintf(servbuf,"%d",SMUX_PORT_DEFAULT);
+      servbuf[sizeof (servbuf) - 1] = '\0';
+      gai = getaddrinfo(NULL, servbuf, &hints, &res0);
+    }
+  if (gai)
+    {
+      zlog_warn("Cannot locate loopback service smux");
+      return -1;
+    }
+  for(res=res0; res; res=res->ai_next)
+    {
+      if (res->ai_family != AF_INET 
+#ifdef HAVE_IPV6
+	  && res->ai_family != AF_INET6
+#endif /* HAVE_IPV6 */
+	  )
+	continue;
+
+      sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+      if (sock < 0)
+	continue;
+      sockopt_reuseaddr (sock);
+      sockopt_reuseport (sock);
+      ret = connect (sock, res->ai_addr, res->ai_addrlen);
+      if (ret < 0)
+	{
+	  close(sock);
+	  sock = -1;
+	  continue;
+	}
+      break;
+    }
+  freeaddrinfo(res0);
+  if (sock < 0)
+    zlog_warn ("Can't connect to SNMP agent with SMUX");
+#else
+  sock = socket (AF_INET, SOCK_STREAM, 0);
+  if (sock < 0)
+    {
+      zlog_warn ("Can't make socket for SNMP");
+      return -1;
+    }
+
+  memset (&serv, 0, sizeof (struct sockaddr_in));
+  serv.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+  serv.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+
+  sp = getservbyname ("smux", "tcp");
+  if (sp != NULL) 
+    serv.sin_port = sp->s_port;
+  else
+    serv.sin_port = htons (SMUX_PORT_DEFAULT);
+
+  serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+
+  sockopt_reuseaddr (sock);
+  sockopt_reuseport (sock);
+
+  ret = connect (sock, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
+  if (ret < 0)
+    {
+      close (sock);
+      smux_sock = -1;
+      zlog_warn ("Can't connect to SNMP agent with SMUX");
+      return -1;
+    }
+#endif
+  return sock;
+}
+
+void
+smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat,
+		   long errindex, u_char val_type, void *arg, size_t arg_len)
+{
+  int ret;
+  u_char buf[BUFSIZ];
+  u_char *ptr, *h1, *h1e, *h2, *h2e;
+  int len, length;
+
+  ptr = buf;
+  len = BUFSIZ;
+  length = len;
+
+  if (debug_smux)
+    {
+      zlog_info ("SMUX GETRSP send");
+      zlog_info ("SMUX GETRSP reqid: %ld", reqid);
+    }
+
+  h1 = ptr;
+  /* Place holder h1 for complete sequence */
+  ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0);
+  h1e = ptr;
+ 
+  ptr = asn_build_int (ptr, &len,
+		       (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+		       &reqid, sizeof (reqid));
+
+  if (debug_smux)
+    zlog_info ("SMUX GETRSP errstat: %ld", errstat);
+
+  ptr = asn_build_int (ptr, &len,
+		       (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+		       &errstat, sizeof (errstat));
+  if (debug_smux)
+    zlog_info ("SMUX GETRSP errindex: %ld", errindex);
+
+  ptr = asn_build_int (ptr, &len,
+		       (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+		       &errindex, sizeof (errindex));
+
+  h2 = ptr;
+  /* Place holder h2 for one variable */
+  ptr = asn_build_sequence (ptr, &len, 
+			   (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
+			   0);
+  h2e = ptr;
+
+  ptr = snmp_build_var_op (ptr, objid, &objid_len, 
+			   val_type, arg_len, arg, &len);
+
+  /* Now variable size is known, fill in size */
+  asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e);
+
+  /* Fill in size of whole sequence */
+  asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e);
+
+  if (debug_smux)
+    zlog_info ("SMUX getresp send: %d", ptr - buf);
+  
+  ret = send (smux_sock, buf, (ptr - buf), 0);
+}
+
+char *
+smux_var (char *ptr, int len, oid objid[], size_t *objid_len,
+          size_t *var_val_len,
+          u_char *var_val_type,
+          void **var_value)
+{
+  u_char type;
+  u_char val_type;
+  size_t val_len;
+  u_char *val;
+
+  if (debug_smux)
+    zlog_info ("SMUX var parse: len %d", len);
+
+  /* Parse header. */
+  ptr = asn_parse_header (ptr, &len, &type);
+  
+  if (debug_smux)
+    {
+      zlog_info ("SMUX var parse: type %d len %d", type, len);
+      zlog_info ("SMUX var parse: type must be %d", 
+		 (ASN_SEQUENCE | ASN_CONSTRUCTOR));
+    }
+
+  /* Parse var option. */
+  *objid_len = MAX_OID_LEN;
+  ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type, 
+			  &val_len, &val, &len);
+
+  if (var_val_len)
+    *var_val_len = val_len;
+
+  if (var_value)
+    *var_value = (void*) val;
+
+  if (var_val_type)
+    *var_val_type = val_type;
+
+  /* Requested object id length is objid_len. */
+  if (debug_smux)
+    smux_oid_dump ("Request OID", objid, *objid_len);
+
+  if (debug_smux)
+    zlog_info ("SMUX val_type: %d", val_type);
+
+  /* Check request value type. */
+  if (debug_smux)
+  switch (val_type)
+    {
+    case ASN_NULL:
+      /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
+         ASN_NULL. */
+      zlog_info ("ASN_NULL");
+      break;
+
+    case ASN_INTEGER:
+      zlog_info ("ASN_INTEGER");
+      break;
+    case ASN_COUNTER:
+    case ASN_GAUGE:
+    case ASN_TIMETICKS:
+    case ASN_UINTEGER:
+      zlog_info ("ASN_COUNTER");
+      break;
+    case ASN_COUNTER64:
+      zlog_info ("ASN_COUNTER64");
+      break;
+    case ASN_IPADDRESS:
+      zlog_info ("ASN_IPADDRESS");
+      break;
+    case ASN_OCTET_STR:
+      zlog_info ("ASN_OCTET_STR");
+      break;
+    case ASN_OPAQUE:
+    case ASN_NSAP:
+    case ASN_OBJECT_ID:
+      zlog_info ("ASN_OPAQUE");
+      break;
+    case SNMP_NOSUCHOBJECT:
+      zlog_info ("SNMP_NOSUCHOBJECT");
+      break;
+    case SNMP_NOSUCHINSTANCE:
+      zlog_info ("SNMP_NOSUCHINSTANCE");
+      break;
+    case SNMP_ENDOFMIBVIEW:
+      zlog_info ("SNMP_ENDOFMIBVIEW");
+      break;
+    case ASN_BIT_STR:
+      zlog_info ("ASN_BIT_STR");
+      break;
+    default:
+      zlog_info ("Unknown type");
+      break;
+    }
+  return ptr;
+}
+
+/* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on
+   ucd-snmp smux and as such suppose, that the peer receives in the message
+   only one variable. Fortunately, IBM seems to do the same in AIX. */
+
+int
+smux_set (oid *reqid, size_t *reqid_len,
+          u_char val_type, void *val, size_t val_len, int action)
+{
+  int j;
+  struct subtree *subtree;
+  struct variable *v;
+  int subresult;
+  oid *suffix;
+  int suffix_len;
+  int result;
+  u_char *statP = NULL;
+  WriteMethod *write_method = NULL;
+  struct listnode *node;
+
+  /* Check */
+  for (node = treelist->head; node; node = node->next)
+    {
+      subtree = node->data;
+      subresult = oid_compare_part (reqid, *reqid_len,
+                                    subtree->name, subtree->name_len);
+
+      /* Subtree matched. */
+      if (subresult == 0)
+        {
+          /* Prepare suffix. */
+          suffix = reqid + subtree->name_len;
+          suffix_len = *reqid_len - subtree->name_len;
+          result = subresult;
+
+          /* Check variables. */
+          for (j = 0; j < subtree->variables_num; j++)
+            {
+              v = &subtree->variables[j];
+
+              /* Always check suffix */
+              result = oid_compare_part (suffix, suffix_len,
+                                         v->name, v->namelen);
+
+              /* This is exact match so result must be zero. */
+              if (result == 0)
+                {
+                  if (debug_smux)
+                    zlog_info ("SMUX function call index is %d", v->magic);
+		  
+                  statP = (*v->findVar) (v, suffix, &suffix_len, 1,
+					 &val_len, &write_method);
+
+                  if (write_method)
+                    {
+                      return (*write_method)(action, val, val_type, val_len,
+					     statP, suffix, suffix_len, v);
+                    }
+                  else
+                    {
+                      return SNMP_ERR_READONLY;
+                    }
+                }
+
+              /* If above execution is failed or oid is small (so
+                 there is no further match). */
+              if (result < 0)
+                return SNMP_ERR_NOSUCHNAME;
+            }
+        }
+    }
+  return SNMP_ERR_NOSUCHNAME;
+}
+
+int
+smux_get (oid *reqid, size_t *reqid_len, int exact, 
+	  u_char *val_type,void **val, size_t *val_len)
+{
+  int j;
+  struct subtree *subtree;
+  struct variable *v;
+  int subresult;
+  oid *suffix;
+  int suffix_len;
+  int result;
+  WriteMethod *write_method=NULL;
+  struct listnode *node;
+
+  /* Check */
+  for (node = treelist->head; node; node = node->next)
+    {
+      subtree = node->data;
+      subresult = oid_compare_part (reqid, *reqid_len, 
+				    subtree->name, subtree->name_len);
+
+      /* Subtree matched. */
+      if (subresult == 0)
+	{
+	  /* Prepare suffix. */
+	  suffix = reqid + subtree->name_len;
+	  suffix_len = *reqid_len - subtree->name_len;
+	  result = subresult;
+
+	  /* Check variables. */
+	  for (j = 0; j < subtree->variables_num; j++)
+	    {
+	      v = &subtree->variables[j];
+
+	      /* Always check suffix */
+	      result = oid_compare_part (suffix, suffix_len,
+					 v->name, v->namelen);
+
+	      /* This is exact match so result must be zero. */
+	      if (result == 0)
+		{
+		  if (debug_smux)
+		    zlog_info ("SMUX function call index is %d", v->magic);
+
+		  *val = (*v->findVar) (v, suffix, &suffix_len, exact,
+					val_len, &write_method);
+
+		  /* There is no instance. */
+		  if (*val == NULL)
+		    return SNMP_NOSUCHINSTANCE;
+
+		  /* Call is suceed. */
+		  *val_type = v->type;
+
+		  return 0;
+		}
+
+	      /* If above execution is failed or oid is small (so
+                 there is no further match). */
+	      if (result < 0)
+		return SNMP_ERR_NOSUCHNAME;
+	    }
+	}
+    }
+  return SNMP_ERR_NOSUCHNAME;
+}
+
+int
+smux_getnext (oid *reqid, size_t *reqid_len, int exact, 
+	      u_char *val_type,void **val, size_t *val_len)
+{
+  int j;
+  oid save[MAX_OID_LEN];
+  int savelen = 0;
+  struct subtree *subtree;
+  struct variable *v;
+  int subresult;
+  oid *suffix;
+  int suffix_len;
+  int result;
+  WriteMethod *write_method=NULL;
+  struct listnode *node;
+
+
+  /* Save incoming request. */
+  oid_copy (save, reqid, *reqid_len);
+  savelen = *reqid_len;
+
+  /* Check */
+  for (node = treelist->head; node; node = node->next)
+    {
+      subtree = node->data;
+      subresult = oid_compare_part (reqid, *reqid_len, 
+				    subtree->name, subtree->name_len);
+
+      /* If request is in the tree. The agent has to make sure we
+         only receive requests we have registered for. */
+      /* Unfortunately, that's not true. In fact, a SMUX subagent has to
+         behave as if it manages the whole SNMP MIB tree itself. It's the
+         duty of the master agent to collect the best answer and return it
+         to the manager. See RFC 1227 chapter 3.1.6 for the glory details
+         :-). ucd-snmp really behaves bad here as it actually might ask
+         multiple times for the same GETNEXT request as it throws away the
+         answer when it expects it in a different subtree and might come
+         back later with the very same request. --jochen */
+
+      if (subresult <= 0)
+	{
+	  /* Prepare suffix. */
+	  suffix = reqid + subtree->name_len;
+	  suffix_len = *reqid_len - subtree->name_len;
+	  if (subresult < 0)
+	    {
+	      oid_copy(reqid, subtree->name, subtree->name_len);
+	      *reqid_len = subtree->name_len;
+	    }
+	  for (j = 0; j < subtree->variables_num; j++)
+	    {
+	      result = subresult;
+	      v = &subtree->variables[j];
+
+	      /* Next then check result >= 0. */
+	      if (result == 0)
+		result = oid_compare_part (suffix, suffix_len,
+					   v->name, v->namelen);
+
+	      if (result <= 0)
+		{
+		  if (debug_smux)
+		    zlog_info ("SMUX function call index is %d", v->magic);
+		  if(result<0)
+		    {
+		      oid_copy(suffix, v->name, v->namelen);
+		      suffix_len = v->namelen;
+		    }
+		  *val = (*v->findVar) (v, suffix, &suffix_len, exact,
+					val_len, &write_method);
+		  *reqid_len = suffix_len + subtree->name_len;
+		  if (*val)
+		    {
+		      *val_type = v->type;
+		      return 0;
+		    }
+		}
+	    }
+	}
+    }
+  memcpy (reqid, save, savelen * sizeof(oid));
+  *reqid_len = savelen;
+
+  return SNMP_ERR_NOSUCHNAME;
+}
+
+/* GET message header. */
+char *
+smux_parse_get_header (char *ptr, size_t *len, long *reqid)
+{
+  u_char type;
+  long errstat;
+  long errindex;
+
+  /* Request ID. */
+  ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));
+
+  if (debug_smux)
+    zlog_info ("SMUX GET reqid: %d len: %d", (int) *reqid, (int) *len);
+
+  /* Error status. */
+  ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));
+
+  if (debug_smux)
+    zlog_info ("SMUX GET errstat %ld len: %d", errstat, *len);
+
+  /* Error index. */
+  ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));
+
+  if (debug_smux)
+    zlog_info ("SMUX GET errindex %ld len: %d", errindex, *len);
+
+  return ptr;
+}
+
+void
+smux_parse_set (char *ptr, size_t len, int action)
+{
+  long reqid;
+  oid oid[MAX_OID_LEN];
+  size_t oid_len;
+  u_char val_type;
+  void *val;
+  size_t val_len;
+  int ret;
+
+  if (debug_smux)
+    zlog_info ("SMUX SET(%s) message parse: len %d",
+               (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"),
+               len);
+
+  /* Parse SET message header. */
+  ptr = smux_parse_get_header (ptr, &len, &reqid);
+
+  /* Parse SET message object ID. */
+  ptr = smux_var (ptr, len, oid, &oid_len, &val_len, &val_type, &val);
+
+  ret = smux_set (oid, &oid_len, val_type, val, val_len, action);
+  if (debug_smux)
+    zlog_info ("SMUX SET ret %d", ret);
+
+  /* Return result. */
+  if (RESERVE1 == action)
+    smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
+}
+
+void
+smux_parse_get (char *ptr, size_t len, int exact)
+{
+  long reqid;
+  oid oid[MAX_OID_LEN];
+  size_t oid_len;
+  u_char val_type;
+  void *val;
+  size_t val_len;
+  int ret;
+
+  if (debug_smux)
+    zlog_info ("SMUX GET message parse: len %d", len);
+  
+  /* Parse GET message header. */
+  ptr = smux_parse_get_header (ptr, &len, &reqid);
+  
+  /* Parse GET message object ID. We needn't the value come */
+  ptr = smux_var (ptr, len, oid, &oid_len, NULL, NULL, NULL);
+
+  /* Traditional getstatptr. */
+  if (exact)
+    ret = smux_get (oid, &oid_len, exact, &val_type, &val, &val_len);
+  else
+    ret = smux_getnext (oid, &oid_len, exact, &val_type, &val, &val_len);
+
+  /* Return result. */
+  if (ret == 0)
+    smux_getresp_send (oid, oid_len, reqid, 0, 0, val_type, val, val_len);
+  else
+    smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
+}
+
+/* Parse SMUX_CLOSE message. */
+void
+smux_parse_close (char *ptr, int len)
+{
+  long reason = 0;
+
+  while (len--)
+    {
+      reason = (reason << 8) | (long) *ptr;
+      ptr++;
+    }
+  zlog_info ("SMUX_CLOSE with reason: %ld", reason);
+}
+
+/* SMUX_RRSP message. */
+void
+smux_parse_rrsp (char *ptr, int len)
+{
+  char val;
+  long errstat;
+  
+  ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));
+
+  if (debug_smux)
+    zlog_info ("SMUX_RRSP value: %d errstat: %ld", val, errstat);
+}
+
+/* Parse SMUX message. */
+int
+smux_parse (char *ptr, int len)
+{
+  /* This buffer we'll use for SOUT message. We could allocate it with
+     malloc and save only static pointer/lenght, but IMHO static
+     buffer is a faster solusion. */
+  static u_char sout_save_buff[SMUXMAXPKTSIZE];
+  static int sout_save_len = 0;
+
+  int len_income = len; /* see note below: YYY */
+  u_char type;
+  u_char rollback;
+
+  rollback = ptr[2]; /* important only for SMUX_SOUT */
+
+process_rest: /* see note below: YYY */
+
+  /* Parse SMUX message type and subsequent length. */
+  ptr = asn_parse_header (ptr, &len, &type);
+
+  if (debug_smux)
+    zlog_info ("SMUX message received type: %d rest len: %d", type, len);
+
+  switch (type)
+    {
+    case SMUX_OPEN:
+      /* Open must be not send from SNMP agent. */
+      zlog_warn ("SMUX_OPEN received: resetting connection.");
+      return -1;
+      break;
+    case SMUX_RREQ:
+      /* SMUX_RREQ message is invalid for us. */
+      zlog_warn ("SMUX_RREQ received: resetting connection.");
+      return -1;
+      break;
+    case SMUX_SOUT:
+      /* SMUX_SOUT message is now valied for us. */
+      if (debug_smux)
+        zlog_info ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");
+
+      if (sout_save_len > 0)
+        {
+          smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
+          sout_save_len = 0;
+        }
+      else
+        zlog_warn ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);
+
+      if (len_income > 3) 
+        {
+          /* YYY: this strange code has to solve the "slow peer"
+             problem: When agent sends SMUX_SOUT message it doesn't
+             wait any responce and may send some next message to
+             subagent. Then the peer in 'smux_read()' will recieve
+             from socket the 'concatenated' buffer, contaning both
+             SMUX_SOUT message and the next one
+             (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
+             the buffer is longer than 3 ( length of SMUX_SOUT ), we
+             must process the rest of it.  This effect may be observed
+             if 'debug_smux' is set to '1' */
+          ptr++;
+          len = len_income - 3;
+          goto process_rest;
+        }
+      break;
+    case SMUX_GETRSP:
+      /* SMUX_GETRSP message is invalid for us. */
+      zlog_warn ("SMUX_GETRSP received: resetting connection.");
+      return -1;
+      break;
+    case SMUX_CLOSE:
+      /* Close SMUX connection. */
+      if (debug_smux)
+	zlog_info ("SMUX_CLOSE");
+      smux_parse_close (ptr, len);
+      return -1;
+      break;
+    case SMUX_RRSP:
+      /* This is response for register message. */
+      if (debug_smux)
+	zlog_info ("SMUX_RRSP");
+      smux_parse_rrsp (ptr, len);
+      break;
+    case SMUX_GET:
+      /* Exact request for object id. */
+      if (debug_smux)
+	zlog_info ("SMUX_GET");
+      smux_parse_get (ptr, len, 1);
+      break;
+    case SMUX_GETNEXT:
+      /* Next request for object id. */
+      if (debug_smux)
+	zlog_info ("SMUX_GETNEXT");
+      smux_parse_get (ptr, len, 0);
+      break;
+    case SMUX_SET:
+      /* SMUX_SET is supported with some limitations. */
+      if (debug_smux)
+	zlog_info ("SMUX_SET");
+
+      /* save the data for future SMUX_SOUT */
+      memcpy (sout_save_buff, ptr, len);
+      sout_save_len = len;
+      smux_parse_set (ptr, len, RESERVE1);
+      break;
+    default:
+      zlog_info ("Unknown type: %d", type);
+      break;
+    }
+  return 0;
+}
+
+/* SMUX message read function. */
+int
+smux_read (struct thread *t)
+{
+  int sock;
+  int len;
+  u_char buf[SMUXMAXPKTSIZE];
+  int ret;
+
+  /* Clear thread. */
+  sock = THREAD_FD (t);
+  smux_read_thread = NULL;
+
+  if (debug_smux)
+    zlog_info ("SMUX read start");
+
+  /* Read message from SMUX socket. */
+  len = recv (sock, buf, SMUXMAXPKTSIZE, 0);
+
+  if (len < 0)
+    {
+      zlog_warn ("Can't read all SMUX packet: %s", strerror (errno));
+      close (sock);
+      smux_sock = -1;
+      smux_event (SMUX_CONNECT, 0);
+      return -1;
+    }
+
+  if (len == 0)
+    {
+      zlog_warn ("SMUX connection closed: %d", sock);
+      close (sock);
+      smux_sock = -1;
+      smux_event (SMUX_CONNECT, 0);
+      return -1;
+    }
+
+  if (debug_smux)
+    zlog_info ("SMUX read len: %d", len);
+
+  /* Parse the message. */
+  ret = smux_parse (buf, len);
+
+  if (ret < 0)
+    {
+      close (sock);
+      smux_sock = -1;
+      smux_event (SMUX_CONNECT, 0);
+      return -1;
+    }
+
+  /* Regiser read thread. */
+  smux_event (SMUX_READ, sock);
+
+  return 0;
+}
+
+int
+smux_open (int sock)
+{
+  u_char buf[BUFSIZ];
+  u_char *ptr;
+  int len;
+  u_long version;
+  u_char progname[] = "zebra-" ZEBRA_VERSION;
+
+  if (debug_smux)
+    {
+      smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len);
+      zlog_info ("SMUX open progname: %s", progname);
+      zlog_info ("SMUX open password: %s", smux_passwd);
+    }
+
+  ptr = buf;
+  len = BUFSIZ;
+
+  /* SMUX Header.  As placeholder. */
+  ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0);
+
+  /* SMUX Open. */
+  version = 0;
+  ptr = asn_build_int (ptr, &len, 
+		       (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+		       &version, sizeof (u_long));
+
+  /* SMUX connection oid. */
+  ptr = asn_build_objid (ptr, &len,
+			 (u_char) 
+			 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
+			 smux_oid, smux_oid_len);
+
+  /* SMUX connection description. */
+  ptr = asn_build_string (ptr, &len, 
+			  (u_char)
+			  (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
+			  progname, strlen (progname));
+
+  /* SMUX connection password. */
+  ptr = asn_build_string (ptr, &len, 
+			  (u_char)
+			  (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
+			  smux_passwd, strlen (smux_passwd));
+
+  /* Fill in real SMUX header.  We exclude ASN header size (2). */
+  len = BUFSIZ;
+  asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2);
+
+  return send (sock, buf, (ptr - buf), 0);
+}
+
+int
+smux_trap (oid *name, size_t namelen,
+	   oid *iname, size_t inamelen,
+	   struct trap_object *trapobj, size_t trapobjlen,
+	   unsigned int tick)
+{
+  int i;
+  u_char buf[BUFSIZ];
+  u_char *ptr;
+  int len, length;
+  struct in_addr addr;
+  unsigned long val;
+  u_char *h1, *h1e;
+
+  ptr = buf;
+  len = BUFSIZ;
+  length = len;
+
+  /* When SMUX connection is not established. */
+  if (smux_sock < 0)
+    return 0;
+
+  /* SMUX header. */
+  ptr = asn_build_header (ptr, &len, (u_char) SMUX_TRAP, 0);
+
+  /* Sub agent enterprise oid. */
+  ptr = asn_build_objid (ptr, &len,
+			 (u_char) 
+			 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
+			 smux_oid, smux_oid_len);
+
+  /* IP address. */
+  addr.s_addr = 0;
+  ptr = asn_build_string (ptr, &len, 
+			  (u_char)
+			  (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_IPADDRESS),
+			  (u_char *)&addr, sizeof (struct in_addr));
+
+  /* Generic trap integer. */
+  val = SNMP_TRAP_ENTERPRISESPECIFIC;
+  ptr = asn_build_int (ptr, &len, 
+		       (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+		       &val, sizeof (int));
+
+  /* Specific trap integer. */
+  val = 2;
+  ptr = asn_build_int (ptr, &len, 
+		       (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+		       &val, sizeof (int));
+
+  /* Timeticks timestamp. */
+  val = 0;
+  ptr = asn_build_unsigned_int (ptr, &len, 
+				(u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_TIMETICKS),
+				&val, sizeof (int));
+  
+  /* Variables. */
+  h1 = ptr;
+  ptr = asn_build_sequence (ptr, &len, 
+			    (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
+			    0);
+
+
+  /* Iteration for each objects. */
+  h1e = ptr;
+  for (i = 0; i < trapobjlen; i++)
+    {
+      int ret;
+      oid oid[MAX_OID_LEN];
+      size_t oid_len;
+      void *val;
+      size_t val_len;
+      u_char val_type;
+
+      /* Make OID. */
+      oid_copy (oid, name, namelen);
+      oid_copy (oid + namelen, trapobj[i].name, trapobj[i].namelen);
+      oid_copy (oid + namelen + trapobj[i].namelen, iname, inamelen);
+      oid_len = namelen + trapobj[i].namelen + inamelen;
+
+      if (debug_smux)
+	smux_oid_dump ("Trap", oid, oid_len);
+
+      ret = smux_get (oid, &oid_len, 1, &val_type, &val, &val_len);
+
+      if (debug_smux)
+	zlog_info ("smux_get result %d", ret);
+
+      if (ret == 0)
+	ptr = snmp_build_var_op (ptr, oid, &oid_len,
+				 val_type, val_len, val, &len);
+    }
+
+  /* Now variable size is known, fill in size */
+  asn_build_sequence(h1, &length,
+		     (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
+		     ptr - h1e);
+
+  /* Fill in size of whole sequence */
+  len = BUFSIZ;
+  asn_build_header (buf, &len, (u_char) SMUX_TRAP, (ptr - buf) - 2);
+
+  return send (smux_sock, buf, (ptr - buf), 0);
+}
+
+int
+smux_register (int sock)
+{
+  u_char buf[BUFSIZ];
+  u_char *ptr;
+  int len, ret;
+  long priority;
+  long operation;
+  struct subtree *subtree;
+  struct listnode *node;
+
+  ret = 0;
+
+  for (node = treelist->head; node; node = node->next)
+    {
+      ptr = buf;
+      len = BUFSIZ;
+
+      subtree = node->data;
+
+      /* SMUX RReq Header. */
+      ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0);
+
+      /* Register MIB tree. */
+      ptr = asn_build_objid (ptr, &len,
+			    (u_char)
+			    (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
+			    subtree->name, subtree->name_len);
+
+      /* Priority. */
+      priority = -1;
+      ptr = asn_build_int (ptr, &len, 
+		          (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+		          &priority, sizeof (u_long));
+
+      /* Operation. */
+      operation = 2; /* Register R/W */
+      ptr = asn_build_int (ptr, &len, 
+		          (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
+		          &operation, sizeof (u_long));
+
+      if (debug_smux)
+        {
+          smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len);
+          zlog_info ("SMUX register priority: %ld", priority);
+          zlog_info ("SMUX register operation: %ld", operation);
+        }
+
+      len = BUFSIZ;
+      asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2);
+      ret = send (sock, buf, (ptr - buf), 0);
+      if (ret < 0)
+        return ret;
+    }
+  return ret;
+}
+
+/* Try to connect to SNMP agent. */
+int
+smux_connect (struct thread *t)
+{
+  int ret;
+
+  if (debug_smux)
+    zlog_info ("SMUX connect try %d", fail + 1);
+
+  /* Clear thread poner of myself. */
+  smux_connect_thread = NULL;
+
+  /* Make socket.  Try to connect. */
+  smux_sock = smux_socket ();
+  if (smux_sock < 0)
+    {
+      if (++fail < SMUX_MAX_FAILURE)
+	smux_event (SMUX_CONNECT, 0);
+      return 0;
+    }
+
+  /* Send OPEN PDU. */
+  ret = smux_open (smux_sock);
+  if (ret < 0)
+    {
+      zlog_warn ("SMUX open message send failed: %s", strerror (errno));
+      close (smux_sock);
+      smux_sock = -1;
+      if (++fail < SMUX_MAX_FAILURE)
+	smux_event (SMUX_CONNECT, 0);
+      return -1;
+    }
+
+  /* Send any outstanding register PDUs. */
+  ret = smux_register (smux_sock);
+  if (ret < 0)
+    {
+      zlog_warn ("SMUX register message send failed: %s", strerror (errno));
+      close (smux_sock);
+      smux_sock = -1;
+      if (++fail < SMUX_MAX_FAILURE)
+	smux_event (SMUX_CONNECT, 0);
+      return -1;
+    }
+
+  /* Everything goes fine. */
+  smux_event (SMUX_READ, smux_sock);
+
+  return 0;
+}
+
+/* Clear all SMUX related resources. */
+void
+smux_stop ()
+{
+  if (smux_read_thread)
+    thread_cancel (smux_read_thread);
+  if (smux_connect_thread)
+    thread_cancel (smux_connect_thread);
+
+  if (smux_sock >= 0)
+    {
+      close (smux_sock);
+      smux_sock = -1;
+    }
+}
+
+extern struct thread_master *master;
+
+void
+smux_event (enum smux_event event, int sock)
+{
+  switch (event)
+    {
+    case SMUX_SCHEDULE:
+      smux_connect_thread = thread_add_event (master, smux_connect, NULL, 0);
+      break;
+    case SMUX_CONNECT:
+      smux_connect_thread = thread_add_timer (master, smux_connect, NULL, 10);
+      break;
+    case SMUX_READ:
+      smux_read_thread = thread_add_read (master, smux_read, NULL, sock);
+      break;
+    default:
+      break;
+    }
+}
+
+int
+smux_str2oid (char *str, oid *oid, size_t *oid_len)
+{
+  int len;
+  int val;
+
+  len = 0;
+  val = 0;
+  *oid_len = 0;
+
+  if (*str == '.')
+    str++;
+  if (*str == '\0')
+    return 0;
+
+  while (1)
+    {
+      if (! isdigit (*str))
+	return -1;
+
+      while (isdigit (*str))
+	{
+	  val *= 10;
+	  val += (*str - '0');
+	  str++;
+	}
+
+      if (*str == '\0')
+	break;
+      if (*str != '.')
+	return -1;
+
+      oid[len++] = val;
+      val = 0;
+      str++;
+    }
+
+  oid[len++] = val;
+  *oid_len = len;
+
+  return 0;
+}
+
+oid *
+smux_oid_dup (oid *objid, size_t objid_len)
+{
+  oid *new;
+
+  new = XMALLOC (MTYPE_TMP, sizeof (oid) * objid_len);
+  oid_copy (new, objid, objid_len);
+
+  return new;
+}
+
+int
+smux_peer_oid (struct vty *vty, char *oid_str, char *passwd_str)
+{
+  int ret;
+  oid oid[MAX_OID_LEN];
+  size_t oid_len;
+
+  ret = smux_str2oid (oid_str, oid, &oid_len);
+  if (ret != 0)
+    {
+      vty_out (vty, "object ID malformed%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (smux_oid && smux_oid != smux_default_oid)
+    free (smux_oid);
+
+  if (smux_passwd && smux_passwd != smux_default_passwd)
+    {
+      free (smux_passwd);
+      smux_passwd = NULL;
+    }
+
+  smux_oid = smux_oid_dup (oid, oid_len);
+  smux_oid_len = oid_len;
+
+  if (passwd_str)
+    smux_passwd = strdup (passwd_str);
+
+  return CMD_SUCCESS;
+}
+
+int
+smux_header_generic (struct variable *v, oid *name, size_t *length, int exact,
+		     size_t *var_len, WriteMethod **write_method)
+{
+  oid fulloid[MAX_OID_LEN];
+  int ret;
+
+  oid_copy (fulloid, v->name, v->namelen);
+  fulloid[v->namelen] = 0;
+  /* Check against full instance. */
+  ret = oid_compare (name, *length, fulloid, v->namelen + 1);
+
+  /* Check single instance. */
+  if ((exact && (ret != 0)) || (!exact && (ret >= 0)))
+	return MATCH_FAILED;
+
+  /* In case of getnext, fill in full instance. */
+  memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid));
+  *length = v->namelen + 1;
+
+  *write_method = 0;
+  *var_len = sizeof(long);    /* default to 'long' results */
+
+  return MATCH_SUCCEEDED;
+}
+
+int
+smux_peer_default ()
+{
+  if (smux_oid != smux_default_oid)
+    {
+      free (smux_oid);
+      smux_oid = smux_default_oid;
+      smux_oid_len = smux_default_oid_len;
+    }
+  if (smux_passwd != smux_default_passwd)
+    {
+      free (smux_passwd);
+      smux_passwd = smux_default_passwd;
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (smux_peer,
+       smux_peer_cmd,
+       "smux peer OID",
+       "SNMP MUX protocol settings\n"
+       "SNMP MUX peer settings\n"
+       "Object ID used in SMUX peering\n")
+{
+  return smux_peer_oid (vty, argv[0], NULL);
+}
+
+DEFUN (smux_peer_password,
+       smux_peer_password_cmd,
+       "smux peer OID PASSWORD",
+       "SNMP MUX protocol settings\n"
+       "SNMP MUX peer settings\n"
+       "SMUX peering object ID\n"
+       "SMUX peering password\n")
+{
+  return smux_peer_oid (vty, argv[0], argv[1]);
+}
+
+DEFUN (no_smux_peer,
+       no_smux_peer_cmd,
+       "no smux peer OID",
+       NO_STR
+       "SNMP MUX protocol settings\n"
+       "SNMP MUX peer settings\n"
+       "Object ID used in SMUX peering\n")
+{
+  return smux_peer_default ();
+}
+
+DEFUN (no_smux_peer_password,
+       no_smux_peer_password_cmd,
+       "no smux peer OID PASSWORD",
+       NO_STR
+       "SNMP MUX protocol settings\n"
+       "SNMP MUX peer settings\n"
+       "SMUX peering object ID\n"
+       "SMUX peering password\n")
+{
+  return smux_peer_default ();
+}
+
+int
+config_write_smux (struct vty *vty)
+{
+  int first = 1;
+  int i;
+
+  if (smux_oid != smux_default_oid || smux_passwd != smux_default_passwd)
+    {
+      vty_out (vty, "smux peer ");
+      for (i = 0; i < smux_oid_len; i++)
+	{
+	  vty_out (vty, "%s%d", first ? "" : ".", (int) smux_oid[i]);
+	  first = 0;
+	}
+      vty_out (vty, " %s%s", smux_passwd, VTY_NEWLINE);
+    }
+  return 0;
+}
+
+/* Register subtree to smux master tree. */
+void
+smux_register_mib (char *descr, struct variable *var, size_t width, int num, 
+		   oid name[], size_t namelen)
+{
+  struct subtree *tree;
+
+  tree = (struct subtree *)malloc(sizeof(struct subtree));
+  oid_copy (tree->name, name, namelen);
+  tree->name_len = namelen;
+  tree->variables = var;
+  tree->variables_num = num;
+  tree->variables_width = width;
+  tree->registered = 0;
+  listnode_add_sort(treelist, tree);
+}
+
+void
+smux_reset ()
+{
+  /* Setting configuration to default. */
+  smux_peer_default ();
+}
+
+/* Compare function to keep treelist sorted */
+static int
+smux_tree_cmp(struct subtree *tree1, struct subtree *tree2)
+{
+  return oid_compare(tree1->name, tree1->name_len, 
+		     tree2->name, tree2->name_len);
+}
+
+/* Initialize some values then schedule first SMUX connection. */
+void
+smux_init (oid defoid[], size_t defoid_len)
+{
+  /* Set default SMUX oid. */
+  smux_default_oid = defoid;
+  smux_default_oid_len = defoid_len;
+
+  smux_oid = smux_default_oid;
+  smux_oid_len = smux_default_oid_len;
+  smux_passwd = smux_default_passwd;
+  
+  /* Make MIB tree. */
+  treelist = list_new();
+  treelist->cmp = (int (*)(void *, void *))smux_tree_cmp;
+
+  /* Install commands. */
+  install_node (&smux_node, config_write_smux);
+
+  install_element (CONFIG_NODE, &smux_peer_cmd);
+  install_element (CONFIG_NODE, &smux_peer_password_cmd);
+  install_element (CONFIG_NODE, &no_smux_peer_cmd);
+  install_element (CONFIG_NODE, &no_smux_peer_password_cmd);
+}
+
+void
+smux_start(void)
+{
+  /* Schedule first connection. */
+  smux_event (SMUX_SCHEDULE, 0);
+}
+#endif /* HAVE_SNMP */
diff --git a/lib/smux.h b/lib/smux.h
new file mode 100644
index 0000000..91c3d46
--- /dev/null
+++ b/lib/smux.h
@@ -0,0 +1,159 @@
+/* SNMP support
+ * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
+ *
+ * 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 _ZEBRA_SNMP_H
+#define _ZEBRA_SNMP_H
+
+#define SMUX_PORT_DEFAULT 199
+
+#define SMUXMAXPKTSIZE    1500
+#define SMUXMAXSTRLEN      256
+
+#define SMUX_OPEN       (ASN_APPLICATION | ASN_CONSTRUCTOR | 0)
+#define SMUX_CLOSE      (ASN_APPLICATION | ASN_PRIMITIVE | 1)
+#define SMUX_RREQ       (ASN_APPLICATION | ASN_CONSTRUCTOR | 2)
+#define SMUX_RRSP       (ASN_APPLICATION | ASN_PRIMITIVE | 3)
+#define SMUX_SOUT       (ASN_APPLICATION | ASN_PRIMITIVE | 4)
+
+#define SMUX_GET        (ASN_CONTEXT | ASN_CONSTRUCTOR | 0)
+#define SMUX_GETNEXT    (ASN_CONTEXT | ASN_CONSTRUCTOR | 1)
+#define SMUX_GETRSP     (ASN_CONTEXT | ASN_CONSTRUCTOR | 2)
+#define SMUX_SET	(ASN_CONTEXT | ASN_CONSTRUCTOR | 3)
+#define SMUX_TRAP	(ASN_CONTEXT | ASN_CONSTRUCTOR | 4)
+
+#define SMUX_MAX_FAILURE 3
+
+/* Structures here are mostly compatible with UCD SNMP 4.1.1 */
+#define MATCH_FAILED     (-1)
+#define MATCH_SUCCEEDED  0
+
+/* SYNTAX TruthValue from SNMPv2-TC. */
+#define SNMP_TRUE  1
+#define SNMP_FALSE 2
+
+/* SYNTAX RowStatus from SNMPv2-TC. */
+#define SNMP_VALID  1
+#define SNMP_INVALID 2
+
+#define IN_ADDR_SIZE sizeof(struct in_addr)
+
+struct variable;
+
+#define REGISTER_MIB(descr, var, vartype, theoid)		\
+    smux_register_mib(descr, (struct variable *)var, sizeof(struct vartype), \
+    sizeof(var)/sizeof(struct vartype),			\
+    theoid, sizeof(theoid)/sizeof(oid))
+
+typedef int (WriteMethod)(int action,
+			  u_char  *var_val,
+			  u_char   var_val_type,
+			  size_t   var_val_len,
+			  u_char  *statP,
+			  oid     *name,
+			  size_t   length,
+			  struct variable *v);
+
+typedef u_char *(FindVarMethod)(struct variable *v,
+				oid     *name,
+				size_t  *length,
+				int      exact,
+				size_t  *var_len,
+				WriteMethod   **write_method);
+
+/* SNMP variable */
+struct variable
+{
+  /* Index of the MIB.*/
+  u_char magic;
+
+  /* Type of variable. */
+  char type;
+
+  /* Access control list. */
+  u_short acl;
+
+  /* Callback function. */
+  FindVarMethod *findVar;
+
+  /* Suffix of the MIB. */
+  u_char namelen;
+  oid name[MAX_OID_LEN];
+};
+
+/* SNMP tree. */
+struct subtree
+{
+  /* Tree's oid. */
+  oid name[MAX_OID_LEN];
+  u_char name_len;
+
+  /* List of the variables. */
+  struct variable *variables;
+
+  /* Length of the variables list. */
+  int variables_num;
+
+  /* Width of the variables list. */
+  int variables_width;
+
+  /* Registered flag. */
+  int registered;
+};
+
+struct trap_object
+{
+  FindVarMethod *findVar;
+  u_char namelen;
+  oid name[MAX_OID_LEN];
+};
+
+/* Declare SMUX return value. */
+#define SNMP_LOCAL_VARIABLES \
+  static int32_t snmp_int_val; \
+  static struct in_addr snmp_in_addr_val;
+
+#define SNMP_INTEGER(V) \
+  ( \
+    *var_len = sizeof (int32_t), \
+    snmp_int_val = V, \
+    (u_char *) &snmp_int_val \
+  )
+
+#define SNMP_IPADDRESS(V) \
+  ( \
+    *var_len = sizeof (struct in_addr), \
+    snmp_in_addr_val = V, \
+    (u_char *) &snmp_in_addr_val \
+  )
+
+void smux_init (oid [], size_t);
+void smux_start (void);
+void smux_register_mib(char *, struct variable *, size_t, int, oid [], size_t);
+int smux_header_generic (struct variable *, oid [], size_t *, int, size_t *, 
+    WriteMethod **);
+int smux_trap (oid *, size_t, oid *, size_t, struct trap_object *, size_t, unsigned int);
+
+int oid_compare (oid *, int, oid *, int);
+void oid2in_addr (oid [], int, struct in_addr *);
+void *oid_copy (void *, void *, size_t);
+void oid_copy_addr (oid [], struct in_addr *, int);
+
+#endif /* _ZEBRA_SNMP_H */
diff --git a/lib/sockopt.c b/lib/sockopt.c
new file mode 100644
index 0000000..e2beca9
--- /dev/null
+++ b/lib/sockopt.c
@@ -0,0 +1,199 @@
+/* setsockopt functions
+ * Copyright (C) 1999 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.  
+ */
+
+#include <zebra.h>
+#include "log.h"
+
+#ifdef HAVE_IPV6
+/* Set IPv6 packet info to the socket. */
+int
+setsockopt_ipv6_pktinfo (int sock, int val)
+{
+  int ret;
+    
+#ifdef IPV6_RECVPKTINFO		/*2292bis-01*/
+  ret = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val));
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_RECVPKTINFO : %s", strerror (errno));
+#else	/*RFC2292*/
+  ret = setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &val, sizeof(val));
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_PKTINFO : %s", strerror (errno));
+#endif /* INIA_IPV6 */
+  return ret;
+}
+
+/* Set multicast hops val to the socket. */
+int
+setsockopt_ipv6_checksum (int sock, int val)
+{
+  int ret;
+
+#ifdef GNU_LINUX
+  ret = setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val));
+#else
+  ret = setsockopt(sock, IPPROTO_IPV6, IPV6_CHECKSUM, &val, sizeof(val));
+#endif /* GNU_LINUX */
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_CHECKSUM");
+  return ret;
+}
+
+/* Set multicast hops val to the socket. */
+int
+setsockopt_ipv6_multicast_hops (int sock, int val)
+{
+  int ret;
+
+  ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val));
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_MULTICAST_HOPS");
+  return ret;
+}
+
+/* Set multicast hops val to the socket. */
+int
+setsockopt_ipv6_unicast_hops (int sock, int val)
+{
+  int ret;
+
+  ret = setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val));
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_UNICAST_HOPS");
+  return ret;
+}
+
+int
+setsockopt_ipv6_hoplimit (int sock, int val)
+{
+  int ret;
+
+#ifdef IPV6_RECVHOPLIMIT	/*2292bis-01*/
+  ret = setsockopt (sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val));
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_RECVHOPLIMIT");
+#else	/*RFC2292*/
+  ret = setsockopt (sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &val, sizeof(val));
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_HOPLIMIT");
+#endif
+  return ret;
+}
+
+/* Set multicast loop zero to the socket. */
+int
+setsockopt_ipv6_multicast_loop (int sock, int val)
+{
+  int ret;
+    
+  ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
+		    sizeof (val));
+  if (ret < 0)
+    zlog_warn ("can't setsockopt IPV6_MULTICAST_LOOP");
+  return ret;
+}
+
+#endif /* HAVE_IPV6 */
+
+
+/* Set up a multicast socket options for IPv4
+   This is here so that people only have to do their OS multicast mess 
+   in one place rather than all through zebra, ospfd, and ripd 
+   NB: This is a hookpoint for specific OS functionality */
+int
+setsockopt_multicast_ipv4(int sock, 
+			int optname, 
+			struct in_addr if_addr,
+			unsigned int mcast_addr,
+			unsigned int ifindex)
+{
+
+  /* Linux 2.2.0 and up */
+#if defined(GNU_LINUX) && LINUX_VERSION_CODE > 131584
+  /* This is better because it uses ifindex directly */
+  struct ip_mreqn mreqn;
+  
+  switch (optname)
+    {
+    case IP_MULTICAST_IF:
+    case IP_ADD_MEMBERSHIP:
+    case IP_DROP_MEMBERSHIP:
+      memset (&mreqn, 0, sizeof(mreqn));
+
+      if (mcast_addr)
+	mreqn.imr_multiaddr.s_addr = mcast_addr;
+      
+      if (ifindex)
+	mreqn.imr_ifindex = ifindex;
+      else
+	mreqn.imr_address = if_addr;
+      
+      return setsockopt(sock, IPPROTO_IP, optname, (void *)&mreqn, sizeof(mreqn));
+      break;
+
+    default:
+      /* Can out and give an understandable error */
+      errno = EINVAL;
+      return -1;
+      break;
+    }
+
+  /* Example defines for another OS, boilerplate off other code in this
+     function, AND handle optname as per other sections for consistency !! */
+  /* #elif  defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */
+  /* Add your favourite OS here! */
+
+#else /* #if OS_TYPE */ 
+  /* default OS support */
+
+  struct in_addr m;
+  struct ip_mreq mreq;
+
+  switch (optname)
+    {
+    case IP_MULTICAST_IF:
+      m = if_addr;
+      
+      return setsockopt (sock, IPPROTO_IP, optname, (void *)&m, sizeof(m)); 
+      break;
+
+    case IP_ADD_MEMBERSHIP:
+    case IP_DROP_MEMBERSHIP:
+      memset (&mreq, 0, sizeof(mreq));
+      mreq.imr_multiaddr.s_addr = mcast_addr;
+      mreq.imr_interface = if_addr;
+      
+      return setsockopt (sock, 
+			 IPPROTO_IP, 
+			 optname, 
+			 (void *)&mreq, 
+			 sizeof(mreq));
+      break;
+      
+    default:
+      /* Can out and give an understandable error */
+      errno = EINVAL;
+      return -1;
+      break;
+    }
+#endif /* #if OS_TYPE */
+
+}
diff --git a/lib/sockopt.h b/lib/sockopt.h
new file mode 100644
index 0000000..7fb31c1
--- /dev/null
+++ b/lib/sockopt.h
@@ -0,0 +1,41 @@
+/* Router advertisement
+ * Copyright (C) 1999 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 _ZEBRA_SOCKOPT_H
+#define _ZEBRA_SOCKOPT_H
+
+#ifdef HAVE_IPV6
+int setsockopt_ipv6_pktinfo (int, int);
+int setsockopt_ipv6_checksum (int, int);
+int setsockopt_ipv6_multicast_hops (int, int);
+int setsockopt_ipv6_unicast_hops (int, int);
+int setsockopt_ipv6_hoplimit (int, int);
+int setsockopt_ipv6_multicast_loop (int, int);
+#endif /* HAVE_IPV6 */
+
+int setsockopt_multicast_ipv4(int sock, 
+			     int optname, 
+			     struct in_addr if_addr,
+			     unsigned int mcast_addr,
+			     unsigned int ifindex);
+
+
+#endif /*_ZEBRA_SOCKOPT_H */
diff --git a/lib/sockunion.c b/lib/sockunion.c
new file mode 100644
index 0000000..2137162
--- /dev/null
+++ b/lib/sockunion.c
@@ -0,0 +1,756 @@
+/* Socket union related function.
+ * Copyright (c) 1997, 98 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.  
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "vty.h"
+#include "sockunion.h"
+#include "memory.h"
+#include "str.h"
+#include "log.h"
+
+#ifndef HAVE_INET_ATON
+int
+inet_aton (const char *cp, struct in_addr *inaddr)
+{
+  int dots = 0;
+  register u_long addr = 0;
+  register u_long val = 0, base = 10;
+
+  do
+    {
+      register char c = *cp;
+
+      switch (c)
+	{
+	case '0': case '1': case '2': case '3': case '4': case '5':
+	case '6': case '7': case '8': case '9':
+	  val = (val * base) + (c - '0');
+	  break;
+	case '.':
+	  if (++dots > 3)
+	    return 0;
+	case '\0':
+	  if (val > 255)
+	    return 0;
+	  addr = addr << 8 | val;
+	  val = 0;
+	  break;
+	default:
+	  return 0;
+	}
+    } while (*cp++) ;
+
+  if (dots < 3)
+    addr <<= 8 * (3 - dots);
+  if (inaddr)
+    inaddr->s_addr = htonl (addr);
+  return 1;
+}
+#endif /* ! HAVE_INET_ATON */
+
+
+#ifndef HAVE_INET_PTON
+int
+inet_pton (int family, const char *strptr, void *addrptr)
+{
+  if (family == AF_INET)
+    {
+      struct in_addr in_val;
+
+      if (inet_aton (strptr, &in_val))
+	{
+	  memcpy (addrptr, &in_val, sizeof (struct in_addr));
+	  return 1;
+	}
+      return 0;
+    }
+  errno = EAFNOSUPPORT;
+  return -1;
+}
+#endif /* ! HAVE_INET_PTON */
+
+#ifndef HAVE_INET_NTOP
+const char *
+inet_ntop (int family, const void *addrptr, char *strptr, size_t len)
+{
+  unsigned char *p = (unsigned char *) addrptr;
+
+  if (family == AF_INET) 
+    {
+      char temp[INET_ADDRSTRLEN];
+
+      snprintf(temp, sizeof(temp), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+
+      if (strlen(temp) >= len) 
+	{
+	  errno = ENOSPC;
+	  return NULL;
+	}
+      strcpy(strptr, temp);
+      return strptr;
+    }
+
+  errno = EAFNOSUPPORT;
+  return NULL;
+}
+#endif /* ! HAVE_INET_NTOP */
+
+const char *
+inet_sutop (union sockunion *su, char *str)
+{
+  switch (su->sa.sa_family)
+    {
+    case AF_INET:
+      inet_ntop (AF_INET, &su->sin.sin_addr, str, INET_ADDRSTRLEN);
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, INET6_ADDRSTRLEN);
+      break;
+#endif /* HAVE_IPV6 */
+    }
+  return str;
+}
+
+int
+str2sockunion (char *str, union sockunion *su)
+{
+  int ret;
+
+  memset (su, 0, sizeof (union sockunion));
+
+  ret = inet_pton (AF_INET, str, &su->sin.sin_addr);
+  if (ret > 0)			/* Valid IPv4 address format. */
+    {
+      su->sin.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+      su->sin.sin_len = sizeof(struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+      return 0;
+    }
+#ifdef HAVE_IPV6
+  ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr);
+  if (ret > 0)			/* Valid IPv6 address format. */
+    {
+      su->sin6.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+      su->sin6.sin6_len = sizeof(struct sockaddr_in6);
+#endif /* SIN6_LEN */
+      return 0;
+    }
+#endif /* HAVE_IPV6 */
+  return -1;
+}
+
+const char *
+sockunion2str (union sockunion *su, char *buf, size_t len)
+{
+  if  (su->sa.sa_family == AF_INET)
+    return inet_ntop (AF_INET, &su->sin.sin_addr, buf, len);
+#ifdef HAVE_IPV6
+  else if (su->sa.sa_family == AF_INET6)
+    return inet_ntop (AF_INET6, &su->sin6.sin6_addr, buf, len);
+#endif /* HAVE_IPV6 */
+  return NULL;
+}
+
+union sockunion *
+sockunion_str2su (char *str)
+{
+  int ret;
+  union sockunion *su;
+
+  su = XMALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
+  memset (su, 0, sizeof (union sockunion));
+
+  ret = inet_pton (AF_INET, str, &su->sin.sin_addr);
+  if (ret > 0)			/* Valid IPv4 address format. */
+    {
+      su->sin.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+      su->sin.sin_len = sizeof(struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+      return su;
+    }
+#ifdef HAVE_IPV6
+  ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr);
+  if (ret > 0)			/* Valid IPv6 address format. */
+    {
+      su->sin6.sin6_family = AF_INET6;
+#ifdef SIN6_LEN
+      su->sin6.sin6_len = sizeof(struct sockaddr_in6);
+#endif /* SIN6_LEN */
+      return su;
+    }
+#endif /* HAVE_IPV6 */
+
+  XFREE (MTYPE_SOCKUNION, su);
+  return NULL;
+}
+
+char *
+sockunion_su2str (union sockunion *su)
+{
+  char str[INET6_ADDRSTRLEN];
+
+  switch (su->sa.sa_family)
+    {
+    case AF_INET:
+      inet_ntop (AF_INET, &su->sin.sin_addr, str, sizeof (str));
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, sizeof (str));
+      break;
+#endif /* HAVE_IPV6 */
+    }
+  return strdup (str);
+}
+
+/* Return socket of sockunion. */
+int
+sockunion_socket (union sockunion *su)
+{
+  int sock;
+
+  sock = socket (su->sa.sa_family, SOCK_STREAM, 0);
+  if (sock < 0)
+    {
+      zlog (NULL, LOG_WARNING, "Can't make socket : %s", strerror (errno));
+      return -1;
+    }
+
+  return sock;
+}
+
+/* Return accepted new socket file descriptor. */
+int
+sockunion_accept (int sock, union sockunion *su)
+{
+  socklen_t len;
+  int client_sock;
+
+  len = sizeof (union sockunion);
+  client_sock = accept (sock, (struct sockaddr *) su, &len);
+  
+  /* Convert IPv4 compatible IPv6 address to IPv4 address. */
+#ifdef HAVE_IPV6
+  if (su->sa.sa_family == AF_INET6)
+    {
+      if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr))
+	{
+	  struct sockaddr_in sin;
+
+	  memset (&sin, 0, sizeof (struct sockaddr_in));
+	  sin.sin_family = AF_INET;
+	  memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4);
+	  memcpy (su, &sin, sizeof (struct sockaddr_in));
+	}
+    }
+#endif /* HAVE_IPV6 */
+
+  return client_sock;
+}
+
+/* Return sizeof union sockunion.  */
+int
+sockunion_sizeof (union sockunion *su)
+{
+  int ret;
+
+  ret = 0;
+  switch (su->sa.sa_family)
+    {
+    case AF_INET:
+      ret = sizeof (struct sockaddr_in);
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      ret = sizeof (struct sockaddr_in6);
+      break;
+#endif /* AF_INET6 */
+    }
+  return ret;
+}
+
+/* return sockunion structure : this function should be revised. */
+char *
+sockunion_log (union sockunion *su)
+{
+  static char buf[SU_ADDRSTRLEN];
+
+  switch (su->sa.sa_family) 
+    {
+    case AF_INET:
+      snprintf (buf, BUFSIZ, "%s", inet_ntoa (su->sin.sin_addr));
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      snprintf (buf, BUFSIZ, "%s",
+		inet_ntop (AF_INET6, &(su->sin6.sin6_addr), buf, BUFSIZ));
+      break;
+#endif /* HAVE_IPV6 */
+    default:
+      snprintf (buf, BUFSIZ, "af_unknown %d ", su->sa.sa_family);
+      break;
+    }
+  return buf;
+}
+
+/* sockunion_connect returns
+   -1 : error occured
+   0 : connect success
+   1 : connect is in progress */
+enum connect_result
+sockunion_connect (int fd, union sockunion *peersu, unsigned short port,
+		   unsigned int ifindex)
+{
+  int ret;
+  int val;
+  union sockunion su;
+
+  memcpy (&su, peersu, sizeof (union sockunion));
+
+  switch (su.sa.sa_family)
+    {
+    case AF_INET:
+      su.sin.sin_port = port;
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      su.sin6.sin6_port  = port;
+#ifdef KAME
+      if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr) && ifindex)
+	{
+#ifdef HAVE_SIN6_SCOPE_ID
+	  /* su.sin6.sin6_scope_id = ifindex; */
+#endif /* HAVE_SIN6_SCOPE_ID */
+	  SET_IN6_LINKLOCAL_IFINDEX (su.sin6.sin6_addr, ifindex);
+	}
+#endif /* KAME */
+      break;
+#endif /* HAVE_IPV6 */
+    }      
+
+  /* Make socket non-block. */
+  val = fcntl (fd, F_GETFL, 0);
+  fcntl (fd, F_SETFL, val|O_NONBLOCK);
+
+  /* Call connect function. */
+  ret = connect (fd, (struct sockaddr *) &su, sockunion_sizeof (&su));
+
+  /* Immediate success */
+  if (ret == 0)
+    {
+      fcntl (fd, F_SETFL, val);
+      return connect_success;
+    }
+
+  /* If connect is in progress then return 1 else it's real error. */
+  if (ret < 0)
+    {
+      if (errno != EINPROGRESS)
+	{
+	  zlog_info ("can't connect to %s fd %d : %s",
+		     sockunion_log (&su), fd, strerror (errno));
+	  return connect_error;
+	}
+    }
+
+  fcntl (fd, F_SETFL, val);
+
+  return connect_in_progress;
+}
+
+/* Make socket from sockunion union. */
+int
+sockunion_stream_socket (union sockunion *su)
+{
+  int sock;
+
+  if (su->sa.sa_family == 0)
+    su->sa.sa_family = AF_INET_UNION;
+
+  sock = socket (su->sa.sa_family, SOCK_STREAM, 0);
+
+  if (sock < 0)
+    zlog (NULL, LOG_WARNING, "can't make socket sockunion_stream_socket");
+
+  return sock;
+}
+
+/* Bind socket to specified address. */
+int
+sockunion_bind (int sock, union sockunion *su, unsigned short port, 
+		union sockunion *su_addr)
+{
+  int size = 0;
+  int ret;
+
+  if (su->sa.sa_family == AF_INET)
+    {
+      size = sizeof (struct sockaddr_in);
+      su->sin.sin_port = htons (port);
+#ifdef HAVE_SIN_LEN
+      su->sin.sin_len = size;
+#endif /* HAVE_SIN_LEN */
+      if (su_addr == NULL)
+	su->sin.sin_addr.s_addr = htonl (INADDR_ANY);
+    }
+#ifdef HAVE_IPV6
+  else if (su->sa.sa_family == AF_INET6)
+    {
+      size = sizeof (struct sockaddr_in6);
+      su->sin6.sin6_port = htons (port);
+#ifdef SIN6_LEN
+      su->sin6.sin6_len = size;
+#endif /* SIN6_LEN */
+      if (su_addr == NULL)
+	{
+#if defined(LINUX_IPV6) || defined(NRL)
+	  memset (&su->sin6.sin6_addr, 0, sizeof (struct in6_addr));
+#else
+	  su->sin6.sin6_addr = in6addr_any;
+#endif /* LINUX_IPV6 */
+	}
+    }
+#endif /* HAVE_IPV6 */
+  
+
+  ret = bind (sock, (struct sockaddr *)su, size);
+  if (ret < 0)
+    zlog (NULL, LOG_WARNING, "can't bind socket : %s", strerror (errno));
+
+  return ret;
+}
+
+int
+sockopt_reuseaddr (int sock)
+{
+  int ret;
+  int on = 1;
+
+  ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, 
+		    (void *) &on, sizeof (on));
+  if (ret < 0)
+    {
+      zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEADDR to socket %d", sock);
+      return -1;
+    }
+  return 0;
+}
+
+#ifdef SO_REUSEPORT
+int
+sockopt_reuseport (int sock)
+{
+  int ret;
+  int on = 1;
+
+  ret = setsockopt (sock, SOL_SOCKET, SO_REUSEPORT, 
+		    (void *) &on, sizeof (on));
+  if (ret < 0)
+    {
+      zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEADDR to socket %d", sock);
+      return -1;
+    }
+  return 0;
+}
+#else
+int
+sockopt_reuseport (int sock)
+{
+  return 0;
+}
+#endif /* 0 */
+
+int
+sockopt_ttl (int family, int sock, int ttl)
+{
+  int ret;
+
+#ifdef IP_TTL
+  if (family == AF_INET)
+    {
+      ret = setsockopt (sock, IPPROTO_IP, IP_TTL, 
+			(void *) &ttl, sizeof (int));
+      if (ret < 0)
+	{
+	  zlog (NULL, LOG_WARNING, "can't set sockopt IP_TTL %d to socket %d", ttl, sock);
+	  return -1;
+	}
+      return 0;
+    }
+#endif /* IP_TTL */
+#ifdef HAVE_IPV6
+  if (family == AF_INET6)
+    {
+      ret = setsockopt (sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 
+			(void *) &ttl, sizeof (int));
+      if (ret < 0)
+	{
+	  zlog (NULL, LOG_WARNING, "can't set sockopt IPV6_UNICAST_HOPS %d to socket %d",
+		    ttl, sock);
+	  return -1;
+	}
+      return 0;
+    }
+#endif /* HAVE_IPV6 */
+  return 0;
+}
+
+/* If same family and same prefix return 1. */
+int
+sockunion_same (union sockunion *su1, union sockunion *su2)
+{
+  int ret = 0;
+
+  if (su1->sa.sa_family != su2->sa.sa_family)
+    return 0;
+
+  switch (su1->sa.sa_family)
+    {
+    case AF_INET:
+      ret = memcmp (&su1->sin.sin_addr, &su2->sin.sin_addr,
+		    sizeof (struct in_addr));
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      ret = memcmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr,
+		    sizeof (struct in6_addr));
+      break;
+#endif /* HAVE_IPV6 */
+    }
+  if (ret == 0)
+    return 1;
+  else
+    return 0;
+}
+
+/* After TCP connection is established.  Get local address and port. */
+union sockunion *
+sockunion_getsockname (int fd)
+{
+  int ret;
+  int len;
+  union
+  {
+    struct sockaddr sa;
+    struct sockaddr_in sin;
+#ifdef HAVE_IPV6
+    struct sockaddr_in6 sin6;
+#endif /* HAVE_IPV6 */
+    char tmp_buffer[128];
+  } name;
+  union sockunion *su;
+
+  memset (&name, 0, sizeof name);
+  len = sizeof name;
+
+  ret = getsockname (fd, (struct sockaddr *)&name, &len);
+  if (ret < 0)
+    {
+      zlog_warn ("Can't get local address and port by getsockname: %s",
+		 strerror (errno));
+      return NULL;
+    }
+
+  if (name.sa.sa_family == AF_INET)
+    {
+      su = XCALLOC (MTYPE_TMP, sizeof (union sockunion));
+      memcpy (su, &name, sizeof (struct sockaddr_in));
+      return su;
+    }
+#ifdef HAVE_IPV6
+  if (name.sa.sa_family == AF_INET6)
+    {
+      su = XCALLOC (MTYPE_TMP, sizeof (union sockunion));
+      memcpy (su, &name, sizeof (struct sockaddr_in6));
+
+      if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr))
+	{
+	  struct sockaddr_in sin;
+
+	  sin.sin_family = AF_INET;
+	  memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4);
+	  sin.sin_port = su->sin6.sin6_port;
+	  memcpy (su, &sin, sizeof (struct sockaddr_in));
+	}
+      return su;
+    }
+#endif /* HAVE_IPV6 */
+  return NULL;
+}
+
+/* After TCP connection is established.  Get remote address and port. */
+union sockunion *
+sockunion_getpeername (int fd)
+{
+  int ret;
+  int len;
+  union
+  {
+    struct sockaddr sa;
+    struct sockaddr_in sin;
+#ifdef HAVE_IPV6
+    struct sockaddr_in6 sin6;
+#endif /* HAVE_IPV6 */
+    char tmp_buffer[128];
+  } name;
+  union sockunion *su;
+
+  memset (&name, 0, sizeof name);
+  len = sizeof name;
+  ret = getpeername (fd, (struct sockaddr *)&name, &len);
+  if (ret < 0)
+    {
+      zlog (NULL, LOG_WARNING, "Can't get remote address and port: %s",
+	    strerror (errno));
+      return NULL;
+    }
+
+  if (name.sa.sa_family == AF_INET)
+    {
+      su = XCALLOC (MTYPE_TMP, sizeof (union sockunion));
+      memcpy (su, &name, sizeof (struct sockaddr_in));
+      return su;
+    }
+#ifdef HAVE_IPV6
+  if (name.sa.sa_family == AF_INET6)
+    {
+      su = XCALLOC (MTYPE_TMP, sizeof (union sockunion));
+      memcpy (su, &name, sizeof (struct sockaddr_in6));
+
+      if (IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr))
+	{
+	  struct sockaddr_in sin;
+
+	  sin.sin_family = AF_INET;
+	  memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4);
+	  sin.sin_port = su->sin6.sin6_port;
+	  memcpy (su, &sin, sizeof (struct sockaddr_in));
+	}
+      return su;
+    }
+#endif /* HAVE_IPV6 */
+  return NULL;
+}
+
+/* Print sockunion structure */
+void
+sockunion_print (union sockunion *su)
+{
+  if (su == NULL)
+    return;
+
+  switch (su->sa.sa_family) 
+    {
+    case AF_INET:
+      printf ("%s\n", inet_ntoa (su->sin.sin_addr));
+      break;
+#ifdef HAVE_IPV6
+    case AF_INET6:
+      {
+	char buf [64];
+
+	printf ("%s\n", inet_ntop (AF_INET6, &(su->sin6.sin6_addr),
+				 buf, sizeof (buf)));
+      }
+      break;
+#endif /* HAVE_IPV6 */
+
+#ifdef AF_LINK
+    case AF_LINK:
+      {
+	struct sockaddr_dl *sdl;
+
+	sdl = (struct sockaddr_dl *)&(su->sa);
+	printf ("link#%d\n", sdl->sdl_index);
+      }
+      break;
+#endif /* AF_LINK */
+    default:
+      printf ("af_unknown %d\n", su->sa.sa_family);
+      break;
+    }
+}
+
+#ifdef HAVE_IPV6
+int
+in6addr_cmp (struct in6_addr *addr1, struct in6_addr *addr2)
+{
+  int i;
+  u_char *p1, *p2;
+
+  p1 = (u_char *)addr1;
+  p2 = (u_char *)addr2;
+
+  for (i = 0; i < sizeof (struct in6_addr); i++)
+    {
+      if (p1[i] > p2[i])
+	return 1;
+      else if (p1[i] < p2[i])
+	return -1;
+    }
+  return 0;
+}
+#endif /* HAVE_IPV6 */
+
+int
+sockunion_cmp (union sockunion *su1, union sockunion *su2)
+{
+  if (su1->sa.sa_family > su2->sa.sa_family)
+    return 1;
+  if (su1->sa.sa_family < su2->sa.sa_family)
+    return -1;
+
+  if (su1->sa.sa_family == AF_INET)
+    {
+      if (ntohl (su1->sin.sin_addr.s_addr) == ntohl (su2->sin.sin_addr.s_addr))
+	return 0;
+      if (ntohl (su1->sin.sin_addr.s_addr) > ntohl (su2->sin.sin_addr.s_addr))
+	return 1;
+      else
+	return -1;
+    }
+#ifdef HAVE_IPV6
+  if (su1->sa.sa_family == AF_INET6)
+    return in6addr_cmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr);
+#endif /* HAVE_IPV6 */
+  return 0;
+}
+
+/* Duplicate sockunion. */
+union sockunion *
+sockunion_dup (union sockunion *su)
+{
+  union sockunion *dup = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
+  memcpy (dup, su, sizeof (union sockunion));
+  return dup;
+}
+
+void
+sockunion_free (union sockunion *su)
+{
+  XFREE (MTYPE_SOCKUNION, su);
+}
diff --git a/lib/sockunion.h b/lib/sockunion.h
new file mode 100644
index 0000000..99bdf6a
--- /dev/null
+++ b/lib/sockunion.h
@@ -0,0 +1,128 @@
+/*
+ * Socket union header.
+ * Copyright (c) 1997 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 _ZEBRA_SOCKUNION_H
+#define _ZEBRA_SOCKUNION_H
+
+#if 0
+union sockunion {
+  struct sockinet {
+    u_char si_len;
+    u_char si_family;
+    u_short si_port;
+  } su_si;
+  struct sockaddr_in  su_sin;
+  struct sockaddr_in6 su_sin6;
+};
+#define su_len                su_si.si_len
+#define su_family     su_si.si_family
+#define su_port               su_si.si_port
+#endif /* 0 */
+
+union sockunion 
+{
+  struct sockaddr sa;
+  struct sockaddr_in sin;
+#ifdef HAVE_IPV6
+  struct sockaddr_in6 sin6;
+#endif /* HAVE_IPV6 */
+};
+
+enum connect_result
+{
+  connect_error,
+  connect_success,
+  connect_in_progress
+};
+
+/* Default address family. */
+#ifdef HAVE_IPV6
+#define AF_INET_UNION AF_INET6
+#else
+#define AF_INET_UNION AF_INET
+#endif
+
+/* Sockunion address string length.  Same as INET6_ADDRSTRLEN. */
+#define SU_ADDRSTRLEN 46
+
+/* Macro to set link local index to the IPv6 address.  For KAME IPv6
+   stack. */
+#ifdef KAME
+#define	IN6_LINKLOCAL_IFINDEX(a)  ((a).s6_addr[2] << 8 | (a).s6_addr[3])
+#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
+  do { \
+    (a).s6_addr[2] = ((i) >> 8) & 0xff; \
+    (a).s6_addr[3] = (i) & 0xff; \
+  } while (0)
+#else
+#define	IN6_LINKLOCAL_IFINDEX(a)
+#define SET_IN6_LINKLOCAL_IFINDEX(a, i)
+#endif /* KAME */
+
+/* shortcut macro to specify address field of struct sockaddr */
+#define sock2ip(X)   (((struct sockaddr_in *)(X))->sin_addr.s_addr)
+#ifdef HAVE_IPV6
+#define sock2ip6(X)  (((struct sockaddr_in6 *)(X))->sin6_addr.s6_addr)
+#endif /* HAVE_IPV6 */
+
+#define sockunion_family(X)  (X)->sa.sa_family
+
+/* Prototypes. */
+int str2sockunion (char *, union sockunion *);
+const char *sockunion2str (union sockunion *, char *, size_t);
+int sockunion_cmp (union sockunion *, union sockunion *);
+int sockunion_same (union sockunion *, union sockunion *);
+
+char *sockunion_su2str (union sockunion *su);
+union sockunion *sockunion_str2su (char *str);
+struct in_addr sockunion_get_in_addr (union sockunion *su);
+int sockunion_accept (int sock, union sockunion *);
+int sockunion_stream_socket (union sockunion *);
+int sockopt_reuseaddr (int);
+int sockopt_reuseport (int);
+int sockunion_bind (int sock, union sockunion *, unsigned short, union sockunion *);
+int sockopt_ttl (int family, int sock, int ttl);
+int sockunion_socket (union sockunion *su);
+const char *inet_sutop (union sockunion *su, char *str);
+enum connect_result
+sockunion_connect (int fd, union sockunion *su, unsigned short port, unsigned int);
+union sockunion *sockunion_getsockname (int);
+union sockunion *sockunion_getpeername (int);
+union sockunion *sockunion_dup (union sockunion *);
+void sockunion_free (union sockunion *);
+
+#ifndef HAVE_INET_NTOP
+const char *
+inet_ntop (int family, const void *addrptr, char *strptr, size_t len);
+#endif /* HAVE_INET_NTOP */
+
+#ifndef HAVE_INET_PTON
+int
+inet_pton (int family, const char *strptr, void *addrptr);
+#endif /* HAVE_INET_PTON */
+
+#ifndef HAVE_INET_ATON
+int
+inet_aton (const char *cp, struct in_addr *inaddr);
+#endif
+
+#endif /* _ZEBRA_SOCKUNION_H */
diff --git a/lib/str.c b/lib/str.c
new file mode 100644
index 0000000..797e9b8
--- /dev/null
+++ b/lib/str.c
@@ -0,0 +1,62 @@
+/*
+ * zebra string function
+ *
+ * these functions are just very basic wrappers around exiting ones and
+ * do not offer the protection that might be expected against buffer
+ * overruns etc
+ */
+
+#include <zebra.h>
+
+#include "str.h"
+
+#ifndef HAVE_SNPRINTF
+/*
+ * snprint() is a real basic wrapper around the standard sprintf()
+ * without any bounds checking
+ */
+int
+snprintf(char *str, size_t size, const char *format, ...)
+{
+  va_list args;
+
+  va_start (args, format);
+
+  return vsprintf (str, format, args);
+}
+#endif
+
+#ifndef HAVE_STRLCPY
+/*
+ * strlcpy is a safer version of strncpy(), checking the total
+ * size of the buffer
+ */
+size_t
+strlcpy(char *dst, const char *src, size_t size)
+{
+  strncpy(dst, src, size);
+
+  return (strlen(dst));
+}
+#endif
+
+#ifndef HAVE_STRLCAT
+/*
+ * strlcat is a safer version of strncat(), checking the total
+ * size of the buffer
+ */
+size_t
+strlcat(char *dst, const char *src, size_t size)
+{
+  /* strncpy(dst, src, size - strlen(dst)); */
+
+  /* I've just added below code only for workable under Linux.  So
+     need rewrite -- Kunihiro. */
+  if (strlen (dst) + strlen (src) >= size)
+    return -1;
+
+  strcat (dst, src);
+
+  return (strlen(dst));
+}
+#endif
diff --git a/lib/str.h b/lib/str.h
new file mode 100644
index 0000000..4098896
--- /dev/null
+++ b/lib/str.h
@@ -0,0 +1,24 @@
+/*
+ * $Id: str.h,v 1.1 2002/12/13 20:15:29 paul Exp $
+ */
+
+#ifndef _ZEBRA_STR_H
+#define _ZEBRA_STR_H
+
+#ifndef HAVE_SNPRINTF
+int snprintf(char *, size_t, const char *, ...);
+#endif
+
+#ifndef HAVE_VSNPRINTF
+#define vsnprintf(buf, size, format, args) vsprintf(buf, format, args)
+#endif
+
+#ifndef HAVE_STRLCPY
+size_t strlcpy(char *, const char *, size_t);
+#endif
+
+#ifndef HAVE_STRLCAT
+size_t strlcat(char *, const char *, size_t);
+#endif
+
+#endif
diff --git a/lib/stream.c b/lib/stream.c
new file mode 100644
index 0000000..2d4de76
--- /dev/null
+++ b/lib/stream.c
@@ -0,0 +1,479 @@
+/*
+ * Packet interface
+ * Copyright (C) 1999 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.  
+ */
+
+#include <zebra.h>
+
+#include "stream.h"
+#include "memory.h"
+#include "network.h"
+#include "prefix.h"
+
+
+/*A macro to check pointers in order to not
+  go behind the allocated mem block 
+  S -- stream reference
+  Z -- size of data to be written 
+*/
+
+#define CHECK_SIZE(S, Z) \
+	if (((S)->putp + (Z)) > (S)->size) \
+           (Z) = (S)->size - (S)->putp;
+
+/* Stream is fixed length buffer for network output/input. */
+
+/* Make stream buffer. */
+struct stream *
+stream_new (size_t size)
+{
+  struct stream *s;
+
+  s = XCALLOC (MTYPE_STREAM, sizeof (struct stream));
+
+  s->data = XCALLOC (MTYPE_STREAM_DATA, size);
+  s->size = size;
+  return s;
+}
+
+/* Free it now. */
+void
+stream_free (struct stream *s)
+{
+  XFREE (MTYPE_STREAM_DATA, s->data);
+  XFREE (MTYPE_STREAM, s);
+}
+
+unsigned long
+stream_get_getp (struct stream *s)
+{
+  return s->getp;
+}
+
+unsigned long
+stream_get_putp (struct stream *s)
+{
+  return s->putp;
+}
+
+unsigned long
+stream_get_endp (struct stream *s)
+{
+  return s->endp;
+}
+
+unsigned long
+stream_get_size (struct stream *s)
+{
+  return s->size;
+}
+
+/* Stream structre' stream pointer related functions.  */
+void
+stream_set_getp (struct stream *s, unsigned long pos)
+{
+  s->getp = pos;
+}
+
+void
+stream_set_putp (struct stream *s, unsigned long pos)
+{
+  s->putp = pos;
+}
+
+/* Forward pointer. */
+void
+stream_forward (struct stream *s, int size)
+{
+  s->getp += size;
+}
+
+/* Copy from stream to destination. */
+void
+stream_get (void *dst, struct stream *s, size_t size)
+{
+  memcpy (dst, s->data + s->getp, size);
+  s->getp += size;
+}
+
+/* Get next character from the stream. */
+u_char
+stream_getc (struct stream *s)
+{
+  u_char c;
+
+  c = s->data[s->getp];
+  s->getp++;
+  return c;
+}
+
+/* Get next character from the stream. */
+u_char
+stream_getc_from (struct stream *s, unsigned long from)
+{
+  u_char c;
+
+  c = s->data[from];
+  return c;
+}
+
+/* Get next word from the stream. */
+u_int16_t
+stream_getw (struct stream *s)
+{
+  u_int16_t w;
+
+  w = s->data[s->getp++] << 8;
+  w |= s->data[s->getp++];
+  return w;
+}
+
+/* Get next word from the stream. */
+u_int16_t
+stream_getw_from (struct stream *s, unsigned long from)
+{
+  u_int16_t w;
+
+  w = s->data[from++] << 8;
+  w |= s->data[from];
+  return w;
+}
+
+/* Get next long word from the stream. */
+u_int32_t
+stream_getl (struct stream *s)
+{
+  u_int32_t l;
+
+  l  = s->data[s->getp++] << 24;
+  l |= s->data[s->getp++] << 16;
+  l |= s->data[s->getp++] << 8;
+  l |= s->data[s->getp++];
+  return l;
+}
+
+/* Get next long word from the stream. */
+u_int32_t
+stream_get_ipv4 (struct stream *s)
+{
+  u_int32_t l;
+
+  memcpy (&l, s->data + s->getp, 4);
+  s->getp += 4;
+
+  return l;
+}
+
+/* Copy to source to stream. */
+void
+stream_put (struct stream *s, void *src, size_t size)
+{
+
+  CHECK_SIZE(s, size);
+
+  if (src)
+    memcpy (s->data + s->putp, src, size);
+  else
+    memset (s->data + s->putp, 0, size);
+
+  s->putp += size;
+  if (s->putp > s->endp)
+    s->endp = s->putp;
+}
+
+/* Put character to the stream. */
+int
+stream_putc (struct stream *s, u_char c)
+{
+  if (s->putp >= s->size) return 0;
+
+  s->data[s->putp] = c;
+  s->putp++;
+  if (s->putp > s->endp)
+    s->endp = s->putp;
+  return 1;
+}
+
+/* Put word to the stream. */
+int
+stream_putw (struct stream *s, u_int16_t w)
+{
+  if ((s->size - s->putp) < 2) return 0;
+
+  s->data[s->putp++] = (u_char)(w >>  8);
+  s->data[s->putp++] = (u_char) w;
+
+  if (s->putp > s->endp)
+    s->endp = s->putp;
+  return 2;
+}
+
+/* Put long word to the stream. */
+int
+stream_putl (struct stream *s, u_int32_t l)
+{
+  if ((s->size - s->putp) < 4) return 0;
+
+  s->data[s->putp++] = (u_char)(l >> 24);
+  s->data[s->putp++] = (u_char)(l >> 16);
+  s->data[s->putp++] = (u_char)(l >>  8);
+  s->data[s->putp++] = (u_char)l;
+
+  if (s->putp > s->endp)
+    s->endp = s->putp;
+  return 4;
+}
+
+int
+stream_putc_at (struct stream *s, unsigned long putp, u_char c)
+{
+  s->data[putp] = c;
+  return 1;
+}
+
+int
+stream_putw_at (struct stream *s, unsigned long putp, u_int16_t w)
+{
+  s->data[putp] = (u_char)(w >>  8);
+  s->data[putp + 1] = (u_char) w;
+  return 2;
+}
+
+int
+stream_putl_at (struct stream *s, unsigned long putp, u_int32_t l)
+{
+  s->data[putp] = (u_char)(l >> 24);
+  s->data[putp + 1] = (u_char)(l >> 16);
+  s->data[putp + 2] = (u_char)(l >>  8);
+  s->data[putp + 3] = (u_char)l;
+  return 4;
+}
+
+/* Put long word to the stream. */
+int
+stream_put_ipv4 (struct stream *s, u_int32_t l)
+{
+  if ((s->size - s->putp) < 4)
+    return 0;
+
+  memcpy (s->data + s->putp, &l, 4);
+  s->putp += 4;
+
+  if (s->putp > s->endp)
+    s->endp = s->putp;
+  return 4;
+}
+
+/* Put long word to the stream. */
+int
+stream_put_in_addr (struct stream *s, struct in_addr *addr)
+{
+  if ((s->size - s->putp) < 4)
+    return 0;
+
+  memcpy (s->data + s->putp, addr, 4);
+  s->putp += 4;
+
+  if (s->putp > s->endp)
+    s->endp = s->putp;
+  return 4;
+}
+
+/* Put prefix by nlri type format. */
+int
+stream_put_prefix (struct stream *s, struct prefix *p)
+{
+  u_char psize;
+
+  psize = PSIZE (p->prefixlen);
+
+  if ((s->size - s->putp) < psize) return 0;
+
+  stream_putc (s, p->prefixlen);
+  memcpy (s->data + s->putp, &p->u.prefix, psize);
+  s->putp += psize;
+  
+  if (s->putp > s->endp)
+    s->endp = s->putp;
+
+  return psize;
+}
+
+/* Read size from fd. */
+int
+stream_read (struct stream *s, int fd, size_t size)
+{
+  int nbytes;
+
+  nbytes = readn (fd, s->data + s->putp, size);
+
+  if (nbytes > 0)
+    {
+      s->putp += nbytes;
+      s->endp += nbytes;
+    }
+  return nbytes;
+}
+
+/* Read size from fd. */
+int
+stream_read_unblock (struct stream *s, int fd, size_t size)
+{
+  int nbytes;
+  int val;
+
+  val = fcntl (fd, F_GETFL, 0);
+  fcntl (fd, F_SETFL, val|O_NONBLOCK);
+  nbytes = read (fd, s->data + s->putp, size);
+  fcntl (fd, F_SETFL, val);
+
+  if (nbytes > 0)
+    {
+      s->putp += nbytes;
+      s->endp += nbytes;
+    }
+  return nbytes;
+}
+
+/* Write data to buffer. */
+int
+stream_write (struct stream *s, u_char *ptr, size_t size)
+{
+
+  CHECK_SIZE(s, size);
+
+  memcpy (s->data + s->putp, ptr, size);
+  s->putp += size;
+  if (s->putp > s->endp)
+    s->endp = s->putp;
+  return size;
+}
+
+/* Return current read pointer. */
+u_char *
+stream_pnt (struct stream *s)
+{
+  return s->data + s->getp;
+}
+
+/* Check does this stream empty? */
+int
+stream_empty (struct stream *s)
+{
+  if (s->putp == 0 && s->endp == 0 && s->getp == 0)
+    return 1;
+  else
+    return 0;
+}
+
+/* Reset stream. */
+void
+stream_reset (struct stream *s)
+{
+  s->putp = 0;
+  s->endp = 0;
+  s->getp = 0;
+}
+
+/* Write stream contens to the file discriptor. */
+int
+stream_flush (struct stream *s, int fd)
+{
+  int nbytes;
+
+  nbytes = write (fd, s->data + s->getp, s->endp - s->getp);
+
+  return nbytes;
+}
+
+/* Stream first in first out queue. */
+
+struct stream_fifo *
+stream_fifo_new ()
+{
+  struct stream_fifo *new;
+ 
+  new = XCALLOC (MTYPE_STREAM_FIFO, sizeof (struct stream_fifo));
+  return new;
+}
+
+/* Add new stream to fifo. */
+void
+stream_fifo_push (struct stream_fifo *fifo, struct stream *s)
+{
+  if (fifo->tail)
+    fifo->tail->next = s;
+  else
+    fifo->head = s;
+     
+  fifo->tail = s;
+
+  fifo->count++;
+}
+
+/* Delete first stream from fifo. */
+struct stream *
+stream_fifo_pop (struct stream_fifo *fifo)
+{
+  struct stream *s;
+  
+  s = fifo->head; 
+
+  if (s)
+    { 
+      fifo->head = s->next;
+
+      if (fifo->head == NULL)
+	fifo->tail = NULL;
+    }
+
+  fifo->count--;
+
+  return s; 
+}
+
+/* Return first fifo entry. */
+struct stream *
+stream_fifo_head (struct stream_fifo *fifo)
+{
+  return fifo->head;
+}
+
+void
+stream_fifo_clean (struct stream_fifo *fifo)
+{
+  struct stream *s;
+  struct stream *next;
+
+  for (s = fifo->head; s; s = next)
+    {
+      next = s->next;
+      stream_free (s);
+    }
+  fifo->head = fifo->tail = NULL;
+  fifo->count = 0;
+}
+
+void
+stream_fifo_free (struct stream_fifo *fifo)
+{
+  stream_fifo_clean (fifo);
+  XFREE (MTYPE_STREAM_FIFO, fifo);
+}
diff --git a/lib/stream.h b/lib/stream.h
new file mode 100644
index 0000000..c6ef3c8
--- /dev/null
+++ b/lib/stream.h
@@ -0,0 +1,113 @@
+/*
+ * Packet interface
+ * Copyright (C) 1999 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 _ZEBRA_STREAM_H
+#define _ZEBRA_STREAM_H
+
+/* Stream buffer. */
+struct stream
+{
+  struct stream *next;
+
+  unsigned char *data;
+  
+  /* Put pointer. */
+  unsigned long putp;
+
+  /* Get pointer. */
+  unsigned long getp;
+
+  /* End of pointer. */
+  unsigned long endp;
+
+  /* Data size. */
+  unsigned long size;
+};
+
+/* First in first out queue structure. */
+struct stream_fifo
+{
+  unsigned long count;
+
+  struct stream *head;
+  struct stream *tail;
+};
+
+/* Utility macros. */
+#define STREAM_PNT(S)   ((S)->data + (S)->getp)
+#define STREAM_SIZE(S)  ((S)->size)
+#define STREAM_REMAIN(S) ((S)->size - (S)->putp)
+#define STREAM_DATA(S)  ((S)->data)
+
+/* Stream prototypes. */
+struct stream *stream_new (size_t);
+void stream_free (struct stream *);
+
+unsigned long stream_get_getp (struct stream *);
+unsigned long stream_get_putp (struct stream *);
+unsigned long stream_get_endp (struct stream *);
+unsigned long stream_get_size (struct stream *);
+u_char *stream_get_data (struct stream *);
+
+void stream_set_getp (struct stream *, unsigned long);
+void stream_set_putp (struct stream *, unsigned long);
+
+void stream_forward (struct stream *, int);
+
+void stream_put (struct stream *, void *, size_t);
+int stream_putc (struct stream *, u_char);
+int stream_putc_at (struct stream *, unsigned long, u_char);
+int stream_putw (struct stream *, u_int16_t);
+int stream_putw_at (struct stream *, unsigned long, u_int16_t);
+int stream_putl (struct stream *, u_int32_t);
+int stream_putl_at (struct stream *, unsigned long, u_int32_t);
+int stream_put_ipv4 (struct stream *, u_int32_t);
+int stream_put_in_addr (struct stream *, struct in_addr *);
+
+void stream_get (void *, struct stream *, size_t);
+u_char stream_getc (struct stream *);
+u_char stream_getc_from (struct stream *, unsigned long);
+u_int16_t stream_getw (struct stream *);
+u_int16_t stream_getw_from (struct stream *, unsigned long);
+u_int32_t stream_getl (struct stream *);
+u_int32_t stream_get_ipv4 (struct stream *);
+
+#undef stream_read
+#undef stream_write
+int stream_read (struct stream *, int, size_t);
+int stream_read_unblock (struct stream *, int, size_t);
+int stream_write (struct stream *, u_char *, size_t);
+
+u_char *stream_pnt (struct stream *);
+void stream_reset (struct stream *);
+int stream_flush (struct stream *, int);
+int stream_empty (struct stream *);
+
+/* Stream fifo. */
+struct stream_fifo *stream_fifo_new ();
+void stream_fifo_push (struct stream_fifo *fifo, struct stream *s);
+struct stream *stream_fifo_pop (struct stream_fifo *fifo);
+struct stream *stream_fifo_head (struct stream_fifo *fifo);
+void stream_fifo_clean (struct stream_fifo *fifo);
+void stream_fifo_free (struct stream_fifo *fifo);
+
+#endif /* _ZEBRA_STREAM_H */
diff --git a/lib/table.c b/lib/table.c
new file mode 100644
index 0000000..00ba58d
--- /dev/null
+++ b/lib/table.c
@@ -0,0 +1,503 @@
+/*
+ * Routing Table functions.
+ * Copyright (C) 1998 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.  
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "table.h"
+#include "memory.h"
+#include "sockunion.h"
+
+void route_node_delete (struct route_node *);
+void route_table_free (struct route_table *);
+
+struct route_table *
+route_table_init (void)
+{
+  struct route_table *rt;
+
+  rt = XCALLOC (MTYPE_ROUTE_TABLE, sizeof (struct route_table));
+  return rt;
+}
+
+void
+route_table_finish (struct route_table *rt)
+{
+  route_table_free (rt);
+}
+
+/* Allocate new route node. */
+struct route_node *
+route_node_new ()
+{
+  struct route_node *node;
+  node = XCALLOC (MTYPE_ROUTE_NODE, sizeof (struct route_node));
+  return node;
+}
+
+/* Allocate new route node with prefix set. */
+struct route_node *
+route_node_set (struct route_table *table, struct prefix *prefix)
+{
+  struct route_node *node;
+  
+  node = route_node_new ();
+
+  prefix_copy (&node->p, prefix);
+  node->table = table;
+
+  return node;
+}
+
+/* Free route node. */
+void
+route_node_free (struct route_node *node)
+{
+  XFREE (MTYPE_ROUTE_NODE, node);
+}
+
+/* Free route table. */
+void
+route_table_free (struct route_table *rt)
+{
+  struct route_node *tmp_node;
+  struct route_node *node;
+ 
+  if (rt == NULL)
+    return;
+
+  node = rt->top;
+
+  while (node)
+    {
+      if (node->l_left)
+	{
+	  node = node->l_left;
+	  continue;
+	}
+
+      if (node->l_right)
+	{
+	  node = node->l_right;
+	  continue;
+	}
+
+      tmp_node = node;
+      node = node->parent;
+
+      if (node != NULL)
+	{
+	  if (node->l_left == tmp_node)
+	    node->l_left = NULL;
+	  else
+	    node->l_right = NULL;
+
+	  route_node_free (tmp_node);
+	}
+      else
+	{
+	  route_node_free (tmp_node);
+	  break;
+	}
+    }
+ 
+  XFREE (MTYPE_ROUTE_TABLE, rt);
+  return;
+}
+
+/* Utility mask array. */
+static u_char maskbit[] = 
+{
+  0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
+};
+
+/* Common prefix route genaration. */
+static void
+route_common (struct prefix *n, struct prefix *p, struct prefix *new)
+{
+  int i;
+  u_char diff;
+  u_char mask;
+
+  u_char *np = (u_char *)&n->u.prefix;
+  u_char *pp = (u_char *)&p->u.prefix;
+  u_char *newp = (u_char *)&new->u.prefix;
+
+  for (i = 0; i < p->prefixlen / 8; i++)
+    {
+      if (np[i] == pp[i])
+	newp[i] = np[i];
+      else
+	break;
+    }
+
+  new->prefixlen = i * 8;
+
+  if (new->prefixlen != p->prefixlen)
+    {
+      diff = np[i] ^ pp[i];
+      mask = 0x80;
+      while (new->prefixlen < p->prefixlen && !(mask & diff))
+	{
+	  mask >>= 1;
+	  new->prefixlen++;
+	}
+      newp[i] = np[i] & maskbit[new->prefixlen % 8];
+    }
+}
+
+/* Macro version of check_bit (). */
+#define CHECK_BIT(X,P) ((((u_char *)(X))[(P) / 8]) >> (7 - ((P) % 8)) & 1)
+
+/* Check bit of the prefix. */
+static int
+check_bit (u_char *prefix, u_char prefixlen)
+{
+  int offset;
+  int shift;
+  u_char *p = (u_char *)prefix;
+
+  assert (prefixlen <= 128);
+
+  offset = prefixlen / 8;
+  shift = 7 - (prefixlen % 8);
+  
+  return (p[offset] >> shift & 1);
+}
+
+/* Macro version of set_link (). */
+#define SET_LINK(X,Y) (X)->link[CHECK_BIT(&(Y)->prefix,(X)->prefixlen)] = (Y);\
+                      (Y)->parent = (X)
+
+static void
+set_link (struct route_node *node, struct route_node *new)
+{
+  int bit;
+    
+  bit = check_bit (&new->p.u.prefix, node->p.prefixlen);
+
+  assert (bit == 0 || bit == 1);
+
+  node->link[bit] = new;
+  new->parent = node;
+}
+
+/* Lock node. */
+struct route_node *
+route_lock_node (struct route_node *node)
+{
+  node->lock++;
+  return node;
+}
+
+/* Unlock node. */
+void
+route_unlock_node (struct route_node *node)
+{
+  node->lock--;
+
+  if (node->lock == 0)
+    route_node_delete (node);
+}
+
+/* Dump routing table. */
+void
+route_dump_node (struct route_table *t)
+{
+  struct route_node *node;
+  char buf[46];
+
+  for (node = route_top (t); node != NULL; node = route_next (node))
+    {
+      printf ("[%d] %p %s/%d\n", 
+	      node->lock,
+	      node->info,
+	      inet_ntop (node->p.family, &node->p.u.prefix, buf, 46),
+	      node->p.prefixlen);
+    }
+}
+
+/* Find matched prefix. */
+struct route_node *
+route_node_match (struct route_table *table, struct prefix *p)
+{
+  struct route_node *node;
+  struct route_node *matched;
+
+  matched = NULL;
+  node = table->top;
+
+  /* Walk down tree.  If there is matched route then store it to
+     matched. */
+  while (node && node->p.prefixlen <= p->prefixlen && 
+	 prefix_match (&node->p, p))
+    {
+      if (node->info)
+	matched = node;
+      node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)];
+    }
+
+  /* If matched route found, return it. */
+  if (matched)
+    return route_lock_node (matched);
+
+  return NULL;
+}
+
+struct route_node *
+route_node_match_ipv4 (struct route_table *table, struct in_addr *addr)
+{
+  struct prefix_ipv4 p;
+
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_PREFIXLEN;
+  p.prefix = *addr;
+
+  return route_node_match (table, (struct prefix *) &p);
+}
+
+#ifdef HAVE_IPV6
+struct route_node *
+route_node_match_ipv6 (struct route_table *table, struct in6_addr *addr)
+{
+  struct prefix_ipv6 p;
+
+  memset (&p, 0, sizeof (struct prefix_ipv6));
+  p.family = AF_INET6;
+  p.prefixlen = IPV6_MAX_PREFIXLEN;
+  p.prefix = *addr;
+
+  return route_node_match (table, (struct prefix *) &p);
+}
+#endif /* HAVE_IPV6 */
+
+/* Lookup same prefix node.  Return NULL when we can't find route. */
+struct route_node *
+route_node_lookup (struct route_table *table, struct prefix *p)
+{
+  struct route_node *node;
+
+  node = table->top;
+
+  while (node && node->p.prefixlen <= p->prefixlen && 
+	 prefix_match (&node->p, p))
+    {
+      if (node->p.prefixlen == p->prefixlen && node->info)
+	return route_lock_node (node);
+
+      node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)];
+    }
+
+  return NULL;
+}
+
+/* Add node to routing table. */
+struct route_node *
+route_node_get (struct route_table *table, struct prefix *p)
+{
+  struct route_node *new;
+  struct route_node *node;
+  struct route_node *match;
+
+  match = NULL;
+  node = table->top;
+  while (node && node->p.prefixlen <= p->prefixlen && 
+	 prefix_match (&node->p, p))
+    {
+      if (node->p.prefixlen == p->prefixlen)
+	{
+	  route_lock_node (node);
+	  return node;
+	}
+      match = node;
+      node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)];
+    }
+
+  if (node == NULL)
+    {
+      new = route_node_set (table, p);
+      if (match)
+	set_link (match, new);
+      else
+	table->top = new;
+    }
+  else
+    {
+      new = route_node_new ();
+      route_common (&node->p, p, &new->p);
+      new->p.family = p->family;
+      new->table = table;
+      set_link (new, node);
+
+      if (match)
+	set_link (match, new);
+      else
+	table->top = new;
+
+      if (new->p.prefixlen != p->prefixlen)
+	{
+	  match = new;
+	  new = route_node_set (table, p);
+	  set_link (match, new);
+	}
+    }
+  route_lock_node (new);
+  
+  return new;
+}
+
+/* Delete node from the routing table. */
+void
+route_node_delete (struct route_node *node)
+{
+  struct route_node *child;
+  struct route_node *parent;
+
+  assert (node->lock == 0);
+  assert (node->info == NULL);
+
+  if (node->l_left && node->l_right)
+    return;
+
+  if (node->l_left)
+    child = node->l_left;
+  else
+    child = node->l_right;
+
+  parent = node->parent;
+
+  if (child)
+    child->parent = parent;
+
+  if (parent)
+    {
+      if (parent->l_left == node)
+	parent->l_left = child;
+      else
+	parent->l_right = child;
+    }
+  else
+    node->table->top = child;
+
+  route_node_free (node);
+
+  /* If parent node is stub then delete it also. */
+  if (parent && parent->lock == 0)
+    route_node_delete (parent);
+}
+
+/* Get fist node and lock it.  This function is useful when one want
+   to lookup all the node exist in the routing table. */
+struct route_node *
+route_top (struct route_table *table)
+{
+  /* If there is no node in the routing table return NULL. */
+  if (table->top == NULL)
+    return NULL;
+
+  /* Lock the top node and return it. */
+  route_lock_node (table->top);
+  return table->top;
+}
+
+/* Unlock current node and lock next node then return it. */
+struct route_node *
+route_next (struct route_node *node)
+{
+  struct route_node *next;
+  struct route_node *start;
+
+  /* Node may be deleted from route_unlock_node so we have to preserve
+     next node's pointer. */
+
+  if (node->l_left)
+    {
+      next = node->l_left;
+      route_lock_node (next);
+      route_unlock_node (node);
+      return next;
+    }
+  if (node->l_right)
+    {
+      next = node->l_right;
+      route_lock_node (next);
+      route_unlock_node (node);
+      return next;
+    }
+
+  start = node;
+  while (node->parent)
+    {
+      if (node->parent->l_left == node && node->parent->l_right)
+	{
+	  next = node->parent->l_right;
+	  route_lock_node (next);
+	  route_unlock_node (start);
+	  return next;
+	}
+      node = node->parent;
+    }
+  route_unlock_node (start);
+  return NULL;
+}
+
+/* Unlock current node and lock next node until limit. */
+struct route_node *
+route_next_until (struct route_node *node, struct route_node *limit)
+{
+  struct route_node *next;
+  struct route_node *start;
+
+  /* Node may be deleted from route_unlock_node so we have to preserve
+     next node's pointer. */
+
+  if (node->l_left)
+    {
+      next = node->l_left;
+      route_lock_node (next);
+      route_unlock_node (node);
+      return next;
+    }
+  if (node->l_right)
+    {
+      next = node->l_right;
+      route_lock_node (next);
+      route_unlock_node (node);
+      return next;
+    }
+
+  start = node;
+  while (node->parent && node != limit)
+    {
+      if (node->parent->l_left == node && node->parent->l_right)
+	{
+	  next = node->parent->l_right;
+	  route_lock_node (next);
+	  route_unlock_node (start);
+	  return next;
+	}
+      node = node->parent;
+    }
+  route_unlock_node (start);
+  return NULL;
+}
diff --git a/lib/table.h b/lib/table.h
new file mode 100644
index 0000000..6f09099
--- /dev/null
+++ b/lib/table.h
@@ -0,0 +1,74 @@
+/*
+ * Routing Table
+ * Copyright (C) 1998 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 _ZEBRA_TABLE_H
+#define _ZEBRA_TABLE_H
+
+/* Routing table top structure. */
+struct route_table
+{
+  struct route_node *top;
+};
+
+/* Each routing entry. */
+struct route_node
+{
+  /* Actual prefix of this radix. */
+  struct prefix p;
+
+  /* Tree link. */
+  struct route_table *table;
+  struct route_node *parent;
+  struct route_node *link[2];
+#define l_left   link[0]
+#define l_right  link[1]
+
+  /* Lock of this radix */
+  unsigned int lock;
+
+  /* Each node of route. */
+  void *info;
+
+  /* Aggregation. */
+  void *aggregate;
+};
+
+/* Prototypes. */
+struct route_table *route_table_init (void);
+void route_table_finish (struct route_table *);
+void route_unlock_node (struct route_node *node);
+void route_node_delete (struct route_node *node);
+struct route_node *route_top (struct route_table *);
+struct route_node *route_next (struct route_node *);
+struct route_node *route_next_until (struct route_node *, struct route_node *);
+struct route_node *route_node_get (struct route_table *, struct prefix *);
+struct route_node *route_node_lookup (struct route_table *, struct prefix *);
+struct route_node *route_lock_node (struct route_node *node);
+struct route_node *route_node_match (struct route_table *, struct prefix *);
+struct route_node *route_node_match_ipv4 (struct route_table *,
+					  struct in_addr *);
+#ifdef HAVE_IPV6
+struct route_node *route_node_match_ipv6 (struct route_table *,
+					  struct in6_addr *);
+#endif /* HAVE_IPV6 */
+
+#endif /* _ZEBRA_TABLE_H */
diff --git a/lib/tcpfilter.c b/lib/tcpfilter.c
new file mode 100644
index 0000000..4895ab5
--- /dev/null
+++ b/lib/tcpfilter.c
@@ -0,0 +1,69 @@
+/* Route filtering function for TCP and UDP.
+ * 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.
+ */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "prefix.h"
+
+#define FILTER_TYPE_IP   1
+#define FILTER_TYPE_TCP  2
+#define FILTER_TYPE_UDP  3
+
+DEFUN (al_tcp_filter,
+       al_tcp_filter_cmd,
+       "access-list WORD (deny|permit) tcp (A.B.C.D/M|any) (A.B.C.D/M|any)",
+       "Add an access list entry\n"
+       "Access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Transmission Control Protocol\n"
+       "Source address prefix\n"
+       "Any source host\n"
+       "Destination address prefix\n"
+       "Any destination host\n")
+{
+  return CMD_SUCCESS;
+}
+
+DEFUN (al_tcp_filter_eq,
+       al_tcp_filter_eq_cmd,
+       "access-list WORD (deny|permit) tcp (A.B.C.D/M|any) (A.B.C.D/M|any) eq <0-65535>",
+       "Add an access list entry\n"
+       "Access-list name\n"
+       "Specify packets to reject\n"
+       "Specify packets to forward\n"
+       "Transmission Control Protocol\n"
+       "Source address prefix\n"
+       "Any source host\n"
+       "Destination address prefix\n"
+       "Any destination host\n"
+       "Port number\n")
+{
+  return CMD_SUCCESS;
+}
+
+void
+tcpfilter_init ()
+{
+  install_element (CONFIG_NODE, &al_tcp_filter_cmd);
+  install_element (CONFIG_NODE, &al_tcp_filter_eq_cmd);
+}
diff --git a/lib/tcpfilter.h b/lib/tcpfilter.h
new file mode 100644
index 0000000..c3d3008
--- /dev/null
+++ b/lib/tcpfilter.h
@@ -0,0 +1,21 @@
+/* Route filtering function for TCP and UDP.
+ * 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.
+ */
+
diff --git a/lib/thread.c b/lib/thread.c
new file mode 100644
index 0000000..31bbcd7
--- /dev/null
+++ b/lib/thread.c
@@ -0,0 +1,668 @@
+/* Thread management routine
+ * Copyright (C) 1998, 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
+ *
+ * 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.  
+ */
+
+/* #define DEBUG */
+
+#include <zebra.h>
+
+#include "thread.h"
+#include "memory.h"
+#include "log.h"
+
+/* Struct timeval's tv_usec one second value.  */
+#define TIMER_SECOND_MICRO 1000000L
+
+struct timeval
+timeval_adjust (struct timeval a)
+{
+  while (a.tv_usec >= TIMER_SECOND_MICRO)
+    {
+      a.tv_usec -= TIMER_SECOND_MICRO;
+      a.tv_sec++;
+    }
+
+  while (a.tv_usec < 0)
+    {
+      a.tv_usec += TIMER_SECOND_MICRO;
+      a.tv_sec--;
+    }
+
+  if (a.tv_sec < 0)
+    {
+      a.tv_sec = 0;
+      a.tv_usec = 10;
+    }
+
+  if (a.tv_sec > TIMER_SECOND_MICRO)
+    a.tv_sec = TIMER_SECOND_MICRO;    
+
+  return a;
+}
+
+static struct timeval
+timeval_subtract (struct timeval a, struct timeval b)
+{
+  struct timeval ret;
+
+  ret.tv_usec = a.tv_usec - b.tv_usec;
+  ret.tv_sec = a.tv_sec - b.tv_sec;
+
+  return timeval_adjust (ret);
+}
+
+static int
+timeval_cmp (struct timeval a, struct timeval b)
+{
+  return (a.tv_sec == b.tv_sec
+	  ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
+}
+
+static unsigned long
+timeval_elapsed (struct timeval a, struct timeval b)
+{
+  return (((a.tv_sec - b.tv_sec) * TIMER_SECOND_MICRO)
+	  + (a.tv_usec - b.tv_usec));
+}
+
+/* List allocation and head/tail print out. */
+static void
+thread_list_debug (struct thread_list *list)
+{
+  printf ("count [%d] head [%p] tail [%p]\n",
+	  list->count, list->head, list->tail);
+}
+
+/* Debug print for thread_master. */
+void
+thread_master_debug (struct thread_master *m)
+{
+  printf ("-----------\n");
+  printf ("readlist  : ");
+  thread_list_debug (&m->read);
+  printf ("writelist : ");
+  thread_list_debug (&m->write);
+  printf ("timerlist : ");
+  thread_list_debug (&m->timer);
+  printf ("eventlist : ");
+  thread_list_debug (&m->event);
+  printf ("unuselist : ");
+  thread_list_debug (&m->unuse);
+  printf ("total alloc: [%ld]\n", m->alloc);
+  printf ("-----------\n");
+}
+
+/* Allocate new thread master.  */
+struct thread_master *
+thread_master_create ()
+{
+  return (struct thread_master *) XCALLOC (MTYPE_THREAD_MASTER,
+					   sizeof (struct thread_master));
+}
+
+/* Add a new thread to the list.  */
+static void
+thread_list_add (struct thread_list *list, struct thread *thread)
+{
+  thread->next = NULL;
+  thread->prev = list->tail;
+  if (list->tail)
+    list->tail->next = thread;
+  else
+    list->head = thread;
+  list->tail = thread;
+  list->count++;
+}
+
+/* Add a new thread just before the point.  */
+static void
+thread_list_add_before (struct thread_list *list, 
+			struct thread *point, 
+			struct thread *thread)
+{
+  thread->next = point;
+  thread->prev = point->prev;
+  if (point->prev)
+    point->prev->next = thread;
+  else
+    list->head = thread;
+  point->prev = thread;
+  list->count++;
+}
+
+/* Delete a thread from the list. */
+static struct thread *
+thread_list_delete (struct thread_list *list, struct thread *thread)
+{
+  if (thread->next)
+    thread->next->prev = thread->prev;
+  else
+    list->tail = thread->prev;
+  if (thread->prev)
+    thread->prev->next = thread->next;
+  else
+    list->head = thread->next;
+  thread->next = thread->prev = NULL;
+  list->count--;
+  return thread;
+}
+
+/* Move thread to unuse list. */
+static void
+thread_add_unuse (struct thread_master *m, struct thread *thread)
+{
+  assert (m != NULL);
+  assert (thread->next == NULL);
+  assert (thread->prev == NULL);
+  assert (thread->type == THREAD_UNUSED);
+  thread_list_add (&m->unuse, thread);
+}
+
+/* Free all unused thread. */
+static void
+thread_list_free (struct thread_master *m, struct thread_list *list)
+{
+  struct thread *t;
+  struct thread *next;
+
+  for (t = list->head; t; t = next)
+    {
+      next = t->next;
+      XFREE (MTYPE_THREAD, t);
+      list->count--;
+      m->alloc--;
+    }
+}
+
+/* Stop thread scheduler. */
+void
+thread_master_free (struct thread_master *m)
+{
+  thread_list_free (m, &m->read);
+  thread_list_free (m, &m->write);
+  thread_list_free (m, &m->timer);
+  thread_list_free (m, &m->event);
+  thread_list_free (m, &m->ready);
+  thread_list_free (m, &m->unuse);
+
+  XFREE (MTYPE_THREAD_MASTER, m);
+}
+
+/* Delete top of the list and return it. */
+static struct thread *
+thread_trim_head (struct thread_list *list)
+{
+  if (list->head)
+    return thread_list_delete (list, list->head);
+  return NULL;
+}
+
+/* Thread list is empty or not.  */
+int
+thread_empty (struct thread_list *list)
+{
+  return  list->head ? 0 : 1;
+}
+
+/* Return remain time in second. */
+unsigned long
+thread_timer_remain_second (struct thread *thread)
+{
+  struct timeval timer_now;
+
+  gettimeofday (&timer_now, NULL);
+
+  if (thread->u.sands.tv_sec - timer_now.tv_sec > 0)
+    return thread->u.sands.tv_sec - timer_now.tv_sec;
+  else
+    return 0;
+}
+
+/* Get new thread.  */
+static struct thread *
+thread_get (struct thread_master *m, u_char type,
+	    int (*func) (struct thread *), void *arg)
+{
+  struct thread *thread;
+
+  if (m->unuse.head)
+    thread = thread_trim_head (&m->unuse);
+  else
+    {
+      thread = XCALLOC (MTYPE_THREAD, sizeof (struct thread));
+      m->alloc++;
+    }
+  thread->type = type;
+  thread->master = m;
+  thread->func = func;
+  thread->arg = arg;
+  
+  return thread;
+}
+
+/* Add new read thread. */
+struct thread *
+thread_add_read (struct thread_master *m, 
+		 int (*func) (struct thread *), void *arg, int fd)
+{
+  struct thread *thread;
+
+  assert (m != NULL);
+
+  if (FD_ISSET (fd, &m->readfd))
+    {
+      zlog (NULL, LOG_WARNING, "There is already read fd [%d]", fd);
+      return NULL;
+    }
+
+  thread = thread_get (m, THREAD_READ, func, arg);
+  FD_SET (fd, &m->readfd);
+  thread->u.fd = fd;
+  thread_list_add (&m->read, thread);
+
+  return thread;
+}
+
+/* Add new write thread. */
+struct thread *
+thread_add_write (struct thread_master *m,
+		 int (*func) (struct thread *), void *arg, int fd)
+{
+  struct thread *thread;
+
+  assert (m != NULL);
+
+  if (FD_ISSET (fd, &m->writefd))
+    {
+      zlog (NULL, LOG_WARNING, "There is already write fd [%d]", fd);
+      return NULL;
+    }
+
+  thread = thread_get (m, THREAD_WRITE, func, arg);
+  FD_SET (fd, &m->writefd);
+  thread->u.fd = fd;
+  thread_list_add (&m->write, thread);
+
+  return thread;
+}
+
+/* Add timer event thread. */
+struct thread *
+thread_add_timer (struct thread_master *m,
+		  int (*func) (struct thread *), void *arg, long timer)
+{
+  struct timeval timer_now;
+  struct thread *thread;
+#ifndef TIMER_NO_SORT
+  struct thread *tt;
+#endif /* TIMER_NO_SORT */
+
+  assert (m != NULL);
+
+  thread = thread_get (m, THREAD_TIMER, func, arg);
+
+  /* Do we need jitter here? */
+  gettimeofday (&timer_now, NULL);
+  timer_now.tv_sec += timer;
+  thread->u.sands = timer_now;
+
+  /* Sort by timeval. */
+#ifdef TIMER_NO_SORT
+  thread_list_add (&m->timer, thread);
+#else
+  for (tt = m->timer.head; tt; tt = tt->next)
+    if (timeval_cmp (thread->u.sands, tt->u.sands) <= 0)
+      break;
+
+  if (tt)
+    thread_list_add_before (&m->timer, tt, thread);
+  else
+    thread_list_add (&m->timer, thread);
+#endif /* TIMER_NO_SORT */
+
+  return thread;
+}
+
+/* Add simple event thread. */
+struct thread *
+thread_add_event (struct thread_master *m,
+		  int (*func) (struct thread *), void *arg, int val)
+{
+  struct thread *thread;
+
+  assert (m != NULL);
+
+  thread = thread_get (m, THREAD_EVENT, func, arg);
+  thread->u.val = val;
+  thread_list_add (&m->event, thread);
+
+  return thread;
+}
+
+/* Cancel thread from scheduler. */
+void
+thread_cancel (struct thread *thread)
+{
+  switch (thread->type)
+    {
+    case THREAD_READ:
+      assert (FD_ISSET (thread->u.fd, &thread->master->readfd));
+      FD_CLR (thread->u.fd, &thread->master->readfd);
+      thread_list_delete (&thread->master->read, thread);
+      break;
+    case THREAD_WRITE:
+      assert (FD_ISSET (thread->u.fd, &thread->master->writefd));
+      FD_CLR (thread->u.fd, &thread->master->writefd);
+      thread_list_delete (&thread->master->write, thread);
+      break;
+    case THREAD_TIMER:
+      thread_list_delete (&thread->master->timer, thread);
+      break;
+    case THREAD_EVENT:
+      thread_list_delete (&thread->master->event, thread);
+      break;
+    case THREAD_READY:
+      thread_list_delete (&thread->master->ready, thread);
+      break;
+    default:
+      break;
+    }
+  thread->type = THREAD_UNUSED;
+  thread_add_unuse (thread->master, thread);
+}
+
+/* Delete all events which has argument value arg. */
+void
+thread_cancel_event (struct thread_master *m, void *arg)
+{
+  struct thread *thread;
+
+  thread = m->event.head;
+  while (thread)
+    {
+      struct thread *t;
+
+      t = thread;
+      thread = t->next;
+
+      if (t->arg == arg)
+	{
+	  thread_list_delete (&m->event, t);
+	  t->type = THREAD_UNUSED;
+	  thread_add_unuse (m, t);
+	}
+    }
+}
+
+#ifdef TIMER_NO_SORT
+struct timeval *
+thread_timer_wait (struct thread_master *m, struct timeval *timer_val)
+{
+  struct timeval timer_now;
+  struct timeval timer_min;
+  struct timeval *timer_wait;
+
+  gettimeofday (&timer_now, NULL);
+
+  timer_wait = NULL;
+  for (thread = m->timer.head; thread; thread = thread->next)
+    {
+      if (! timer_wait)
+	timer_wait = &thread->u.sands;
+      else if (timeval_cmp (thread->u.sands, *timer_wait) < 0)
+	timer_wait = &thread->u.sands;
+    }
+
+  if (m->timer.head)
+    {
+      timer_min = *timer_wait;
+      timer_min = timeval_subtract (timer_min, timer_now);
+      if (timer_min.tv_sec < 0)
+	{
+	  timer_min.tv_sec = 0;
+	  timer_min.tv_usec = 10;
+	}
+      timer_wait = &timer_min;
+    }
+  else
+    timer_wait = NULL;
+
+  if (timer_wait)
+    {
+      *timer_val = timer_wait;
+      return timer_val;
+    }
+  return NULL;
+}
+#else /* ! TIMER_NO_SORT */
+struct timeval *
+thread_timer_wait (struct thread_master *m, struct timeval *timer_val)
+{
+  struct timeval timer_now;
+  struct timeval timer_min;
+
+  if (m->timer.head)
+    {
+      gettimeofday (&timer_now, NULL);
+      timer_min = m->timer.head->u.sands;
+      timer_min = timeval_subtract (timer_min, timer_now);
+      if (timer_min.tv_sec < 0)
+	{
+	  timer_min.tv_sec = 0;
+	  timer_min.tv_usec = 10;
+	}
+      *timer_val = timer_min;
+      return timer_val;
+    }
+  return NULL;
+}
+#endif /* TIMER_NO_SORT */
+
+struct thread *
+thread_run (struct thread_master *m, struct thread *thread,
+	    struct thread *fetch)
+{
+  *fetch = *thread;
+  thread->type = THREAD_UNUSED;
+  thread_add_unuse (m, thread);
+  return fetch;
+}
+
+int
+thread_process_fd (struct thread_master *m, struct thread_list *list,
+		   fd_set *fdset, fd_set *mfdset)
+{
+  struct thread *thread;
+  struct thread *next;
+  int ready = 0;
+
+  for (thread = list->head; thread; thread = next)
+    {
+      next = thread->next;
+
+      if (FD_ISSET (THREAD_FD (thread), fdset))
+	{
+	  assert (FD_ISSET (THREAD_FD (thread), mfdset));
+	  FD_CLR(THREAD_FD (thread), mfdset);
+	  thread_list_delete (list, thread);
+	  thread_list_add (&m->ready, thread);
+	  thread->type = THREAD_READY;
+	  ready++;
+	}
+    }
+  return ready;
+}
+
+/* Fetch next ready thread. */
+struct thread *
+thread_fetch (struct thread_master *m, struct thread *fetch)
+{
+  int num;
+  int ready;
+  struct thread *thread;
+  fd_set readfd;
+  fd_set writefd;
+  fd_set exceptfd;
+  struct timeval timer_now;
+  struct timeval timer_val;
+  struct timeval *timer_wait;
+  struct timeval timer_nowait;
+
+  timer_nowait.tv_sec = 0;
+  timer_nowait.tv_usec = 0;
+
+  while (1)
+    {
+      /* Normal event is the highest priority.  */
+      if ((thread = thread_trim_head (&m->event)) != NULL)
+	return thread_run (m, thread, fetch);
+
+      /* Execute timer.  */
+      gettimeofday (&timer_now, NULL);
+
+      for (thread = m->timer.head; thread; thread = thread->next)
+	if (timeval_cmp (timer_now, thread->u.sands) >= 0)
+	  {
+	    thread_list_delete (&m->timer, thread);
+	    return thread_run (m, thread, fetch);
+	  }
+
+      /* If there are any ready threads, process top of them.  */
+      if ((thread = thread_trim_head (&m->ready)) != NULL)
+	return thread_run (m, thread, fetch);
+
+      /* Structure copy.  */
+      readfd = m->readfd;
+      writefd = m->writefd;
+      exceptfd = m->exceptfd;
+
+      /* Calculate select wait timer. */
+      timer_wait = thread_timer_wait (m, &timer_val);
+
+      num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
+
+      if (num == 0)
+	continue;
+
+      if (num < 0)
+	{
+	  if (errno == EINTR)
+	    continue;
+
+	  zlog_warn ("select() error: %s", strerror (errno));
+	  return NULL;
+	}
+
+      /* Normal priority read thead. */
+      ready = thread_process_fd (m, &m->read, &readfd, &m->readfd);
+
+      /* Write thead. */
+      ready = thread_process_fd (m, &m->write, &writefd, &m->writefd);
+
+      if ((thread = thread_trim_head (&m->ready)) != NULL)
+	return thread_run (m, thread, fetch);
+    }
+}
+
+static unsigned long
+thread_consumed_time (RUSAGE_T *now, RUSAGE_T *start)
+{
+  unsigned long thread_time;
+
+#ifdef HAVE_RUSAGE
+  /* This is 'user + sys' time.  */
+  thread_time = timeval_elapsed (now->ru_utime, start->ru_utime);
+  thread_time += timeval_elapsed (now->ru_stime, start->ru_stime);
+#else
+  /* When rusage is not available, simple elapsed time is used.  */
+  thread_time = timeval_elapsed (*now, *start);
+#endif /* HAVE_RUSAGE */
+
+  return thread_time;
+}
+
+/* We should aim to yield after THREAD_YIELD_TIME_SLOT
+   milliseconds.  */
+int
+thread_should_yield (struct thread *thread)
+{
+  RUSAGE_T ru;
+
+  GETRUSAGE (&ru);
+
+  if (thread_consumed_time (&ru, &thread->ru) > THREAD_YIELD_TIME_SLOT)
+    return 1;
+  else
+    return 0;
+}
+
+/* We check thread consumed time. If the system has getrusage, we'll
+   use that to get indepth stats on the performance of the thread.  If
+   not - we'll use gettimeofday for some guestimation.  */
+void
+thread_call (struct thread *thread)
+{
+  unsigned long thread_time;
+  RUSAGE_T ru;
+
+  GETRUSAGE (&thread->ru);
+
+  (*thread->func) (thread);
+
+  GETRUSAGE (&ru);
+
+  thread_time = thread_consumed_time (&ru, &thread->ru);
+
+#ifdef THREAD_CONSUMED_TIME_CHECK
+  if (thread_time > 200000L)
+    {
+      /*
+       * We have a CPU Hog on our hands.
+       * Whinge about it now, so we're aware this is yet another task
+       * to fix.
+       */
+      zlog_err ("CPU HOG task %lx ran for %ldms",
+                /* FIXME: report the name of the function somehow */
+		(unsigned long) thread->func,
+		thread_time / 1000L);
+    }
+#endif /* THREAD_CONSUMED_TIME_CHECK */
+}
+
+/* Execute thread */
+struct thread *
+thread_execute (struct thread_master *m,
+                int (*func)(struct thread *), 
+                void *arg,
+                int val)
+{
+  struct thread dummy; 
+
+  memset (&dummy, 0, sizeof (struct thread));
+
+  dummy.type = THREAD_EVENT;
+  dummy.master = NULL;
+  dummy.func = func;
+  dummy.arg = arg;
+  dummy.u.val = val;
+  thread_call (&dummy);
+
+  return NULL;
+}
diff --git a/lib/thread.h b/lib/thread.h
new file mode 100644
index 0000000..9de62cd
--- /dev/null
+++ b/lib/thread.h
@@ -0,0 +1,139 @@
+/* Thread management routine header.
+ * Copyright (C) 1998 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 _ZEBRA_THREAD_H
+#define _ZEBRA_THREAD_H
+
+#ifdef HAVE_RUSAGE
+#define RUSAGE_T        struct rusage
+#define GETRUSAGE(X)    getrusage (RUSAGE_SELF, X);
+#else
+#define RUSAGE_T        struct timeval
+#define GETRUSAGE(X)    gettimeofday (X, NULL);
+#endif /* HAVE_RUSAGE */
+
+/* Linked list of thread. */
+struct thread_list
+{
+  struct thread *head;
+  struct thread *tail;
+  int count;
+};
+
+/* Master of the theads. */
+struct thread_master
+{
+  struct thread_list read;
+  struct thread_list write;
+  struct thread_list timer;
+  struct thread_list event;
+  struct thread_list ready;
+  struct thread_list unuse;
+  fd_set readfd;
+  fd_set writefd;
+  fd_set exceptfd;
+  unsigned long alloc;
+};
+
+/* Thread itself. */
+struct thread
+{
+  unsigned char type;		/* thread type */
+  struct thread *next;		/* next pointer of the thread */
+  struct thread *prev;		/* previous pointer of the thread */
+  struct thread_master *master;	/* pointer to the struct thread_master. */
+  int (*func) (struct thread *); /* event function */
+  void *arg;			/* event argument */
+  union {
+    int val;			/* second argument of the event. */
+    int fd;			/* file descriptor in case of read/write. */
+    struct timeval sands;	/* rest of time sands value. */
+  } u;
+  RUSAGE_T ru;			/* Indepth usage info.  */
+};
+
+/* Thread types. */
+#define THREAD_READ           0
+#define THREAD_WRITE          1
+#define THREAD_TIMER          2
+#define THREAD_EVENT          3
+#define THREAD_READY          4
+#define THREAD_UNUSED         5
+
+/* Thread yield time.  */
+#define THREAD_YIELD_TIME_SLOT     100 * 1000L /* 100ms */
+
+/* Macros. */
+#define THREAD_ARG(X) ((X)->arg)
+#define THREAD_FD(X)  ((X)->u.fd)
+#define THREAD_VAL(X) ((X)->u.val)
+
+#define THREAD_READ_ON(master,thread,func,arg,sock) \
+  do { \
+    if (! thread) \
+      thread = thread_add_read (master, func, arg, sock); \
+  } while (0)
+
+#define THREAD_WRITE_ON(master,thread,func,arg,sock) \
+  do { \
+    if (! thread) \
+      thread = thread_add_write (master, func, arg, sock); \
+  } while (0)
+
+#define THREAD_TIMER_ON(master,thread,func,arg,time) \
+  do { \
+    if (! thread) \
+      thread = thread_add_timer (master, func, arg, time); \
+  } while (0)
+
+#define THREAD_OFF(thread) \
+  do { \
+    if (thread) \
+      { \
+        thread_cancel (thread); \
+        thread = NULL; \
+      } \
+  } while (0)
+
+#define THREAD_READ_OFF(thread)  THREAD_OFF(thread)
+#define THREAD_WRITE_OFF(thread)  THREAD_OFF(thread)
+#define THREAD_TIMER_OFF(thread)  THREAD_OFF(thread)
+
+/* Prototypes. */
+struct thread_master *thread_master_create ();
+struct thread *thread_add_read (struct thread_master *, 
+				int (*)(struct thread *), void *, int);
+struct thread *thread_add_write (struct thread_master *,
+				 int (*)(struct thread *), void *, int);
+struct thread *thread_add_timer (struct thread_master *,
+				 int (*)(struct thread *), void *, long);
+struct thread *thread_add_event (struct thread_master *,
+				 int (*)(struct thread *), void *, int );
+void thread_cancel (struct thread *);
+void thread_cancel_event (struct thread_master *, void *);
+
+struct thread *thread_fetch (struct thread_master *, struct thread *);
+struct thread *thread_execute (struct thread_master *,
+			       int (*)(struct thread *), void *, int);
+void thread_call (struct thread *);
+unsigned long thread_timer_remain_second (struct thread *);
+
+#endif /* _ZEBRA_THREAD_H */
diff --git a/lib/vector.c b/lib/vector.c
new file mode 100644
index 0000000..31cdc77
--- /dev/null
+++ b/lib/vector.c
@@ -0,0 +1,189 @@
+/* Generic vector interface routine
+ * Copyright (C) 1997 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.  
+ */
+
+#include <zebra.h>
+
+#include "vector.h"
+#include "memory.h"
+
+/* Initialize vector : allocate memory and return vector. */
+vector
+vector_init (unsigned int size)
+{
+  vector v = XCALLOC (MTYPE_VECTOR, sizeof (struct _vector));
+
+  /* allocate at least one slot */
+  if (size == 0)
+    size = 1;
+
+  v->alloced = size;
+  v->max = 0;
+  v->index = XCALLOC (MTYPE_VECTOR_INDEX, sizeof (void *) * size);
+  return v;
+}
+
+void
+vector_only_wrapper_free (vector v)
+{
+  XFREE (MTYPE_VECTOR, v);
+}
+
+void
+vector_only_index_free (void *index)
+{
+  XFREE (MTYPE_VECTOR_INDEX, index);
+}
+
+void
+vector_free (vector v)
+{
+  XFREE (MTYPE_VECTOR_INDEX, v->index);
+  XFREE (MTYPE_VECTOR, v);
+}
+
+vector
+vector_copy (vector v)
+{
+  unsigned int size;
+  vector new = XCALLOC (MTYPE_VECTOR, sizeof (struct _vector));
+
+  new->max = v->max;
+  new->alloced = v->alloced;
+
+  size = sizeof (void *) * (v->alloced);
+  new->index = XCALLOC (MTYPE_VECTOR_INDEX, size);
+  memcpy (new->index, v->index, size);
+
+  return new;
+}
+
+/* Check assigned index, and if it runs short double index pointer */
+void
+vector_ensure (vector v, unsigned int num)
+{
+  if (v->alloced > num)
+    return;
+
+  v->index = XREALLOC (MTYPE_VECTOR_INDEX, 
+		       v->index, sizeof (void *) * (v->alloced * 2));
+  memset (&v->index[v->alloced], 0, sizeof (void *) * v->alloced);
+  v->alloced *= 2;
+  
+  if (v->alloced <= num)
+    vector_ensure (v, num);
+}
+
+/* This function only returns next empty slot index.  It dose not mean
+   the slot's index memory is assigned, please call vector_ensure()
+   after calling this function. */
+int
+vector_empty_slot (vector v)
+{
+  unsigned int i;
+
+  if (v->max == 0)
+    return 0;
+
+  for (i = 0; i < v->max; i++)
+    if (v->index[i] == 0)
+      return i;
+
+  return i;
+}
+
+/* Set value to the smallest empty slot. */
+int
+vector_set (vector v, void *val)
+{
+  unsigned int i;
+
+  i = vector_empty_slot (v);
+  vector_ensure (v, i);
+
+  v->index[i] = val;
+
+  if (v->max <= i)
+    v->max = i + 1;
+
+  return i;
+}
+
+/* Set value to specified index slot. */
+int
+vector_set_index (vector v, unsigned int i, void *val)
+{
+  vector_ensure (v, i);
+
+  v->index[i] = val;
+
+  if (v->max <= i)
+    v->max = i + 1;
+
+  return i;
+}
+
+/* Look up vector.  */
+void *
+vector_lookup (vector v, unsigned int i)
+{
+  if (i >= v->max)
+    return NULL;
+  return v->index[i];
+}
+
+/* Lookup vector, ensure it. */
+void *
+vector_lookup_ensure (vector v, unsigned int i)
+{
+  vector_ensure (v, i);
+  return v->index[i];
+}
+
+/* Unset value at specified index slot. */
+void
+vector_unset (vector v, unsigned int i)
+{
+  if (i >= v->alloced)
+    return;
+
+  v->index[i] = NULL;
+
+  if (i + 1 == v->max) 
+    {
+      v->max--;
+      while (i && v->index[--i] == NULL && v->max--) 
+	;				/* Is this ugly ? */
+    }
+}
+
+/* Count the number of not emplty slot. */
+unsigned int
+vector_count (vector v)
+{
+  unsigned int i;
+  unsigned count = 0;
+
+  for (i = 0; i < v->max; i++) 
+    if (v->index[i] != NULL)
+      count++;
+
+  return count;
+}
diff --git a/lib/vector.h b/lib/vector.h
new file mode 100644
index 0000000..7e00c39
--- /dev/null
+++ b/lib/vector.h
@@ -0,0 +1,58 @@
+/*
+ * Generic vector interface header.
+ * Copyright (C) 1997, 98 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 _ZEBRA_VECTOR_H
+#define _ZEBRA_VECTOR_H
+
+/* struct for vector */
+struct _vector 
+{
+  unsigned int max;		/* max number of used slot */
+  unsigned int alloced;		/* number of allocated slot */
+  void **index;			/* index to data */
+};
+typedef struct _vector *vector;
+
+#define VECTOR_MIN_SIZE 1
+
+/* (Sometimes) usefull macros.  This macro convert index expression to
+ array expression. */
+#define vector_slot(V,I)  ((V)->index[(I)])
+#define vector_max(V) ((V)->max)
+
+/* Prototypes. */
+vector vector_init (unsigned int size);
+void vector_ensure (vector v, unsigned int num);
+int vector_empty_slot (vector v);
+int vector_set (vector v, void *val);
+int vector_set_index (vector v, unsigned int i, void *val);
+void vector_unset (vector v, unsigned int i);
+unsigned int vector_count (vector v);
+void vector_only_wrapper_free (vector v);
+void vector_only_index_free (void *index);
+void vector_free (vector v);
+vector vector_copy (vector v);
+
+void *vector_lookup (vector, unsigned int);
+void *vector_lookup_ensure (vector, unsigned int);
+
+#endif /* _ZEBRA_VECTOR_H */
diff --git a/lib/version.h b/lib/version.h
new file mode 100644
index 0000000..9a90bf4
--- /dev/null
+++ b/lib/version.h
@@ -0,0 +1,39 @@
+/* Zebra version
+ * Copyright (C) 1997, 1999 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 _ZEBRA_VERSION_H
+#define _ZEBRA_VERSION_H
+
+#define ZEBRA_VERSION     "0.93b"
+
+#define ZEBRA_BUG_ADDRESS "bug-zebra@gnu.org"
+
+extern char *host_name;
+
+void print_version(char *);
+pid_t pid_output (char *);
+pid_t pid_output_lock (char *);
+
+#ifndef HAVE_DAEMON
+int daemon(int, int);
+#endif
+
+#endif /* _ZEBRA_VERSION_H */
diff --git a/lib/vty.c b/lib/vty.c
new file mode 100644
index 0000000..d31521c
--- /dev/null
+++ b/lib/vty.c
@@ -0,0 +1,2792 @@
+/*
+ * Virtual terminal [aka TeletYpe] interface routine.
+ * Copyright (C) 1997, 98 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.  
+ */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "buffer.h"
+#include "version.h"
+#include "command.h"
+#include "sockunion.h"
+#include "thread.h"
+#include "memory.h"
+#include "str.h"
+#include "log.h"
+#include "prefix.h"
+#include "filter.h"
+
+/* Vty events */
+enum event 
+{
+  VTY_SERV,
+  VTY_READ,
+  VTY_WRITE,
+  VTY_TIMEOUT_RESET,
+#ifdef VTYSH
+  VTYSH_SERV,
+  VTYSH_READ
+#endif /* VTYSH */
+};
+
+static void vty_event (enum event, int, struct vty *);
+
+/* Extern host structure from command.c */
+extern struct host host;
+
+/* Vector which store each vty structure. */
+static vector vtyvec;
+
+/* Vty timeout value. */
+static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT;
+
+/* Vty access-class command */
+static char *vty_accesslist_name = NULL;
+
+/* Vty access-calss for IPv6. */
+static char *vty_ipv6_accesslist_name = NULL;
+
+/* VTY server thread. */
+vector Vvty_serv_thread;
+
+/* Current directory. */
+char *vty_cwd = NULL;
+
+/* Configure lock. */
+static int vty_config;
+
+/* Login password check. */
+static int no_password_check = 0;
+
+/* Integrated configuration file path */
+char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
+
+
+/* VTY standard output function. */
+int
+vty_out (struct vty *vty, const char *format, ...)
+{
+  va_list args;
+  int len = 0;
+  int size = 1024;
+  char buf[1024];
+  char *p = NULL;
+  
+  va_start (args, format);
+
+  if (vty_shell (vty))
+    vprintf (format, args);
+  else
+    {
+      /* Try to write to initial buffer.  */
+      len = vsnprintf (buf, sizeof buf, format, args);
+
+      /* Initial buffer is not enough.  */
+      if (len < 0 || len >= size)
+	{
+	  while (1)
+	    {
+	      if (len > -1)
+		size = len + 1;
+	      else
+		size = size * 2;
+
+	      p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size);
+	      if (! p)
+		return -1;
+
+	      len = vsnprintf (p, size, format, args);
+
+	      if (len > -1 && len < size)
+		break;
+	    }
+	}
+
+      /* When initial buffer is enough to store all output.  */
+      if (! p)
+	p = buf;
+
+      /* Pointer p must point out buffer. */
+      if (vty_shell_serv (vty))
+	write (vty->fd, (u_char *) p, len);
+      else
+	buffer_write (vty->obuf, (u_char *) p, len);
+
+      /* If p is not different with buf, it is allocated buffer.  */
+      if (p != buf)
+	XFREE (MTYPE_VTY_OUT_BUF, p);
+    }
+
+  va_end (args);
+
+  return len;
+}
+
+int
+vty_log_out (struct vty *vty, const char *proto_str, const char *format,
+	     va_list va)
+{
+  int len;
+  char buf[1024];
+
+  snprintf (buf, sizeof buf, "%s: ", proto_str);
+  write (vty->fd, buf, strlen (proto_str) + 2);
+
+  len = vsnprintf (buf, sizeof buf, format, va);
+  if (len < 0)
+    return -1;
+  write (vty->fd, (u_char *)buf, len);
+
+  snprintf (buf, sizeof buf, "\r\n");
+  write (vty->fd, buf, 2);
+
+  return len;
+}
+
+/* Output current time to the vty. */
+void
+vty_time_print (struct vty *vty, int cr)
+{
+  time_t clock;
+  struct tm *tm;
+#define TIME_BUF 25
+  char buf [TIME_BUF];
+  int ret;
+  
+  time (&clock);
+  tm = localtime (&clock);
+
+  ret = strftime (buf, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm);
+  if (ret == 0)
+    {
+      zlog (NULL, LOG_INFO, "strftime error");
+      return;
+    }
+  if (cr)
+    vty_out (vty, "%s\n", buf);
+  else
+    vty_out (vty, "%s ", buf);
+
+  return;
+}
+
+/* Say hello to vty interface. */
+void
+vty_hello (struct vty *vty)
+{
+  if (host.motd)
+    vty_out (vty, host.motd);
+}
+
+/* Put out prompt and wait input from user. */
+static void
+vty_prompt (struct vty *vty)
+{
+  struct utsname names;
+  const char*hostname;
+
+  if (vty->type == VTY_TERM)
+    {
+      hostname = host.name;
+      if (!hostname)
+	{
+	  uname (&names);
+	  hostname = names.nodename;
+	}
+      vty_out (vty, cmd_prompt (vty->node), hostname);
+    }
+}
+
+/* Send WILL TELOPT_ECHO to remote server. */
+void
+vty_will_echo (struct vty *vty)
+{
+  char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' };
+  vty_out (vty, "%s", cmd);
+}
+
+/* Make suppress Go-Ahead telnet option. */
+static void
+vty_will_suppress_go_ahead (struct vty *vty)
+{
+  char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' };
+  vty_out (vty, "%s", cmd);
+}
+
+/* Make don't use linemode over telnet. */
+static void
+vty_dont_linemode (struct vty *vty)
+{
+  char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };
+  vty_out (vty, "%s", cmd);
+}
+
+/* Use window size. */
+static void
+vty_do_window_size (struct vty *vty)
+{
+  char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' };
+  vty_out (vty, "%s", cmd);
+}
+
+#if 0 /* Currently not used. */
+/* Make don't use lflow vty interface. */
+static void
+vty_dont_lflow_ahead (struct vty *vty)
+{
+  char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' };
+  vty_out (vty, "%s", cmd);
+}
+#endif /* 0 */
+
+/* Allocate new vty struct. */
+struct vty *
+vty_new ()
+{
+  struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty));
+
+  new->obuf = (struct buffer *) buffer_new (100);
+  new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ);
+  new->max = VTY_BUFSIZ;
+  new->sb_buffer = NULL;
+
+  return new;
+}
+
+/* Authentication of vty */
+static void
+vty_auth (struct vty *vty, char *buf)
+{
+  char *passwd = NULL;
+  enum node_type next_node = 0;
+  int fail;
+  char *crypt (const char *, const char *);
+
+  switch (vty->node)
+    {
+    case AUTH_NODE:
+      if (host.encrypt)
+	passwd = host.password_encrypt;
+      else
+	passwd = host.password;
+      if (host.advanced)
+	next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
+      else
+	next_node = VIEW_NODE;
+      break;
+    case AUTH_ENABLE_NODE:
+      if (host.encrypt)
+	passwd = host.enable_encrypt;
+      else
+	passwd = host.enable;
+      next_node = ENABLE_NODE;
+      break;
+    }
+
+  if (passwd)
+    {
+      if (host.encrypt)
+	fail = strcmp (crypt(buf, passwd), passwd);
+      else
+	fail = strcmp (buf, passwd);
+    }
+  else
+    fail = 1;
+
+  if (! fail)
+    {
+      vty->fail = 0;
+      vty->node = next_node;	/* Success ! */
+    }
+  else
+    {
+      vty->fail++;
+      if (vty->fail >= 3)
+	{
+	  if (vty->node == AUTH_NODE)
+	    {
+	      vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE);
+	      vty->status = VTY_CLOSE;
+	    }
+	  else			
+	    {
+	      /* AUTH_ENABLE_NODE */
+	      vty->fail = 0;
+	      vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
+	      vty->node = VIEW_NODE;
+	    }
+	}
+    }
+}
+
+/* Command execution over the vty interface. */
+int
+vty_command (struct vty *vty, char *buf)
+{
+  int ret;
+  vector vline;
+
+  /* Split readline string up into the vector */
+  vline = cmd_make_strvec (buf);
+
+  if (vline == NULL)
+    return CMD_SUCCESS;
+
+  ret = cmd_execute_command (vline, vty, NULL);
+
+  if (ret != CMD_SUCCESS)
+    switch (ret)
+      {
+      case CMD_WARNING:
+	if (vty->type == VTY_FILE)
+	  vty_out (vty, "Warning...%s", VTY_NEWLINE);
+	break;
+      case CMD_ERR_AMBIGUOUS:
+	vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
+	break;
+      case CMD_ERR_NO_MATCH:
+	vty_out (vty, "%% Unknown command.%s", VTY_NEWLINE);
+	break;
+      case CMD_ERR_INCOMPLETE:
+	vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
+	break;
+      }
+  cmd_free_strvec (vline);
+
+  return ret;
+}
+
+char telnet_backward_char = 0x08;
+char telnet_space_char = ' ';
+
+/* Basic function to write buffer to vty. */
+static void
+vty_write (struct vty *vty, char *buf, size_t nbytes)
+{
+  if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
+    return;
+
+  /* Should we do buffering here ?  And make vty_flush (vty) ? */
+  buffer_write (vty->obuf, (u_char *)buf, nbytes);
+}
+
+/* Ensure length of input buffer.  Is buffer is short, double it. */
+static void
+vty_ensure (struct vty *vty, int length)
+{
+  if (vty->max <= length)
+    {
+      vty->max *= 2;
+      vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max);
+    }
+}
+
+/* Basic function to insert character into vty. */
+static void
+vty_self_insert (struct vty *vty, char c)
+{
+  int i;
+  int length;
+
+  vty_ensure (vty, vty->length + 1);
+  length = vty->length - vty->cp;
+  memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
+  vty->buf[vty->cp] = c;
+
+  vty_write (vty, &vty->buf[vty->cp], length + 1);
+  for (i = 0; i < length; i++)
+    vty_write (vty, &telnet_backward_char, 1);
+
+  vty->cp++;
+  vty->length++;
+}
+
+/* Self insert character 'c' in overwrite mode. */
+static void
+vty_self_insert_overwrite (struct vty *vty, char c)
+{
+  vty_ensure (vty, vty->length + 1);
+  vty->buf[vty->cp++] = c;
+
+  if (vty->cp > vty->length)
+    vty->length++;
+
+  if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
+    return;
+
+  vty_write (vty, &c, 1);
+}
+
+/* Insert a word into vty interface with overwrite mode. */
+static void
+vty_insert_word_overwrite (struct vty *vty, char *str)
+{
+  int len = strlen (str);
+  vty_write (vty, str, len);
+  strcpy (&vty->buf[vty->cp], str);
+  vty->cp += len;
+  vty->length = vty->cp;
+}
+
+/* Forward character. */
+static void
+vty_forward_char (struct vty *vty)
+{
+  if (vty->cp < vty->length)
+    {
+      vty_write (vty, &vty->buf[vty->cp], 1);
+      vty->cp++;
+    }
+}
+
+/* Backward character. */
+static void
+vty_backward_char (struct vty *vty)
+{
+  if (vty->cp > 0)
+    {
+      vty->cp--;
+      vty_write (vty, &telnet_backward_char, 1);
+    }
+}
+
+/* Move to the beginning of the line. */
+static void
+vty_beginning_of_line (struct vty *vty)
+{
+  while (vty->cp)
+    vty_backward_char (vty);
+}
+
+/* Move to the end of the line. */
+static void
+vty_end_of_line (struct vty *vty)
+{
+  while (vty->cp < vty->length)
+    vty_forward_char (vty);
+}
+
+static void vty_kill_line_from_beginning (struct vty *);
+static void vty_redraw_line (struct vty *);
+
+/* Print command line history.  This function is called from
+   vty_next_line and vty_previous_line. */
+static void
+vty_history_print (struct vty *vty)
+{
+  int length;
+
+  vty_kill_line_from_beginning (vty);
+
+  /* Get previous line from history buffer */
+  length = strlen (vty->hist[vty->hp]);
+  memcpy (vty->buf, vty->hist[vty->hp], length);
+  vty->cp = vty->length = length;
+
+  /* Redraw current line */
+  vty_redraw_line (vty);
+}
+
+/* Show next command line history. */
+void
+vty_next_line (struct vty *vty)
+{
+  int try_index;
+
+  if (vty->hp == vty->hindex)
+    return;
+
+  /* Try is there history exist or not. */
+  try_index = vty->hp;
+  if (try_index == (VTY_MAXHIST - 1))
+    try_index = 0;
+  else
+    try_index++;
+
+  /* If there is not history return. */
+  if (vty->hist[try_index] == NULL)
+    return;
+  else
+    vty->hp = try_index;
+
+  vty_history_print (vty);
+}
+
+/* Show previous command line history. */
+void
+vty_previous_line (struct vty *vty)
+{
+  int try_index;
+
+  try_index = vty->hp;
+  if (try_index == 0)
+    try_index = VTY_MAXHIST - 1;
+  else
+    try_index--;
+
+  if (vty->hist[try_index] == NULL)
+    return;
+  else
+    vty->hp = try_index;
+
+  vty_history_print (vty);
+}
+
+/* This function redraw all of the command line character. */
+static void
+vty_redraw_line (struct vty *vty)
+{
+  vty_write (vty, vty->buf, vty->length);
+  vty->cp = vty->length;
+}
+
+/* Forward word. */
+static void
+vty_forward_word (struct vty *vty)
+{
+  while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
+    vty_forward_char (vty);
+  
+  while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
+    vty_forward_char (vty);
+}
+
+/* Backward word without skipping training space. */
+static void
+vty_backward_pure_word (struct vty *vty)
+{
+  while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
+    vty_backward_char (vty);
+}
+
+/* Backward word. */
+static void
+vty_backward_word (struct vty *vty)
+{
+  while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
+    vty_backward_char (vty);
+
+  while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
+    vty_backward_char (vty);
+}
+
+/* When '^D' is typed at the beginning of the line we move to the down
+   level. */
+static void
+vty_down_level (struct vty *vty)
+{
+  vty_out (vty, "%s", VTY_NEWLINE);
+  config_exit (NULL, vty, 0, NULL);
+  vty_prompt (vty);
+  vty->cp = 0;
+}
+
+/* When '^Z' is received from vty, move down to the enable mode. */
+void
+vty_end_config (struct vty *vty)
+{
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  switch (vty->node)
+    {
+    case VIEW_NODE:
+    case ENABLE_NODE:
+      /* Nothing to do. */
+      break;
+    case CONFIG_NODE:
+    case INTERFACE_NODE:
+    case ZEBRA_NODE:
+    case RIP_NODE:
+    case RIPNG_NODE:
+    case BGP_NODE:
+    case BGP_VPNV4_NODE:
+    case BGP_IPV4_NODE:
+    case BGP_IPV4M_NODE:
+    case BGP_IPV6_NODE:
+    case RMAP_NODE:
+    case OSPF_NODE:
+    case OSPF6_NODE:
+    case KEYCHAIN_NODE:
+    case KEYCHAIN_KEY_NODE:
+    case MASC_NODE:
+    case VTY_NODE:
+      vty_config_unlock (vty);
+      vty->node = ENABLE_NODE;
+      break;
+    default:
+      /* Unknown node, we have to ignore it. */
+      break;
+    }
+
+  vty_prompt (vty);
+  vty->cp = 0;
+}
+
+/* Delete a charcter at the current point. */
+static void
+vty_delete_char (struct vty *vty)
+{
+  int i;
+  int size;
+
+  if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
+    return;
+
+  if (vty->length == 0)
+    {
+      vty_down_level (vty);
+      return;
+    }
+
+  if (vty->cp == vty->length)
+    return;			/* completion need here? */
+
+  size = vty->length - vty->cp;
+
+  vty->length--;
+  memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
+  vty->buf[vty->length] = '\0';
+
+  vty_write (vty, &vty->buf[vty->cp], size - 1);
+  vty_write (vty, &telnet_space_char, 1);
+
+  for (i = 0; i < size; i++)
+    vty_write (vty, &telnet_backward_char, 1);
+}
+
+/* Delete a character before the point. */
+static void
+vty_delete_backward_char (struct vty *vty)
+{
+  if (vty->cp == 0)
+    return;
+
+  vty_backward_char (vty);
+  vty_delete_char (vty);
+}
+
+/* Kill rest of line from current point. */
+static void
+vty_kill_line (struct vty *vty)
+{
+  int i;
+  int size;
+
+  size = vty->length - vty->cp;
+  
+  if (size == 0)
+    return;
+
+  for (i = 0; i < size; i++)
+    vty_write (vty, &telnet_space_char, 1);
+  for (i = 0; i < size; i++)
+    vty_write (vty, &telnet_backward_char, 1);
+
+  memset (&vty->buf[vty->cp], 0, size);
+  vty->length = vty->cp;
+}
+
+/* Kill line from the beginning. */
+static void
+vty_kill_line_from_beginning (struct vty *vty)
+{
+  vty_beginning_of_line (vty);
+  vty_kill_line (vty);
+}
+
+/* Delete a word before the point. */
+static void
+vty_forward_kill_word (struct vty *vty)
+{
+  while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
+    vty_delete_char (vty);
+  while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
+    vty_delete_char (vty);
+}
+
+/* Delete a word before the point. */
+static void
+vty_backward_kill_word (struct vty *vty)
+{
+  while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
+    vty_delete_backward_char (vty);
+  while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
+    vty_delete_backward_char (vty);
+}
+
+/* Transpose chars before or at the point. */
+static void
+vty_transpose_chars (struct vty *vty)
+{
+  char c1, c2;
+
+  /* If length is short or point is near by the beginning of line then
+     return. */
+  if (vty->length < 2 || vty->cp < 1)
+    return;
+
+  /* In case of point is located at the end of the line. */
+  if (vty->cp == vty->length)
+    {
+      c1 = vty->buf[vty->cp - 1];
+      c2 = vty->buf[vty->cp - 2];
+
+      vty_backward_char (vty);
+      vty_backward_char (vty);
+      vty_self_insert_overwrite (vty, c1);
+      vty_self_insert_overwrite (vty, c2);
+    }
+  else
+    {
+      c1 = vty->buf[vty->cp];
+      c2 = vty->buf[vty->cp - 1];
+
+      vty_backward_char (vty);
+      vty_self_insert_overwrite (vty, c1);
+      vty_self_insert_overwrite (vty, c2);
+    }
+}
+
+/* Do completion at vty interface. */
+static void
+vty_complete_command (struct vty *vty)
+{
+  int i;
+  int ret;
+  char **matched = NULL;
+  vector vline;
+
+  if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
+    return;
+
+  vline = cmd_make_strvec (vty->buf);
+  if (vline == NULL)
+    return;
+
+  /* In case of 'help \t'. */
+  if (isspace ((int) vty->buf[vty->length - 1]))
+    vector_set (vline, '\0');
+
+  matched = cmd_complete_command (vline, vty, &ret);
+  
+  cmd_free_strvec (vline);
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+  switch (ret)
+    {
+    case CMD_ERR_AMBIGUOUS:
+      vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
+      vty_prompt (vty);
+      vty_redraw_line (vty);
+      break;
+    case CMD_ERR_NO_MATCH:
+      /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
+      vty_prompt (vty);
+      vty_redraw_line (vty);
+      break;
+    case CMD_COMPLETE_FULL_MATCH:
+      vty_prompt (vty);
+      vty_redraw_line (vty);
+      vty_backward_pure_word (vty);
+      vty_insert_word_overwrite (vty, matched[0]);
+      vty_self_insert (vty, ' ');
+      XFREE (MTYPE_TMP, matched[0]);
+      break;
+    case CMD_COMPLETE_MATCH:
+      vty_prompt (vty);
+      vty_redraw_line (vty);
+      vty_backward_pure_word (vty);
+      vty_insert_word_overwrite (vty, matched[0]);
+      XFREE (MTYPE_TMP, matched[0]);
+      vector_only_index_free (matched);
+      return;
+      break;
+    case CMD_COMPLETE_LIST_MATCH:
+      for (i = 0; matched[i] != NULL; i++)
+	{
+	  if (i != 0 && ((i % 6) == 0))
+	    vty_out (vty, "%s", VTY_NEWLINE);
+	  vty_out (vty, "%-10s ", matched[i]);
+	  XFREE (MTYPE_TMP, matched[i]);
+	}
+      vty_out (vty, "%s", VTY_NEWLINE);
+
+      vty_prompt (vty);
+      vty_redraw_line (vty);
+      break;
+    case CMD_ERR_NOTHING_TODO:
+      vty_prompt (vty);
+      vty_redraw_line (vty);
+      break;
+    default:
+      break;
+    }
+  if (matched)
+    vector_only_index_free (matched);
+}
+
+void
+vty_describe_fold (struct vty *vty, int cmd_width,
+                 int desc_width, struct desc *desc)
+{
+  char *buf, *cmd, *p;
+  int pos;
+
+  cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
+
+  if (desc_width <= 0)
+    {
+      vty_out (vty, "  %-*s  %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE);
+      return;
+    }
+
+  buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1);
+
+  for (p = desc->str; strlen (p) > desc_width; p += pos + 1)
+    {
+      for (pos = desc_width; pos > 0; pos--)
+      if (*(p + pos) == ' ')
+        break;
+
+      if (pos == 0)
+      break;
+
+      strncpy (buf, p, pos);
+      buf[pos] = '\0';
+      vty_out (vty, "  %-*s  %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
+
+      cmd = "";
+    }
+
+  vty_out (vty, "  %-*s  %s%s", cmd_width, cmd, p, VTY_NEWLINE);
+
+  XFREE (MTYPE_TMP, buf);
+}
+
+/* Describe matched command function. */
+static void
+vty_describe_command (struct vty *vty)
+{
+  int ret;
+  vector vline;
+  vector describe;
+  int i, width, desc_width;
+  struct desc *desc, *desc_cr = NULL;
+
+  vline = cmd_make_strvec (vty->buf);
+
+  /* In case of '> ?'. */
+  if (vline == NULL)
+    {
+      vline = vector_init (1);
+      vector_set (vline, '\0');
+    }
+  else 
+    if (isspace ((int) vty->buf[vty->length - 1]))
+      vector_set (vline, '\0');
+
+  describe = cmd_describe_command (vline, vty, &ret);
+
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  /* Ambiguous error. */
+  switch (ret)
+    {
+    case CMD_ERR_AMBIGUOUS:
+      cmd_free_strvec (vline);
+      vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
+      vty_prompt (vty);
+      vty_redraw_line (vty);
+      return;
+      break;
+    case CMD_ERR_NO_MATCH:
+      cmd_free_strvec (vline);
+      vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
+      vty_prompt (vty);
+      vty_redraw_line (vty);
+      return;
+      break;
+    }  
+
+  /* Get width of command string. */
+  width = 0;
+  for (i = 0; i < vector_max (describe); i++)
+    if ((desc = vector_slot (describe, i)) != NULL)
+      {
+	int len;
+
+	if (desc->cmd[0] == '\0')
+	  continue;
+
+	len = strlen (desc->cmd);
+	if (desc->cmd[0] == '.')
+	  len--;
+
+	if (width < len)
+	  width = len;
+      }
+
+  /* Get width of description string. */
+  desc_width = vty->width - (width + 6);
+
+  /* Print out description. */
+  for (i = 0; i < vector_max (describe); i++)
+    if ((desc = vector_slot (describe, i)) != NULL)
+      {
+	if (desc->cmd[0] == '\0')
+	  continue;
+	
+	if (strcmp (desc->cmd, "<cr>") == 0)
+	  {
+	    desc_cr = desc;
+	    continue;
+	  }
+
+	if (!desc->str)
+	  vty_out (vty, "  %-s%s",
+		   desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
+		   VTY_NEWLINE);
+	else if (desc_width >= strlen (desc->str))
+	  vty_out (vty, "  %-*s  %s%s", width,
+		   desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
+		   desc->str, VTY_NEWLINE);
+	else
+	  vty_describe_fold (vty, width, desc_width, desc);
+
+#if 0
+	vty_out (vty, "  %-*s %s%s", width
+		 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
+		 desc->str ? desc->str : "", VTY_NEWLINE);
+#endif /* 0 */
+      }
+
+  if ((desc = desc_cr))
+    {
+      if (!desc->str)
+	vty_out (vty, "  %-s%s",
+		 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
+		 VTY_NEWLINE);
+      else if (desc_width >= strlen (desc->str))
+	vty_out (vty, "  %-*s  %s%s", width,
+		 desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
+		 desc->str, VTY_NEWLINE);
+      else
+	vty_describe_fold (vty, width, desc_width, desc);
+    }
+
+  cmd_free_strvec (vline);
+  vector_free (describe);
+
+  vty_prompt (vty);
+  vty_redraw_line (vty);
+}
+
+void
+vty_clear_buf (struct vty *vty)
+{
+  memset (vty->buf, 0, vty->max);
+}
+
+/* ^C stop current input and do not add command line to the history. */
+static void
+vty_stop_input (struct vty *vty)
+{
+  vty->cp = vty->length = 0;
+  vty_clear_buf (vty);
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  switch (vty->node)
+    {
+    case VIEW_NODE:
+    case ENABLE_NODE:
+      /* Nothing to do. */
+      break;
+    case CONFIG_NODE:
+    case INTERFACE_NODE:
+    case ZEBRA_NODE:
+    case RIP_NODE:
+    case RIPNG_NODE:
+    case BGP_NODE:
+    case RMAP_NODE:
+    case OSPF_NODE:
+    case OSPF6_NODE:
+    case KEYCHAIN_NODE:
+    case KEYCHAIN_KEY_NODE:
+    case MASC_NODE:
+    case VTY_NODE:
+      vty_config_unlock (vty);
+      vty->node = ENABLE_NODE;
+      break;
+    default:
+      /* Unknown node, we have to ignore it. */
+      break;
+    }
+  vty_prompt (vty);
+
+  /* Set history pointer to the latest one. */
+  vty->hp = vty->hindex;
+}
+
+/* Add current command line to the history buffer. */
+static void
+vty_hist_add (struct vty *vty)
+{
+  int index;
+
+  if (vty->length == 0)
+    return;
+
+  index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
+
+  /* Ignore the same string as previous one. */
+  if (vty->hist[index])
+    if (strcmp (vty->buf, vty->hist[index]) == 0)
+      {
+      vty->hp = vty->hindex;
+      return;
+      }
+
+  /* Insert history entry. */
+  if (vty->hist[vty->hindex])
+    XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]);
+  vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf);
+
+  /* History index rotation. */
+  vty->hindex++;
+  if (vty->hindex == VTY_MAXHIST)
+    vty->hindex = 0;
+
+  vty->hp = vty->hindex;
+}
+
+/* #define TELNET_OPTION_DEBUG */
+
+/* Get telnet window size. */
+static int
+vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
+{
+#ifdef TELNET_OPTION_DEBUG
+  int i;
+
+  for (i = 0; i < nbytes; i++)
+    {
+      switch (buf[i])
+	{
+	case IAC:
+	  vty_out (vty, "IAC ");
+	  break;
+	case WILL:
+	  vty_out (vty, "WILL ");
+	  break;
+	case WONT:
+	  vty_out (vty, "WONT ");
+	  break;
+	case DO:
+	  vty_out (vty, "DO ");
+	  break;
+	case DONT:
+	  vty_out (vty, "DONT ");
+	  break;
+	case SB:
+	  vty_out (vty, "SB ");
+	  break;
+	case SE:
+	  vty_out (vty, "SE ");
+	  break;
+	case TELOPT_ECHO:
+	  vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
+	  break;
+	case TELOPT_SGA:
+	  vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
+	  break;
+	case TELOPT_NAWS:
+	  vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
+	  break;
+	default:
+	  vty_out (vty, "%x ", buf[i]);
+	  break;
+	}
+    }
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+#endif /* TELNET_OPTION_DEBUG */
+
+  switch (buf[0])
+    {
+    case SB:
+      buffer_reset(vty->sb_buffer);
+      vty->iac_sb_in_progress = 1;
+      return 0;
+      break;
+    case SE: 
+      {
+	char *buffer = (char *)vty->sb_buffer->head->data;
+	int length = vty->sb_buffer->length;
+
+	if (buffer == NULL)
+	  return 0;
+
+	if (!vty->iac_sb_in_progress)
+	  return 0;
+
+	if (buffer[0] == '\0')
+	  {
+	    vty->iac_sb_in_progress = 0;
+	    return 0;
+	  }
+	switch (buffer[0])
+	  {
+	  case TELOPT_NAWS:
+	    if (length < 5)
+	      break;
+	    vty->width = buffer[2];
+	    vty->height = vty->lines >= 0 ? vty->lines : buffer[4];
+	    break;
+	  }
+	vty->iac_sb_in_progress = 0;
+	return 0;
+	break;
+      }
+    default:
+      break;
+    }
+  return 1;
+}
+
+/* Execute current command line. */
+static int
+vty_execute (struct vty *vty)
+{
+  int ret;
+
+  ret = CMD_SUCCESS;
+
+  switch (vty->node)
+    {
+    case AUTH_NODE:
+    case AUTH_ENABLE_NODE:
+      vty_auth (vty, vty->buf);
+      break;
+    default:
+      ret = vty_command (vty, vty->buf);
+      if (vty->type == VTY_TERM)
+	vty_hist_add (vty);
+      break;
+    }
+
+  /* Clear command line buffer. */
+  vty->cp = vty->length = 0;
+  vty_clear_buf (vty);
+
+  if (vty->status != VTY_CLOSE 
+      && vty->status != VTY_START
+      && vty->status != VTY_CONTINUE)
+    vty_prompt (vty);
+
+  return ret;
+}
+
+#define CONTROL(X)  ((X) - '@')
+#define VTY_NORMAL     0
+#define VTY_PRE_ESCAPE 1
+#define VTY_ESCAPE     2
+
+/* Escape character command map. */
+static void
+vty_escape_map (unsigned char c, struct vty *vty)
+{
+  switch (c)
+    {
+    case ('A'):
+      vty_previous_line (vty);
+      break;
+    case ('B'):
+      vty_next_line (vty);
+      break;
+    case ('C'):
+      vty_forward_char (vty);
+      break;
+    case ('D'):
+      vty_backward_char (vty);
+      break;
+    default:
+      break;
+    }
+
+  /* Go back to normal mode. */
+  vty->escape = VTY_NORMAL;
+}
+
+/* Quit print out to the buffer. */
+static void
+vty_buffer_reset (struct vty *vty)
+{
+  buffer_reset (vty->obuf);
+  vty_prompt (vty);
+  vty_redraw_line (vty);
+}
+
+/* Read data via vty socket. */
+static int
+vty_read (struct thread *thread)
+{
+  int i;
+  int ret;
+  int nbytes;
+  unsigned char buf[VTY_READ_BUFSIZ];
+
+  int vty_sock = THREAD_FD (thread);
+  struct vty *vty = THREAD_ARG (thread);
+  vty->t_read = NULL;
+
+  /* Read raw data from socket */
+  nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ);
+  if (nbytes <= 0)
+    vty->status = VTY_CLOSE;
+
+  for (i = 0; i < nbytes; i++) 
+    {
+      if (buf[i] == IAC)
+	{
+	  if (!vty->iac)
+	    {
+	      vty->iac = 1;
+	      continue;
+	    }
+	  else
+	    {
+	      vty->iac = 0;
+	    }
+	}
+      
+      if (vty->iac_sb_in_progress && !vty->iac)
+	{
+	    buffer_putc(vty->sb_buffer, buf[i]);
+	    continue;
+	}
+
+      if (vty->iac)
+	{
+	  /* In case of telnet command */
+	  ret = vty_telnet_option (vty, buf + i, nbytes - i);
+	  vty->iac = 0;
+	  i += ret;
+	  continue;
+	}
+
+      if (vty->status == VTY_MORE)
+	{
+	  switch (buf[i])
+	    {
+	    case CONTROL('C'):
+	    case 'q':
+	    case 'Q':
+	      if (vty->output_func)
+		(*vty->output_func) (vty, 1);
+	      vty_buffer_reset (vty);
+	      break;
+#if 0 /* More line does not work for "show ip bgp".  */
+	    case '\n':
+	    case '\r':
+	      vty->status = VTY_MORELINE;
+	      break;
+#endif
+	    default:
+	      if (vty->output_func)
+		(*vty->output_func) (vty, 0);
+	      break;
+	    }
+	  continue;
+	}
+
+      /* Escape character. */
+      if (vty->escape == VTY_ESCAPE)
+	{
+	  vty_escape_map (buf[i], vty);
+	  continue;
+	}
+
+      /* Pre-escape status. */
+      if (vty->escape == VTY_PRE_ESCAPE)
+	{
+	  switch (buf[i])
+	    {
+	    case '[':
+	      vty->escape = VTY_ESCAPE;
+	      break;
+	    case 'b':
+	      vty_backward_word (vty);
+	      vty->escape = VTY_NORMAL;
+	      break;
+	    case 'f':
+	      vty_forward_word (vty);
+	      vty->escape = VTY_NORMAL;
+	      break;
+	    case 'd':
+	      vty_forward_kill_word (vty);
+	      vty->escape = VTY_NORMAL;
+	      break;
+	    case CONTROL('H'):
+	    case 0x7f:
+	      vty_backward_kill_word (vty);
+	      vty->escape = VTY_NORMAL;
+	      break;
+	    default:
+	      vty->escape = VTY_NORMAL;
+	      break;
+	    }
+	  continue;
+	}
+
+      switch (buf[i])
+	{
+	case CONTROL('A'):
+	  vty_beginning_of_line (vty);
+	  break;
+	case CONTROL('B'):
+	  vty_backward_char (vty);
+	  break;
+	case CONTROL('C'):
+	  vty_stop_input (vty);
+	  break;
+	case CONTROL('D'):
+	  vty_delete_char (vty);
+	  break;
+	case CONTROL('E'):
+	  vty_end_of_line (vty);
+	  break;
+	case CONTROL('F'):
+	  vty_forward_char (vty);
+	  break;
+	case CONTROL('H'):
+	case 0x7f:
+	  vty_delete_backward_char (vty);
+	  break;
+	case CONTROL('K'):
+	  vty_kill_line (vty);
+	  break;
+	case CONTROL('N'):
+	  vty_next_line (vty);
+	  break;
+	case CONTROL('P'):
+	  vty_previous_line (vty);
+	  break;
+	case CONTROL('T'):
+	  vty_transpose_chars (vty);
+	  break;
+	case CONTROL('U'):
+	  vty_kill_line_from_beginning (vty);
+	  break;
+	case CONTROL('W'):
+	  vty_backward_kill_word (vty);
+	  break;
+	case CONTROL('Z'):
+	  vty_end_config (vty);
+	  break;
+	case '\n':
+	case '\r':
+	  vty_out (vty, "%s", VTY_NEWLINE);
+	  vty_execute (vty);
+	  break;
+	case '\t':
+	  vty_complete_command (vty);
+	  break;
+	case '?':
+	  if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
+	    vty_self_insert (vty, buf[i]);
+	  else
+	    vty_describe_command (vty);
+	  break;
+	case '\033':
+	  if (i + 1 < nbytes && buf[i + 1] == '[')
+	    {
+	      vty->escape = VTY_ESCAPE;
+	      i++;
+	    }
+	  else
+	    vty->escape = VTY_PRE_ESCAPE;
+	  break;
+	default:
+	  if (buf[i] > 31 && buf[i] < 127)
+	    vty_self_insert (vty, buf[i]);
+	  break;
+	}
+    }
+
+  /* Check status. */
+  if (vty->status == VTY_CLOSE)
+    vty_close (vty);
+  else
+    {
+      vty_event (VTY_WRITE, vty_sock, vty);
+      vty_event (VTY_READ, vty_sock, vty);
+    }
+  return 0;
+}
+
+/* Flush buffer to the vty. */
+static int
+vty_flush (struct thread *thread)
+{
+  int erase;
+  int dont_more;
+  int vty_sock = THREAD_FD (thread);
+  struct vty *vty = THREAD_ARG (thread);
+  vty->t_write = NULL;
+
+  /* Tempolary disable read thread. */
+  if (vty->lines == 0)
+    if (vty->t_read)
+      {
+	thread_cancel (vty->t_read);
+	vty->t_read = NULL;
+      }
+
+  /* Function execution continue. */
+  if (vty->status == VTY_START || vty->status == VTY_CONTINUE)
+    {
+      if (vty->status == VTY_CONTINUE)
+	erase = 1;
+      else
+	erase = 0;
+
+      if (vty->output_func == NULL)
+	dont_more = 1;
+      else
+	dont_more = 0;
+
+      if (vty->lines == 0)
+	{
+	  erase = 0;
+	  dont_more = 1;
+	}
+
+      buffer_flush_vty_all (vty->obuf, vty->fd, erase, dont_more);
+
+      if (vty->status == VTY_CLOSE)
+	{
+	  vty_close (vty);
+	  return 0;
+	}
+
+      if (vty->output_func == NULL)
+	{
+	  vty->status = VTY_NORMAL;
+	  vty_prompt (vty);
+	  vty_event (VTY_WRITE, vty_sock, vty);
+	}
+      else
+	vty->status = VTY_MORE;
+
+      if (vty->lines == 0)
+	{
+	  if (vty->output_func == NULL)
+	    vty_event (VTY_READ, vty_sock, vty);
+	  else
+	    {
+	      if (vty->output_func)
+		(*vty->output_func) (vty, 0);
+	      vty_event (VTY_WRITE, vty_sock, vty);
+	    }
+	}
+    }
+  else
+    {
+      if (vty->status == VTY_MORE || vty->status == VTY_MORELINE)
+	erase = 1;
+      else
+	erase = 0;
+
+      if (vty->lines == 0)
+	buffer_flush_window (vty->obuf, vty->fd, vty->width, 25, 0, 1);
+      else if (vty->status == VTY_MORELINE)
+	buffer_flush_window (vty->obuf, vty->fd, vty->width, 1, erase, 0);
+      else
+	buffer_flush_window (vty->obuf, vty->fd, vty->width,
+			     vty->lines >= 0 ? vty->lines : vty->height,
+			     erase, 0);
+  
+      if (buffer_empty (vty->obuf))
+	{
+	  if (vty->status == VTY_CLOSE)
+	    vty_close (vty);
+	  else
+	    {
+	      vty->status = VTY_NORMAL;
+	  
+	      if (vty->lines == 0)
+		vty_event (VTY_READ, vty_sock, vty);
+	    }
+	}
+      else
+	{
+	  vty->status = VTY_MORE;
+
+	  if (vty->lines == 0)
+	    vty_event (VTY_WRITE, vty_sock, vty);
+	}
+    }
+
+  return 0;
+}
+
+/* Create new vty structure. */
+struct vty *
+vty_create (int vty_sock, union sockunion *su)
+{
+  struct vty *vty;
+
+  /* Allocate new vty structure and set up default values. */
+  vty = vty_new ();
+  vty->fd = vty_sock;
+  vty->type = VTY_TERM;
+  vty->address = sockunion_su2str (su);
+  if (no_password_check)
+    {
+      if (host.advanced)
+	vty->node = ENABLE_NODE;
+      else
+	vty->node = VIEW_NODE;
+    }
+  else
+    vty->node = AUTH_NODE;
+  vty->fail = 0;
+  vty->cp = 0;
+  vty_clear_buf (vty);
+  vty->length = 0;
+  memset (vty->hist, 0, sizeof (vty->hist));
+  vty->hp = 0;
+  vty->hindex = 0;
+  vector_set_index (vtyvec, vty_sock, vty);
+  vty->status = VTY_NORMAL;
+  vty->v_timeout = vty_timeout_val;
+  if (host.lines >= 0)
+    vty->lines = host.lines;
+  else
+    vty->lines = -1;
+  vty->iac = 0;
+  vty->iac_sb_in_progress = 0;
+  vty->sb_buffer = buffer_new (1024);
+
+  if (! no_password_check)
+    {
+      /* Vty is not available if password isn't set. */
+      if (host.password == NULL && host.password_encrypt == NULL)
+	{
+	  vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
+	  vty->status = VTY_CLOSE;
+	  vty_close (vty);
+	  return NULL;
+	}
+    }
+
+  /* Say hello to the world. */
+  vty_hello (vty);
+  if (! no_password_check)
+    vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+
+  /* Setting up terminal. */
+  vty_will_echo (vty);
+  vty_will_suppress_go_ahead (vty);
+
+  vty_dont_linemode (vty);
+  vty_do_window_size (vty);
+  /* vty_dont_lflow_ahead (vty); */
+
+  vty_prompt (vty);
+
+  /* Add read/write thread. */
+  vty_event (VTY_WRITE, vty_sock, vty);
+  vty_event (VTY_READ, vty_sock, vty);
+
+  return vty;
+}
+
+/* Accept connection from the network. */
+static int
+vty_accept (struct thread *thread)
+{
+  int vty_sock;
+  struct vty *vty;
+  union sockunion su;
+  int ret;
+  unsigned int on;
+  int accept_sock;
+  struct prefix *p = NULL;
+  struct access_list *acl = NULL;
+
+  accept_sock = THREAD_FD (thread);
+
+  /* We continue hearing vty socket. */
+  vty_event (VTY_SERV, accept_sock, NULL);
+
+  memset (&su, 0, sizeof (union sockunion));
+
+  /* We can handle IPv4 or IPv6 socket. */
+  vty_sock = sockunion_accept (accept_sock, &su);
+  if (vty_sock < 0)
+    {
+      zlog_warn ("can't accept vty socket : %s", strerror (errno));
+      return -1;
+    }
+
+  p = sockunion2hostprefix (&su);
+
+  /* VTY's accesslist apply. */
+  if (p->family == AF_INET && vty_accesslist_name)
+    {
+      if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
+	  (access_list_apply (acl, p) == FILTER_DENY))
+	{
+	  char *buf;
+	  zlog (NULL, LOG_INFO, "Vty connection refused from %s",
+		(buf = sockunion_su2str (&su)));
+	  free (buf);
+	  close (vty_sock);
+	  
+	  /* continue accepting connections */
+	  vty_event (VTY_SERV, accept_sock, NULL);
+	  
+	  prefix_free (p);
+
+	  return 0;
+	}
+    }
+
+#ifdef HAVE_IPV6
+  /* VTY's ipv6 accesslist apply. */
+  if (p->family == AF_INET6 && vty_ipv6_accesslist_name)
+    {
+      if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
+	  (access_list_apply (acl, p) == FILTER_DENY))
+	{
+	  char *buf;
+	  zlog (NULL, LOG_INFO, "Vty connection refused from %s",
+		(buf = sockunion_su2str (&su)));
+	  free (buf);
+	  close (vty_sock);
+	  
+	  /* continue accepting connections */
+	  vty_event (VTY_SERV, accept_sock, NULL);
+	  
+	  prefix_free (p);
+
+	  return 0;
+	}
+    }
+#endif /* HAVE_IPV6 */
+  
+  prefix_free (p);
+
+  on = 1;
+  ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY, 
+		    (char *) &on, sizeof (on));
+  if (ret < 0)
+    zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s", 
+	  strerror (errno));
+
+  vty = vty_create (vty_sock, &su);
+
+  return 0;
+}
+
+#if defined(HAVE_IPV6) && !defined(NRL)
+void
+vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
+{
+  int ret;
+  struct addrinfo req;
+  struct addrinfo *ainfo;
+  struct addrinfo *ainfo_save;
+  int sock;
+  char port_str[BUFSIZ];
+
+  memset (&req, 0, sizeof (struct addrinfo));
+  req.ai_flags = AI_PASSIVE;
+  req.ai_family = AF_UNSPEC;
+  req.ai_socktype = SOCK_STREAM;
+  sprintf (port_str, "%d", port);
+  port_str[sizeof (port_str) - 1] = '\0';
+
+  ret = getaddrinfo (hostname, port_str, &req, &ainfo);
+
+  if (ret != 0)
+    {
+      fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret));
+      exit (1);
+    }
+
+  ainfo_save = ainfo;
+
+  do
+    {
+      if (ainfo->ai_family != AF_INET
+#ifdef HAVE_IPV6
+	  && ainfo->ai_family != AF_INET6
+#endif /* HAVE_IPV6 */
+	  )
+	continue;
+
+      sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
+      if (sock < 0)
+	continue;
+
+      sockopt_reuseaddr (sock);
+      sockopt_reuseport (sock);
+
+      ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
+      if (ret < 0)
+	{
+	  close (sock);	/* Avoid sd leak. */
+	continue;
+	}
+
+      ret = listen (sock, 3);
+      if (ret < 0) 
+	{
+	  close (sock);	/* Avoid sd leak. */
+	continue;
+	}
+
+      vty_event (VTY_SERV, sock, NULL);
+    }
+  while ((ainfo = ainfo->ai_next) != NULL);
+
+  freeaddrinfo (ainfo_save);
+}
+#endif /* HAVE_IPV6 && ! NRL */
+
+/* Make vty server socket. */
+void
+vty_serv_sock_family (unsigned short port, int family)
+{
+  int ret;
+  union sockunion su;
+  int accept_sock;
+
+  memset (&su, 0, sizeof (union sockunion));
+  su.sa.sa_family = family;
+
+  /* Make new socket. */
+  accept_sock = sockunion_stream_socket (&su);
+  if (accept_sock < 0)
+    return;
+
+  /* This is server, so reuse address. */
+  sockopt_reuseaddr (accept_sock);
+  sockopt_reuseport (accept_sock);
+
+  /* Bind socket to universal address and given port. */
+  ret = sockunion_bind (accept_sock, &su, port, NULL);
+  if (ret < 0)
+    {
+      close (accept_sock);	/* Avoid sd leak. */
+      return;
+    }
+
+  /* Listen socket under queue 3. */
+  ret = listen (accept_sock, 3);
+  if (ret < 0) 
+    {
+      zlog (NULL, LOG_WARNING, "can't listen socket");
+      close (accept_sock);	/* Avoid sd leak. */
+      return;
+    }
+
+  /* Add vty server event. */
+  vty_event (VTY_SERV, accept_sock, NULL);
+}
+
+#ifdef VTYSH
+/* For sockaddr_un. */
+#include <sys/un.h>
+
+/* VTY shell UNIX domain socket. */
+void
+vty_serv_un (char *path)
+{
+  int ret;
+  int sock, len;
+  struct sockaddr_un serv;
+  mode_t old_mask;
+
+  /* First of all, unlink existing socket */
+  unlink (path);
+
+  /* Set umask */
+  old_mask = umask (0077);
+
+  /* Make UNIX domain socket. */
+  sock = socket (AF_UNIX, SOCK_STREAM, 0);
+  if (sock < 0)
+    {
+      perror ("sock");
+      return;
+    }
+
+  /* Make server socket. */
+  memset (&serv, 0, sizeof (struct sockaddr_un));
+  serv.sun_family = AF_UNIX;
+  strncpy (serv.sun_path, path, strlen (path));
+#ifdef HAVE_SUN_LEN
+  len = serv.sun_len = SUN_LEN(&serv);
+#else
+  len = sizeof (serv.sun_family) + strlen (serv.sun_path);
+#endif /* HAVE_SUN_LEN */
+
+  ret = bind (sock, (struct sockaddr *) &serv, len);
+  if (ret < 0)
+    {
+      perror ("bind");
+      close (sock);	/* Avoid sd leak. */
+      return;
+    }
+
+  ret = listen (sock, 5);
+  if (ret < 0)
+    {
+      perror ("listen");
+      close (sock);	/* Avoid sd leak. */
+      return;
+    }
+
+  umask (old_mask);
+
+  vty_event (VTYSH_SERV, sock, NULL);
+}
+
+/* #define VTYSH_DEBUG 1 */
+
+static int
+vtysh_accept (struct thread *thread)
+{
+  int accept_sock;
+  int sock;
+  int client_len;
+  struct sockaddr_un client;
+  struct vty *vty;
+  
+  accept_sock = THREAD_FD (thread);
+
+  vty_event (VTYSH_SERV, accept_sock, NULL);
+
+  memset (&client, 0, sizeof (struct sockaddr_un));
+  client_len = sizeof (struct sockaddr_un);
+
+  sock = accept (accept_sock, (struct sockaddr *) &client, &client_len);
+
+  if (sock < 0)
+    {
+      zlog_warn ("can't accept vty socket : %s", strerror (errno));
+      return -1;
+    }
+
+#ifdef VTYSH_DEBUG
+  printf ("VTY shell accept\n");
+#endif /* VTYSH_DEBUG */
+
+  vty = vty_new ();
+  vty->fd = sock;
+  vty->type = VTY_SHELL_SERV;
+  vty->node = VIEW_NODE;
+
+  vty_event (VTYSH_READ, sock, vty);
+
+  return 0;
+}
+
+static int
+vtysh_read (struct thread *thread)
+{
+  int ret;
+  int sock;
+  int nbytes;
+  struct vty *vty;
+  unsigned char buf[VTY_READ_BUFSIZ];
+  u_char header[4] = {0, 0, 0, 0};
+
+  sock = THREAD_FD (thread);
+  vty = THREAD_ARG (thread);
+  vty->t_read = NULL;
+
+  nbytes = read (sock, buf, VTY_READ_BUFSIZ);
+  if (nbytes <= 0)
+    {
+      vty_close (vty);
+#ifdef VTYSH_DEBUG
+      printf ("close vtysh\n");
+#endif /* VTYSH_DEBUG */
+      return 0;
+    }
+
+#ifdef VTYSH_DEBUG
+  printf ("line: %s\n", buf);
+#endif /* VTYSH_DEBUG */
+
+  vty_ensure (vty, nbytes);
+  memcpy (vty->buf, buf, nbytes);
+  
+  /* Pass this line to parser. */
+  ret = vty_execute (vty);
+
+  vty_clear_buf (vty);
+
+  /* Return result. */
+#ifdef VTYSH_DEBUG
+  printf ("result: %d\n", ret);
+  printf ("vtysh node: %d\n", vty->node);
+#endif /* VTYSH_DEBUG */
+
+  header[3] = ret;
+  write (vty->fd, header, 4);
+
+  vty_event (VTYSH_READ, sock, vty);
+
+  return 0;
+}
+#endif /* VTYSH */
+
+/* Determine address family to bind. */
+void
+vty_serv_sock (const char *hostname, unsigned short port, char *path)
+{
+  /* If port is set to 0, do not listen on TCP/IP at all! */
+  if (port)
+    {
+
+#ifdef HAVE_IPV6
+#ifdef NRL
+      vty_serv_sock_family (port, AF_INET);
+      vty_serv_sock_family (port, AF_INET6);
+#else /* ! NRL */
+      vty_serv_sock_addrinfo (hostname, port);
+#endif /* NRL*/
+#else /* ! HAVE_IPV6 */
+      vty_serv_sock_family (port, AF_INET);
+#endif /* HAVE_IPV6 */
+    }
+
+#ifdef VTYSH
+  vty_serv_un (path);
+#endif /* VTYSH */
+}
+
+/* Close vty interface. */
+void
+vty_close (struct vty *vty)
+{
+  int i;
+
+  /* Cancel threads.*/
+  if (vty->t_read)
+    thread_cancel (vty->t_read);
+  if (vty->t_write)
+    thread_cancel (vty->t_write);
+  if (vty->t_timeout)
+    thread_cancel (vty->t_timeout);
+  if (vty->t_output)
+    thread_cancel (vty->t_output);
+
+  /* Flush buffer. */
+  if (! buffer_empty (vty->obuf))
+    buffer_flush_all (vty->obuf, vty->fd);
+
+  /* Free input buffer. */
+  buffer_free (vty->obuf);
+
+  /* Free SB buffer. */
+  if (vty->sb_buffer)
+    buffer_free (vty->sb_buffer);
+
+  /* Free command history. */
+  for (i = 0; i < VTY_MAXHIST; i++)
+    if (vty->hist[i])
+      XFREE (MTYPE_VTY_HIST, vty->hist[i]);
+
+  /* Unset vector. */
+  vector_unset (vtyvec, vty->fd);
+
+  /* Close socket. */
+  if (vty->fd > 0)
+    close (vty->fd);
+
+  if (vty->address)
+    XFREE (0, vty->address);
+  if (vty->buf)
+    XFREE (MTYPE_VTY, vty->buf);
+
+  /* Check configure. */
+  vty_config_unlock (vty);
+
+  /* OK free vty. */
+  XFREE (MTYPE_VTY, vty);
+}
+
+/* When time out occur output message then close connection. */
+static int
+vty_timeout (struct thread *thread)
+{
+  struct vty *vty;
+
+  vty = THREAD_ARG (thread);
+  vty->t_timeout = NULL;
+  vty->v_timeout = 0;
+
+  /* Clear buffer*/
+  buffer_reset (vty->obuf);
+  vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
+
+  /* Close connection. */
+  vty->status = VTY_CLOSE;
+  vty_close (vty);
+
+  return 0;
+}
+
+/* Read up configuration file from file_name. */
+static void
+vty_read_file (FILE *confp)
+{
+  int ret;
+  struct vty *vty;
+
+  vty = vty_new ();
+  vty->fd = 0;			/* stdout */
+  vty->type = VTY_TERM;
+  vty->node = CONFIG_NODE;
+  
+  /* Execute configuration file */
+  ret = config_from_file (vty, confp);
+
+  if (ret != CMD_SUCCESS) 
+    {
+      switch (ret)
+	{
+	case CMD_ERR_AMBIGUOUS:
+	  fprintf (stderr, "Ambiguous command.\n");
+	  break;
+	case CMD_ERR_NO_MATCH:
+	  fprintf (stderr, "There is no such command.\n");
+	  break;
+	}
+      fprintf (stderr, "Error occured during reading below line.\n%s\n", 
+	       vty->buf);
+      vty_close (vty);
+      exit (1);
+    }
+
+  vty_close (vty);
+}
+
+FILE *
+vty_use_backup_config (char *fullpath)
+{
+  char *fullpath_sav, *fullpath_tmp;
+  FILE *ret = NULL;
+  struct stat buf;
+  int tmp, sav;
+  int c;
+  char buffer[512];
+  
+  fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
+  strcpy (fullpath_sav, fullpath);
+  strcat (fullpath_sav, CONF_BACKUP_EXT);
+  if (stat (fullpath_sav, &buf) == -1)
+    {
+      free (fullpath_sav);
+      return NULL;
+    }
+
+  fullpath_tmp = malloc (strlen (fullpath) + 8);
+  sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
+  
+  /* Open file to configuration write. */
+  tmp = mkstemp (fullpath_tmp);
+  if (tmp < 0)
+    {
+      free (fullpath_sav);
+      free (fullpath_tmp);
+      return NULL;
+    }
+
+  sav = open (fullpath_sav, O_RDONLY);
+  if (sav < 0)
+    {
+      free (fullpath_sav);
+      free (fullpath_tmp);
+      unlink (fullpath_tmp);
+      return NULL;
+    }
+  
+  while((c = read (sav, buffer, 512)) > 0)
+    write (tmp, buffer, c);
+  
+  close (sav);
+  close (tmp);
+  
+  if (link (fullpath_tmp, fullpath) == 0)
+    ret = fopen (fullpath, "r");
+
+  unlink (fullpath_tmp);
+  
+  free (fullpath_sav);
+  free (fullpath_tmp);
+  return fopen (fullpath, "r");
+}
+
+/* Read up configuration file from file_name. */
+void
+vty_read_config (char *config_file,
+		 char *config_current_dir,
+		 char *config_default_dir)
+{
+  char *cwd;
+  FILE *confp = NULL;
+  char *fullpath;
+
+  /* If -f flag specified. */
+  if (config_file != NULL)
+    {
+      if (! IS_DIRECTORY_SEP (config_file[0]))
+	{
+	  cwd = getcwd (NULL, MAXPATHLEN);
+	  fullpath = XMALLOC (MTYPE_TMP, 
+			      strlen (cwd) + strlen (config_file) + 2);
+	  sprintf (fullpath, "%s/%s", cwd, config_file);
+	}
+      else
+	fullpath = config_file;
+
+      confp = fopen (fullpath, "r");
+
+      if (confp == NULL)
+	{
+	  confp = vty_use_backup_config (fullpath);
+	  if (confp)
+	    fprintf (stderr, "WARNING: using backup configuration file!\n");
+	  else
+	    {
+	      fprintf (stderr, "can't open configuration file [%s]\n", 
+		       config_file);
+	      exit(1);
+	    }
+	}
+    }
+  else
+    {
+      /* Relative path configuration file open. */
+      if (config_current_dir)
+	{
+	  confp = fopen (config_current_dir, "r");
+	  if (confp == NULL)
+	    {
+	      confp = vty_use_backup_config (config_current_dir);
+	      if (confp)
+		fprintf (stderr, "WARNING: using backup configuration file!\n");
+	    }
+	}
+
+      /* If there is no relative path exists, open system default file. */
+      if (confp == NULL)
+	{
+#ifdef VTYSH
+	  int ret;
+	  struct stat conf_stat;
+
+	  /* !!!!PLEASE LEAVE!!!!
+	     This is NEEDED for use with vtysh -b, or else you can get
+	     a real configuration food fight with a lot garbage in the
+	     merged configuration file it creates coming from the per
+	     daemon configuration files.  This also allows the daemons
+	     to start if there default configuration file is not
+	     present or ignore them, as needed when using vtysh -b to
+	     configure the daemons at boot - MAG */
+
+	  /* Stat for vtysh Zebra.conf, if found startup and wait for
+	     boot configuration */
+
+	  if ( strstr(config_default_dir, "vtysh") == NULL)
+	    {
+	      ret = stat (integrate_default, &conf_stat);
+	      if (ret >= 0)
+		{
+		  return;
+		}
+	    }
+#endif /* VTYSH */
+
+	  confp = fopen (config_default_dir, "r");
+	  if (confp == NULL)
+	    {
+	      confp = vty_use_backup_config (config_default_dir);
+	      if (confp)
+		{
+		  fprintf (stderr, "WARNING: using backup configuration file!\n");
+		  fullpath = config_default_dir;
+		}
+	      else
+		{
+		  fprintf (stderr, "can't open configuration file [%s]\n",
+			   config_default_dir);
+		  exit (1);
+		}
+	    }      
+	  else
+	    fullpath = config_default_dir;
+	}
+      else
+	{
+	  /* Rleative path configuration file. */
+	  cwd = getcwd (NULL, MAXPATHLEN);
+	  fullpath = XMALLOC (MTYPE_TMP, 
+			      strlen (cwd) + strlen (config_current_dir) + 2);
+	  sprintf (fullpath, "%s/%s", cwd, config_current_dir);
+	}  
+    }  
+  vty_read_file (confp);
+
+  fclose (confp);
+
+  host_config_set (fullpath);
+}
+
+/* Small utility function which output log to the VTY. */
+void
+vty_log (const char *proto_str, const char *format, va_list va)
+{
+  int i;
+  struct vty *vty;
+
+  for (i = 0; i < vector_max (vtyvec); i++)
+    if ((vty = vector_slot (vtyvec, i)) != NULL)
+      if (vty->monitor)
+	vty_log_out (vty, proto_str, format, va);
+}
+
+int
+vty_config_lock (struct vty *vty)
+{
+  if (vty_config == 0)
+    {
+      vty->config = 1;
+      vty_config = 1;
+    }
+  return vty->config;
+}
+
+int
+vty_config_unlock (struct vty *vty)
+{
+  if (vty_config == 1 && vty->config == 1)
+    {
+      vty->config = 0;
+      vty_config = 0;
+    }
+  return vty->config;
+}
+
+/* Master of the threads. */
+extern struct thread_master *master;
+/* struct thread_master *master; */
+
+static void
+vty_event (enum event event, int sock, struct vty *vty)
+{
+  struct thread *vty_serv_thread;
+
+  switch (event)
+    {
+    case VTY_SERV:
+      vty_serv_thread = thread_add_read (master, vty_accept, vty, sock);
+      vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
+      break;
+#ifdef VTYSH
+    case VTYSH_SERV:
+      thread_add_read (master, vtysh_accept, vty, sock);
+      break;
+    case VTYSH_READ:
+      thread_add_read (master, vtysh_read, vty, sock);
+      break;
+#endif /* VTYSH */
+    case VTY_READ:
+      vty->t_read = thread_add_read (master, vty_read, vty, sock);
+
+      /* Time out treatment. */
+      if (vty->v_timeout)
+	{
+	  if (vty->t_timeout)
+	    thread_cancel (vty->t_timeout);
+	  vty->t_timeout = 
+	    thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
+	}
+      break;
+    case VTY_WRITE:
+      if (! vty->t_write)
+	vty->t_write = thread_add_write (master, vty_flush, vty, sock);
+      break;
+    case VTY_TIMEOUT_RESET:
+      if (vty->t_timeout)
+	{
+	  thread_cancel (vty->t_timeout);
+	  vty->t_timeout = NULL;
+	}
+      if (vty->v_timeout)
+	{
+	  vty->t_timeout = 
+	    thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
+	}
+      break;
+    }
+}
+
+DEFUN (config_who,
+       config_who_cmd,
+       "who",
+       "Display who is on vty\n")
+{
+  int i;
+  struct vty *v;
+
+  for (i = 0; i < vector_max (vtyvec); i++)
+    if ((v = vector_slot (vtyvec, i)) != NULL)
+      vty_out (vty, "%svty[%d] connected from %s.%s",
+	       v->config ? "*" : " ",
+	       i, v->address, VTY_NEWLINE);
+  return CMD_SUCCESS;
+}
+
+/* Move to vty configuration mode. */
+DEFUN (line_vty,
+       line_vty_cmd,
+       "line vty",
+       "Configure a terminal line\n"
+       "Virtual terminal\n")
+{
+  vty->node = VTY_NODE;
+  return CMD_SUCCESS;
+}
+
+/* Set time out value. */
+int
+exec_timeout (struct vty *vty, char *min_str, char *sec_str)
+{
+  unsigned long timeout = 0;
+
+  /* min_str and sec_str are already checked by parser.  So it must be
+     all digit string. */
+  if (min_str)
+    {
+      timeout = strtol (min_str, NULL, 10);
+      timeout *= 60;
+    }
+  if (sec_str)
+    timeout += strtol (sec_str, NULL, 10);
+
+  vty_timeout_val = timeout;
+  vty->v_timeout = timeout;
+  vty_event (VTY_TIMEOUT_RESET, 0, vty);
+
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (exec_timeout_min,
+       exec_timeout_min_cmd,
+       "exec-timeout <0-35791>",
+       "Set timeout value\n"
+       "Timeout value in minutes\n")
+{
+  return exec_timeout (vty, argv[0], NULL);
+}
+
+DEFUN (exec_timeout_sec,
+       exec_timeout_sec_cmd,
+       "exec-timeout <0-35791> <0-2147483>",
+       "Set the EXEC timeout\n"
+       "Timeout in minutes\n"
+       "Timeout in seconds\n")
+{
+  return exec_timeout (vty, argv[0], argv[1]);
+}
+
+DEFUN (no_exec_timeout,
+       no_exec_timeout_cmd,
+       "no exec-timeout",
+       NO_STR
+       "Set the EXEC timeout\n")
+{
+  return exec_timeout (vty, NULL, NULL);
+}
+
+/* Set vty access class. */
+DEFUN (vty_access_class,
+       vty_access_class_cmd,
+       "access-class WORD",
+       "Filter connections based on an IP access list\n"
+       "IP access list\n")
+{
+  if (vty_accesslist_name)
+    XFREE(MTYPE_VTY, vty_accesslist_name);
+
+  vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
+
+  return CMD_SUCCESS;
+}
+
+/* Clear vty access class. */
+DEFUN (no_vty_access_class,
+       no_vty_access_class_cmd,
+       "no access-class [WORD]",
+       NO_STR
+       "Filter connections based on an IP access list\n"
+       "IP access list\n")
+{
+  if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
+    {
+      vty_out (vty, "Access-class is not currently applied to vty%s",
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  XFREE(MTYPE_VTY, vty_accesslist_name);
+
+  vty_accesslist_name = NULL;
+
+  return CMD_SUCCESS;
+}
+
+#ifdef HAVE_IPV6
+/* Set vty access class. */
+DEFUN (vty_ipv6_access_class,
+       vty_ipv6_access_class_cmd,
+       "ipv6 access-class WORD",
+       IPV6_STR
+       "Filter connections based on an IP access list\n"
+       "IPv6 access list\n")
+{
+  if (vty_ipv6_accesslist_name)
+    XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
+
+  vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
+
+  return CMD_SUCCESS;
+}
+
+/* Clear vty access class. */
+DEFUN (no_vty_ipv6_access_class,
+       no_vty_ipv6_access_class_cmd,
+       "no ipv6 access-class [WORD]",
+       NO_STR
+       IPV6_STR
+       "Filter connections based on an IP access list\n"
+       "IPv6 access list\n")
+{
+  if (! vty_ipv6_accesslist_name ||
+      (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
+    {
+      vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
+
+  vty_ipv6_accesslist_name = NULL;
+
+  return CMD_SUCCESS;
+}
+#endif /* HAVE_IPV6 */
+
+/* vty login. */
+DEFUN (vty_login,
+       vty_login_cmd,
+       "login",
+       "Enable password checking\n")
+{
+  no_password_check = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_vty_login,
+       no_vty_login_cmd,
+       "no login",
+       NO_STR
+       "Enable password checking\n")
+{
+  no_password_check = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (service_advanced_vty,
+       service_advanced_vty_cmd,
+       "service advanced-vty",
+       "Set up miscellaneous service\n"
+       "Enable advanced mode vty interface\n")
+{
+  host.advanced = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_service_advanced_vty,
+       no_service_advanced_vty_cmd,
+       "no service advanced-vty",
+       NO_STR
+       "Set up miscellaneous service\n"
+       "Enable advanced mode vty interface\n")
+{
+  host.advanced = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (terminal_monitor,
+       terminal_monitor_cmd,
+       "terminal monitor",
+       "Set terminal line parameters\n"
+       "Copy debug output to the current terminal line\n")
+{
+  vty->monitor = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (terminal_no_monitor,
+       terminal_no_monitor_cmd,
+       "terminal no monitor",
+       "Set terminal line parameters\n"
+       NO_STR
+       "Copy debug output to the current terminal line\n")
+{
+  vty->monitor = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (show_history,
+       show_history_cmd,
+       "show history",
+       SHOW_STR
+       "Display the session command history\n")
+{
+  int index;
+
+  for (index = vty->hindex + 1; index != vty->hindex;)
+    {
+      if (index == VTY_MAXHIST)
+	{
+	  index = 0;
+	  continue;
+	}
+
+      if (vty->hist[index] != NULL)
+	vty_out (vty, "  %s%s", vty->hist[index], VTY_NEWLINE);
+
+      index++;
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* Display current configuration. */
+int
+vty_config_write (struct vty *vty)
+{
+  vty_out (vty, "line vty%s", VTY_NEWLINE);
+
+  if (vty_accesslist_name)
+    vty_out (vty, " access-class %s%s",
+	     vty_accesslist_name, VTY_NEWLINE);
+
+  if (vty_ipv6_accesslist_name)
+    vty_out (vty, " ipv6 access-class %s%s",
+	     vty_ipv6_accesslist_name, VTY_NEWLINE);
+
+  /* exec-timeout */
+  if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
+    vty_out (vty, " exec-timeout %ld %ld%s", 
+	     vty_timeout_val / 60,
+	     vty_timeout_val % 60, VTY_NEWLINE);
+
+  /* login */
+  if (no_password_check)
+    vty_out (vty, " no login%s", VTY_NEWLINE);
+
+  vty_out (vty, "!%s", VTY_NEWLINE);
+
+  return CMD_SUCCESS;
+}
+
+struct cmd_node vty_node =
+{
+  VTY_NODE,
+  "%s(config-line)# ",
+};
+
+/* Reset all VTY status. */
+void
+vty_reset ()
+{
+  int i;
+  struct vty *vty;
+  struct thread *vty_serv_thread;
+
+  for (i = 0; i < vector_max (vtyvec); i++)
+    if ((vty = vector_slot (vtyvec, i)) != NULL)
+      {
+	buffer_reset (vty->obuf);
+	vty->status = VTY_CLOSE;
+	vty_close (vty);
+      }
+
+  for (i = 0; i < vector_max (Vvty_serv_thread); i++)
+    if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
+      {
+	thread_cancel (vty_serv_thread);
+	vector_slot (Vvty_serv_thread, i) = NULL;
+        close (i);
+      }
+
+  vty_timeout_val = VTY_TIMEOUT_DEFAULT;
+
+  if (vty_accesslist_name)
+    {
+      XFREE(MTYPE_VTY, vty_accesslist_name);
+      vty_accesslist_name = NULL;
+    }
+
+  if (vty_ipv6_accesslist_name)
+    {
+      XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
+      vty_ipv6_accesslist_name = NULL;
+    }
+}
+
+/* for ospf6d easy temprary reload function */
+/* vty_reset + close accept socket */
+void
+vty_finish ()
+{
+  int i;
+  struct vty *vty;
+  struct thread *vty_serv_thread;
+
+  for (i = 0; i < vector_max (vtyvec); i++)
+    if ((vty = vector_slot (vtyvec, i)) != NULL)
+      {
+	buffer_reset (vty->obuf);
+	vty->status = VTY_CLOSE;
+	vty_close (vty);
+      }
+
+  for (i = 0; i < vector_max (Vvty_serv_thread); i++)
+    if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
+      {
+	thread_cancel (vty_serv_thread);
+	vector_slot (Vvty_serv_thread, i) = NULL;
+        close (i);
+      }
+
+  vty_timeout_val = VTY_TIMEOUT_DEFAULT;
+
+  if (vty_accesslist_name)
+    {
+      XFREE(MTYPE_VTY, vty_accesslist_name);
+      vty_accesslist_name = NULL;
+    }
+
+  if (vty_ipv6_accesslist_name)
+    {
+      XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
+      vty_ipv6_accesslist_name = NULL;
+    }
+}
+
+void
+vty_save_cwd ()
+{
+  char *cwd;
+
+  cwd = getcwd (NULL, MAXPATHLEN);
+
+  vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
+  strcpy (vty_cwd, cwd);
+}
+
+char *
+vty_get_cwd ()
+{
+  return vty_cwd;
+}
+
+int
+vty_shell (struct vty *vty)
+{
+  return vty->type == VTY_SHELL ? 1 : 0;
+}
+
+int
+vty_shell_serv (struct vty *vty)
+{
+  return vty->type == VTY_SHELL_SERV ? 1 : 0;
+}
+
+void
+vty_init_vtysh ()
+{
+  vtyvec = vector_init (VECTOR_MIN_SIZE);
+}
+
+/* Install vty's own commands like `who' command. */
+void
+vty_init ()
+{
+  /* For further configuration read, preserve current directory. */
+  vty_save_cwd ();
+
+  vtyvec = vector_init (VECTOR_MIN_SIZE);
+
+  /* Initilize server thread vector. */
+  Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
+
+  /* Install bgp top node. */
+  install_node (&vty_node, vty_config_write);
+
+  install_element (VIEW_NODE, &config_who_cmd);
+  install_element (VIEW_NODE, &show_history_cmd);
+  install_element (ENABLE_NODE, &config_who_cmd);
+  install_element (CONFIG_NODE, &line_vty_cmd);
+  install_element (CONFIG_NODE, &service_advanced_vty_cmd);
+  install_element (CONFIG_NODE, &no_service_advanced_vty_cmd);
+  install_element (CONFIG_NODE, &show_history_cmd);
+  install_element (ENABLE_NODE, &terminal_monitor_cmd);
+  install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
+  install_element (ENABLE_NODE, &show_history_cmd);
+
+  install_default (VTY_NODE);
+  install_element (VTY_NODE, &exec_timeout_min_cmd);
+  install_element (VTY_NODE, &exec_timeout_sec_cmd);
+  install_element (VTY_NODE, &no_exec_timeout_cmd);
+  install_element (VTY_NODE, &vty_access_class_cmd);
+  install_element (VTY_NODE, &no_vty_access_class_cmd);
+  install_element (VTY_NODE, &vty_login_cmd);
+  install_element (VTY_NODE, &no_vty_login_cmd);
+#ifdef HAVE_IPV6
+  install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
+  install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
+#endif /* HAVE_IPV6 */
+}
diff --git a/lib/vty.h b/lib/vty.h
new file mode 100644
index 0000000..4d2a6a0
--- /dev/null
+++ b/lib/vty.h
@@ -0,0 +1,205 @@
+/* Virtual terminal [aka TeletYpe] interface routine
+   Copyright (C) 1997 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 _ZEBRA_VTY_H
+#define _ZEBRA_VTY_H
+
+#define VTY_BUFSIZ 512
+#define VTY_MAXHIST 20
+
+/* VTY struct. */
+struct vty 
+{
+  /* File descripter of this vty. */
+  int fd;
+
+  /* Is this vty connect to file or not */
+  enum {VTY_TERM, VTY_FILE, VTY_SHELL, VTY_SHELL_SERV} type;
+
+  /* Node status of this vty */
+  int node;
+
+  /* What address is this vty comming from. */
+  char *address;
+
+  /* Privilege level of this vty. */
+  int privilege;
+
+  /* Failure count */
+  int fail;
+
+  /* Output buffer. */
+  struct buffer *obuf;
+
+  /* Command input buffer */
+  char *buf;
+
+  /* Command cursor point */
+  int cp;
+
+  /* Command length */
+  int length;
+
+  /* Command max length. */
+  int max;
+
+  /* Histry of command */
+  char *hist[VTY_MAXHIST];
+
+  /* History lookup current point */
+  int hp;
+
+  /* History insert end point */
+  int hindex;
+
+  /* For current referencing point of interface, route-map,
+     access-list etc... */
+  void *index;
+
+  /* For multiple level index treatment such as key chain and key. */
+  void *index_sub;
+
+  /* For escape character. */
+  unsigned char escape;
+
+  /* Current vty status. */
+  enum {VTY_NORMAL, VTY_CLOSE, VTY_MORE, VTY_MORELINE,
+        VTY_START, VTY_CONTINUE} status;
+
+  /* IAC handling */
+  unsigned char iac;
+
+  /* IAC SB handling */
+  unsigned char iac_sb_in_progress;
+  struct buffer *sb_buffer;
+
+  /* Window width/height. */
+  int width;
+  int height;
+
+  int scroll_one;
+
+  /* Configure lines. */
+  int lines;
+
+  /* Current executing function pointer. */
+  int (*func) (struct vty *, void *arg);
+
+  /* Terminal monitor. */
+  int monitor;
+
+  /* In configure mode. */
+  int config;
+
+  /* Read and write thread. */
+  struct thread *t_read;
+  struct thread *t_write;
+
+  /* Timeout seconds and thread. */
+  unsigned long v_timeout;
+  struct thread *t_timeout;
+
+  /* Thread output function. */
+  struct thread *t_output;
+
+  /* Output data pointer. */
+  int (*output_func) (struct vty *, int);
+  void (*output_clean) (struct vty *);
+  void *output_rn;
+  unsigned long output_count;
+  int output_type;
+  void *output_arg;
+};
+
+/* Integrated configuration file. */
+#define INTEGRATE_DEFAULT_CONFIG "Zebra.conf"
+
+/* Small macro to determine newline is newline only or linefeed needed. */
+#define VTY_NEWLINE  ((vty->type == VTY_TERM) ? "\r\n" : "\n")
+
+/* Default time out value */
+#define VTY_TIMEOUT_DEFAULT 600
+
+/* Vty read buffer size. */
+#define VTY_READ_BUFSIZ 512
+
+/* Directory separator. */
+#ifndef DIRECTORY_SEP
+#define DIRECTORY_SEP '/'
+#endif /* DIRECTORY_SEP */
+
+#ifndef IS_DIRECTORY_SEP
+#define IS_DIRECTORY_SEP(c) ((c) == DIRECTORY_SEP)
+#endif
+
+/* GCC have printf type attribute check.  */
+#ifdef __GNUC__
+#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
+#else
+#define PRINTF_ATTRIBUTE(a,b)
+#endif /* __GNUC__ */
+
+/* Utility macro to convert VTY argument to unsigned integer.  */
+#define VTY_GET_INTEGER(NAME,V,STR)                              \
+{                                                                \
+  char *endptr = NULL;                                           \
+  (V) = strtoul ((STR), &endptr, 10);                            \
+  if ((V) == ULONG_MAX || *endptr != '\0')                       \
+    {                                                            \
+      vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \
+      return CMD_WARNING;                                        \
+    }                                                            \
+}
+
+#define VTY_GET_INTEGER_RANGE(NAME,V,STR,MIN,MAX)                \
+{                                                                \
+  char *endptr = NULL;                                           \
+  (V) = strtoul ((STR), &endptr, 10);                            \
+  if ((V) == ULONG_MAX || *endptr != '\0'                        \
+      || (V) < (MIN) || (V) > (MAX))                             \
+    {                                                            \
+      vty_out (vty, "%% Invalid %s value%s", NAME, VTY_NEWLINE); \
+      return CMD_WARNING;                                        \
+    }                                                            \
+}
+
+/* Exported variables */
+extern char integrate_default[];
+
+/* Prototypes. */
+void vty_init (void);
+void vty_init_vtysh (void);
+void vty_reset (void);
+void vty_finish (void);
+struct vty *vty_new (void);
+int vty_out (struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3);
+void vty_read_config (char *, char *, char *);
+void vty_time_print (struct vty *, int);
+void vty_serv_sock (const char *, unsigned short, char *);
+void vty_close (struct vty *);
+char *vty_get_cwd (void);
+void vty_log (const char *, const char *, va_list);
+int vty_config_lock (struct vty *);
+int vty_config_unlock (struct vty *);
+int vty_shell (struct vty *);
+int vty_shell_serv (struct vty *);
+void vty_hello (struct vty *);
+
+#endif /* _ZEBRA_VTY_H */
diff --git a/lib/zclient.c b/lib/zclient.c
new file mode 100644
index 0000000..5e37154
--- /dev/null
+++ b/lib/zclient.c
@@ -0,0 +1,901 @@
+/* Zebra's client library.
+ * Copyright (C) 1999 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.
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "stream.h"
+#include "network.h"
+#include "if.h"
+#include "log.h"
+#include "thread.h"
+#include "zclient.h"
+#include "memory.h"
+#include "table.h"
+
+#include "zebra/rib.h"
+#include "zebra/zserv.h"
+
+/* Zebra client events. */
+enum event {ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT};
+
+/* Prototype for event manager. */
+static void zclient_event (enum event, struct zclient *);
+
+/* This file local debug flag. */
+int zclient_debug = 0;
+
+/* Allocate zclient structure. */
+struct zclient *
+zclient_new ()
+{
+  struct zclient *zclient;
+  zclient = XMALLOC (MTYPE_ZCLIENT, sizeof (struct zclient));
+  memset (zclient, 0, sizeof (struct zclient));
+
+  zclient->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
+  zclient->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ);
+
+  return zclient;
+}
+
+/* Free zclient structure. */
+void
+zclient_free (struct zclient *zclient)
+{
+  XFREE (MTYPE_ZCLIENT, zclient);
+}
+
+/* Initialize zebra client.  Argument redist_default is unwanted
+   redistribute route type. */
+void
+zclient_init (struct zclient *zclient, int redist_default)
+{
+  int i;
+  
+  /* Enable zebra client connection by default. */
+  zclient->enable = 1;
+
+  /* Set -1 to the default socket value. */
+  zclient->sock = -1;
+
+  /* Clear redistribution flags. */
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    zclient->redist[i] = 0;
+
+  /* Set unwanted redistribute route.  bgpd does not need BGP route
+     redistribution. */
+  zclient->redist_default = redist_default;
+  zclient->redist[redist_default] = 1;
+
+  /* Set default-information redistribute to zero. */
+  zclient->default_information = 0;
+
+  /* Schedule first zclient connection. */
+  if (zclient_debug)
+    zlog_info ("zclient start scheduled");
+
+  zclient_event (ZCLIENT_SCHEDULE, zclient);
+}
+
+/* Stop zebra client services. */
+void
+zclient_stop (struct zclient *zclient)
+{
+  if (zclient_debug)
+    zlog_info ("zclient stopped");
+
+  /* Stop threads. */
+  if (zclient->t_read)
+    {
+      thread_cancel (zclient->t_read);
+      zclient->t_read = NULL;
+   }
+  if (zclient->t_connect)
+    {
+      thread_cancel (zclient->t_connect);
+      zclient->t_connect = NULL;
+    }
+
+  /* Close socket. */
+  if (zclient->sock >= 0)
+    {
+      close (zclient->sock);
+      zclient->sock = -1;
+    }
+  zclient->fail = 0;
+}
+
+void
+zclient_reset (struct zclient *zclient)
+{
+  zclient_stop (zclient);
+  zclient_init (zclient, zclient->redist_default);
+}
+
+/* Make socket to zebra daemon. Return zebra socket. */
+int
+zclient_socket ()
+{
+  int sock;
+  int ret;
+  struct sockaddr_in serv;
+
+  /* We should think about IPv6 connection. */
+  sock = socket (AF_INET, SOCK_STREAM, 0);
+  if (sock < 0)
+    return -1;
+  
+  /* Make server socket. */ 
+  memset (&serv, 0, sizeof (struct sockaddr_in));
+  serv.sin_family = AF_INET;
+  serv.sin_port = htons (ZEBRA_PORT);
+#ifdef HAVE_SIN_LEN
+  serv.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+  serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+
+  /* Connect to zebra. */
+  ret = connect (sock, (struct sockaddr *) &serv, sizeof (serv));
+  if (ret < 0)
+    {
+      close (sock);
+      return -1;
+    }
+  return sock;
+}
+
+/* For sockaddr_un. */
+#include <sys/un.h>
+
+int
+zclient_socket_un (char *path)
+{
+  int ret;
+  int sock, len;
+  struct sockaddr_un addr;
+
+  sock = socket (AF_UNIX, SOCK_STREAM, 0);
+  if (sock < 0)
+    return -1;
+  
+  /* Make server socket. */ 
+  memset (&addr, 0, sizeof (struct sockaddr_un));
+  addr.sun_family = AF_UNIX;
+  strncpy (addr.sun_path, path, strlen (path));
+#ifdef HAVE_SUN_LEN
+  len = addr.sun_len = SUN_LEN(&addr);
+#else
+  len = sizeof (addr.sun_family) + strlen (addr.sun_path);
+#endif /* HAVE_SUN_LEN */
+
+  ret = connect (sock, (struct sockaddr *) &addr, len);
+  if (ret < 0)
+    {
+      close (sock);
+      return -1;
+    }
+  return sock;
+}
+
+/* Send simple Zebra message. */
+int
+zebra_message_send (struct zclient *zclient, int command)
+{
+  struct stream *s;
+
+  /* Get zclient output buffer. */
+  s = zclient->obuf;
+  stream_reset (s);
+
+  /* Send very simple command only Zebra message. */
+  stream_putw (s, 3);
+  stream_putc (s, command);
+
+  return writen (zclient->sock, s->data, 3);
+}
+
+/* Make connection to zebra daemon. */
+int
+zclient_start (struct zclient *zclient)
+{
+  int i;
+
+  if (zclient_debug)
+    zlog_info ("zclient_start is called");
+
+  /* zclient is disabled. */
+  if (! zclient->enable)
+    return 0;
+
+  /* If already connected to the zebra. */
+  if (zclient->sock >= 0)
+    return 0;
+
+  /* Check connect thread. */
+  if (zclient->t_connect)
+    return 0;
+
+  /* Make socket. */
+#ifdef HAVE_TCP_ZEBRA
+  zclient->sock = zclient_socket ();
+#else
+  zclient->sock = zclient_socket_un (ZEBRA_SERV_PATH);
+#endif /* HAVE_TCP_ZEBRA */
+  if (zclient->sock < 0)
+    {
+      if (zclient_debug)
+	zlog_info ("zclient connection fail");
+      zclient->fail++;
+      zclient_event (ZCLIENT_CONNECT, zclient);
+      return -1;
+    }
+
+  /* Clear fail count. */
+  zclient->fail = 0;
+  if (zclient_debug)
+    zlog_info ("zclient connect success with socket [%d]", zclient->sock);
+      
+  /* Create read thread. */
+  zclient_event (ZCLIENT_READ, zclient);
+
+  /* We need interface information. */
+  zebra_message_send (zclient, ZEBRA_INTERFACE_ADD);
+
+  /* Flush all redistribute request. */
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    if (i != zclient->redist_default && zclient->redist[i])
+      zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, i);
+
+  /* If default information is needed. */
+  if (zclient->default_information)
+    zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_ADD);
+
+  return 0;
+}
+
+/* This function is a wrapper function for calling zclient_start from
+   timer or event thread. */
+int
+zclient_connect (struct thread *t)
+{
+  struct zclient *zclient;
+
+  zclient = THREAD_ARG (t);
+  zclient->t_connect = NULL;
+
+  if (zclient_debug)
+    zlog_info ("zclient_connect is called");
+
+  return zclient_start (zclient);
+}
+
+int
+zapi_ipv4_add (struct zclient *zclient, struct prefix_ipv4 *p,
+	       struct zapi_ipv4 *api)
+{
+  int i;
+  int psize;
+  struct stream *s;
+
+  /* Reset stream. */
+  s = zclient->obuf;
+  stream_reset (s);
+
+  /* Length place holder. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV4_ROUTE_ADD);
+  stream_putc (s, api->type);
+  stream_putc (s, api->flags);
+  stream_putc (s, api->message);
+  
+  /* Put prefix information. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->prefix, psize);
+
+  /* Nexthop, ifindex, distance and metric information. */
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE))
+	{
+	  stream_putc (s, 1);
+	  stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE);
+	}
+      else
+	stream_putc (s, api->nexthop_num + api->ifindex_num);
+
+      for (i = 0; i < api->nexthop_num; i++)
+	{
+	  stream_putc (s, ZEBRA_NEXTHOP_IPV4);
+	  stream_put_in_addr (s, api->nexthop[i]);
+	}
+      for (i = 0; i < api->ifindex_num; i++)
+	{
+	  stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
+	  stream_putl (s, api->ifindex[i]);
+	}
+    }
+
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE))
+    stream_putc (s, api->distance);
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
+    stream_putl (s, api->metric);
+
+  /* Put length at the first point of the stream. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (zclient->sock, s->data, stream_get_endp (s));
+}
+
+int
+zapi_ipv4_delete (struct zclient *zclient, struct prefix_ipv4 *p,
+		  struct zapi_ipv4 *api)
+{
+  int i;
+  int psize;
+  struct stream *s;
+
+  /* Reset stream. */
+  s = zclient->obuf;
+  stream_reset (s);
+
+  /* Length place holder. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV4_ROUTE_DELETE);
+  stream_putc (s, api->type);
+  stream_putc (s, api->flags);
+  stream_putc (s, api->message);
+  
+  /* Put prefix information. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->prefix, psize);
+
+  /* Nexthop, ifindex, distance and metric information. */
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      if (CHECK_FLAG (api->flags, ZEBRA_FLAG_BLACKHOLE))
+	{
+	  stream_putc (s, 1);
+	  stream_putc (s, ZEBRA_NEXTHOP_BLACKHOLE);
+	}
+      else
+	stream_putc (s, api->nexthop_num + api->ifindex_num);
+
+      for (i = 0; i < api->nexthop_num; i++)
+	{
+	  stream_putc (s, ZEBRA_NEXTHOP_IPV4);
+	  stream_put_in_addr (s, api->nexthop[i]);
+	}
+      for (i = 0; i < api->ifindex_num; i++)
+	{
+	  stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
+	  stream_putl (s, api->ifindex[i]);
+	}
+    }
+
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE))
+    stream_putc (s, api->distance);
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
+    stream_putl (s, api->metric);
+
+  /* Put length at the first point of the stream. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (zclient->sock, s->data, stream_get_endp (s));
+}
+
+#ifdef HAVE_IPV6
+int
+zapi_ipv6_add (struct zclient *zclient, struct prefix_ipv6 *p,
+	       struct zapi_ipv6 *api)
+{
+  int i;
+  int psize;
+  struct stream *s;
+
+  /* Reset stream. */
+  s = zclient->obuf;
+  stream_reset (s);
+
+  /* Length place holder. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV6_ROUTE_ADD);
+  stream_putc (s, api->type);
+  stream_putc (s, api->flags);
+  stream_putc (s, api->message);
+  
+  /* Put prefix information. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->prefix, psize);
+
+  /* Nexthop, ifindex, distance and metric information. */
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      stream_putc (s, api->nexthop_num + api->ifindex_num);
+
+      for (i = 0; i < api->nexthop_num; i++)
+	{
+	  stream_putc (s, ZEBRA_NEXTHOP_IPV6);
+	  stream_write (s, (u_char *)api->nexthop[i], 16);
+	}
+      for (i = 0; i < api->ifindex_num; i++)
+	{
+	  stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
+	  stream_putl (s, api->ifindex[i]);
+	}
+    }
+
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE))
+    stream_putc (s, api->distance);
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
+    stream_putl (s, api->metric);
+
+  /* Put length at the first point of the stream. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (zclient->sock, s->data, stream_get_endp (s));
+}
+
+int
+zapi_ipv6_delete (struct zclient *zclient, struct prefix_ipv6 *p,
+		  struct zapi_ipv6 *api)
+{
+  int i;
+  int psize;
+  struct stream *s;
+
+  /* Reset stream. */
+  s = zclient->obuf;
+  stream_reset (s);
+
+  /* Length place holder. */
+  stream_putw (s, 0);
+
+  /* Put command, type and nexthop. */
+  stream_putc (s, ZEBRA_IPV6_ROUTE_DELETE);
+  stream_putc (s, api->type);
+  stream_putc (s, api->flags);
+  stream_putc (s, api->message);
+  
+  /* Put prefix information. */
+  psize = PSIZE (p->prefixlen);
+  stream_putc (s, p->prefixlen);
+  stream_write (s, (u_char *)&p->prefix, psize);
+
+  /* Nexthop, ifindex, distance and metric information. */
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      stream_putc (s, api->nexthop_num + api->ifindex_num);
+
+      for (i = 0; i < api->nexthop_num; i++)
+	{
+	  stream_putc (s, ZEBRA_NEXTHOP_IPV6);
+	  stream_write (s, (u_char *)api->nexthop[i], 16);
+	}
+      for (i = 0; i < api->ifindex_num; i++)
+	{
+	  stream_putc (s, ZEBRA_NEXTHOP_IFINDEX);
+	  stream_putl (s, api->ifindex[i]);
+	}
+    }
+
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_DISTANCE))
+    stream_putc (s, api->distance);
+  if (CHECK_FLAG (api->message, ZAPI_MESSAGE_METRIC))
+    stream_putl (s, api->metric);
+
+  /* Put length at the first point of the stream. */
+  stream_putw_at (s, 0, stream_get_endp (s));
+
+  return writen (zclient->sock, s->data, stream_get_endp (s));
+}
+
+#endif /* HAVE_IPV6 */
+
+int
+zebra_redistribute_send (int command, int sock, int type)
+{
+  int ret;
+  struct stream *s;
+
+  s = stream_new (ZEBRA_MAX_PACKET_SIZ);
+
+  /* Total length of the messages. */
+  stream_putw (s, 4);
+  
+  stream_putc (s, command);
+  stream_putc (s, type);
+
+  ret = writen (sock, s->data, 4);
+
+  stream_free (s);
+
+  return ret;
+}
+
+/* Interface addition from zebra daemon. */
+struct interface *
+zebra_interface_add_read (struct stream *s)
+{
+  struct interface *ifp;
+  u_char ifname_tmp[INTERFACE_NAMSIZ];
+
+  /* Read interface name. */
+  stream_get (ifname_tmp, s, INTERFACE_NAMSIZ);
+
+  /* Lookup this by interface name. */
+  ifp = if_lookup_by_name (ifname_tmp);
+
+  /* If such interface does not exist, make new one. */
+  if (! ifp)
+    {
+      ifp = if_create ();
+      strncpy (ifp->name, ifname_tmp, IFNAMSIZ);
+    }
+
+  /* Read interface's index. */
+  ifp->ifindex = stream_getl (s);
+
+  /* Read interface's value. */
+  ifp->flags = stream_getl (s);
+  ifp->metric = stream_getl (s);
+  ifp->mtu = stream_getl (s);
+  ifp->bandwidth = stream_getl (s);
+#ifdef HAVE_SOCKADDR_DL
+  stream_get (&ifp->sdl, s, sizeof (ifp->sdl));
+#else
+  ifp->hw_addr_len = stream_getl (s);
+  if (ifp->hw_addr_len)
+    stream_get (ifp->hw_addr, s, ifp->hw_addr_len);
+#endif /* HAVE_SOCKADDR_DL */
+  
+  return ifp;
+}
+
+/* Read interface up/down msg from zebra daemon. */
+struct interface *
+zebra_interface_state_read (struct stream *s)
+{
+  struct interface *ifp;
+  u_char ifname_tmp[INTERFACE_NAMSIZ];
+
+  /* Read interface name. */
+  stream_get (ifname_tmp, s, INTERFACE_NAMSIZ);
+
+  /* Lookup this by interface index. */
+  ifp = if_lookup_by_name (ifname_tmp);
+
+  /* If such interface does not exist, indicate an error */
+  if (! ifp)
+     return NULL;
+
+  /* Read interface's index. */
+  ifp->ifindex = stream_getl (s);
+
+  /* Read interface's value. */
+  ifp->flags = stream_getl (s);
+  ifp->metric = stream_getl (s);
+  ifp->mtu = stream_getl (s);
+  ifp->bandwidth = stream_getl (s);
+
+  return ifp;
+}
+
+struct connected *
+zebra_interface_address_add_read (struct stream *s)
+{
+  unsigned int ifindex;
+  struct interface *ifp;
+  struct connected *ifc;
+  struct prefix *p;
+  int family;
+  int plen;
+
+  /* Get interface index. */
+  ifindex = stream_getl (s);
+
+  /* Lookup index. */
+  ifp = if_lookup_by_index (ifindex);
+  if (ifp == NULL)
+    {
+      zlog_warn ("zebra_interface_address_add_read: Can't find interface by ifindex: %d ", ifindex);
+      return NULL;
+    }
+
+  /* Allocate new connected address. */
+  ifc = connected_new ();
+  ifc->ifp = ifp;
+
+  /* Fetch flag. */
+  ifc->flags = stream_getc (s);
+
+  /* Fetch interface address. */
+  p = prefix_new ();
+  family = p->family = stream_getc (s);
+
+  plen = prefix_blen (p);
+  stream_get (&p->u.prefix, s, plen);
+  p->prefixlen = stream_getc (s);
+  ifc->address = p;
+
+  /* Fetch destination address. */
+  p = prefix_new ();
+  stream_get (&p->u.prefix, s, plen);
+  p->family = family;
+
+  ifc->destination = p;
+
+  p = ifc->address;
+
+  /* Add connected address to the interface. */
+  listnode_add (ifp->connected, ifc);
+
+  return ifc;
+}
+
+struct connected *
+zebra_interface_address_delete_read (struct stream *s)
+{
+  unsigned int ifindex;
+  struct interface *ifp;
+  struct connected *ifc;
+  struct prefix p;
+  struct prefix d;
+  int family;
+  int len;
+  u_char flags;
+
+  /* Get interface index. */
+  ifindex = stream_getl (s);
+
+  /* Lookup index. */
+  ifp = if_lookup_by_index (ifindex);
+  if (ifp == NULL)
+    {
+      zlog_warn ("zebra_interface_address_delete_read: Can't find interface by ifindex: %d ", ifindex);
+      return NULL;
+    }
+
+  /* Fetch flag. */
+  flags = stream_getc (s);
+
+  /* Fetch interface address. */
+  family = p.family = stream_getc (s);
+
+  len = prefix_blen (&p);
+  stream_get (&p.u.prefix, s, len);
+  p.prefixlen = stream_getc (s);
+
+  /* Fetch destination address. */
+  stream_get (&d.u.prefix, s, len);
+  d.family = family;
+
+  ifc = connected_delete_by_prefix (ifp, &p);
+
+  return ifc;
+}
+
+/* Zebra client message read function. */
+int
+zclient_read (struct thread *thread)
+{
+  int ret;
+  int nbytes;
+  int sock;
+  zebra_size_t length;
+  zebra_command_t command;
+  struct zclient *zclient;
+
+  /* Get socket to zebra. */
+  sock = THREAD_FD (thread);
+  zclient = THREAD_ARG (thread);
+  zclient->t_read = NULL;
+
+  /* Clear input buffer. */
+  stream_reset (zclient->ibuf);
+
+  /* Read zebra header. */
+  nbytes = stream_read (zclient->ibuf, sock, ZEBRA_HEADER_SIZE);
+
+  /* zebra socket is closed. */
+  if (nbytes == 0) 
+    {
+      if (zclient_debug)
+	zlog_info ("zclient connection closed socket [%d].", sock);
+      zclient->fail++;
+      zclient_stop (zclient);
+      zclient_event (ZCLIENT_CONNECT, zclient);
+      return -1;
+    }
+
+  /* zebra read error. */
+  if (nbytes < 0 || nbytes != ZEBRA_HEADER_SIZE)
+    {
+      if (zclient_debug)
+	zlog_info ("Can't read all packet (length %d).", nbytes);
+      zclient->fail++;
+      zclient_stop (zclient);
+      zclient_event (ZCLIENT_CONNECT, zclient);
+      return -1;
+    }
+
+  /* Fetch length and command. */
+  length = stream_getw (zclient->ibuf);
+  command = stream_getc (zclient->ibuf);
+
+  /* Length check. */
+  if (length >= zclient->ibuf->size)
+    {
+      stream_free (zclient->ibuf);
+      zclient->ibuf = stream_new (length + 1);
+    }
+  length -= ZEBRA_HEADER_SIZE;
+
+  /* Read rest of zebra packet. */
+  nbytes = stream_read (zclient->ibuf, sock, length);
+ if (nbytes != length)
+   {
+     if (zclient_debug)
+       zlog_info ("zclient connection closed socket [%d].", sock);
+     zclient->fail++;
+     zclient_stop (zclient);
+     zclient_event (ZCLIENT_CONNECT, zclient);
+     return -1;
+   }
+
+  switch (command)
+    {
+    case ZEBRA_INTERFACE_ADD:
+      if (zclient->interface_add)
+	ret = (*zclient->interface_add) (command, zclient, length);
+      break;
+    case ZEBRA_INTERFACE_DELETE:
+      if (zclient->interface_delete)
+	ret = (*zclient->interface_delete) (command, zclient, length);
+      break;
+    case ZEBRA_INTERFACE_ADDRESS_ADD:
+      if (zclient->interface_address_add)
+	ret = (*zclient->interface_address_add) (command, zclient, length);
+      break;
+    case ZEBRA_INTERFACE_ADDRESS_DELETE:
+      if (zclient->interface_address_delete)
+	ret = (*zclient->interface_address_delete) (command, zclient, length);
+      break;
+    case ZEBRA_INTERFACE_UP:
+      if (zclient->interface_up)
+	ret = (*zclient->interface_up) (command, zclient, length);
+      break;
+    case ZEBRA_INTERFACE_DOWN:
+      if (zclient->interface_down)
+	ret = (*zclient->interface_down) (command, zclient, length);
+      break;
+    case ZEBRA_IPV4_ROUTE_ADD:
+      if (zclient->ipv4_route_add)
+	ret = (*zclient->ipv4_route_add) (command, zclient, length);
+      break;
+    case ZEBRA_IPV4_ROUTE_DELETE:
+      if (zclient->ipv4_route_delete)
+	ret = (*zclient->ipv4_route_delete) (command, zclient, length);
+      break;
+    case ZEBRA_IPV6_ROUTE_ADD:
+      if (zclient->ipv6_route_add)
+	ret = (*zclient->ipv6_route_add) (command, zclient, length);
+      break;
+    case ZEBRA_IPV6_ROUTE_DELETE:
+      if (zclient->ipv6_route_delete)
+	ret = (*zclient->ipv6_route_delete) (command, zclient, length);
+      break;
+    default:
+      break;
+    }
+
+  /* Register read thread. */
+  zclient_event (ZCLIENT_READ, zclient);
+
+  return 0;
+}
+
+void
+zclient_redistribute_set (struct zclient *zclient, int type)
+{
+  if (zclient->redist[type])
+    return;
+
+  zclient->redist[type] = 1;
+
+  if (zclient->sock > 0)
+    zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, type);
+}
+
+void
+zclient_redistribute_unset (struct zclient *zclient, int type)
+{
+  if (! zclient->redist[type])
+    return;
+
+  zclient->redist[type] = 0;
+
+  if (zclient->sock > 0)
+    zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type);
+}
+
+void
+zclient_redistribute_default_set (struct zclient *zclient)
+{
+  if (zclient->default_information)
+    return;
+
+  zclient->default_information = 1;
+
+  if (zclient->sock > 0)
+    zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_ADD);
+}
+
+void
+zclient_redistribute_default_unset (struct zclient *zclient)
+{
+  if (! zclient->default_information)
+    return;
+
+  zclient->default_information = 0;
+
+  if (zclient->sock > 0)
+    zebra_message_send (zclient, ZEBRA_REDISTRIBUTE_DEFAULT_DELETE);
+}
+
+extern struct thread_master *master;
+
+static void
+zclient_event (enum event event, struct zclient *zclient)
+{
+  switch (event)
+    {
+    case ZCLIENT_SCHEDULE:
+      if (! zclient->t_connect)
+	zclient->t_connect =
+	  thread_add_event (master, zclient_connect, zclient, 0);
+      break;
+    case ZCLIENT_CONNECT:
+      if (zclient->fail >= 10)
+	return;
+      if (zclient_debug)
+	zlog_info ("zclient connect schedule interval is %d", 
+		   zclient->fail < 3 ? 10 : 60);
+      if (! zclient->t_connect)
+	zclient->t_connect = 
+	  thread_add_timer (master, zclient_connect, zclient,
+			    zclient->fail < 3 ? 10 : 60);
+      break;
+    case ZCLIENT_READ:
+      zclient->t_read = 
+	thread_add_read (master, zclient_read, zclient, zclient->sock);
+      break;
+    }
+}
diff --git a/lib/zclient.h b/lib/zclient.h
new file mode 100644
index 0000000..66307c9
--- /dev/null
+++ b/lib/zclient.h
@@ -0,0 +1,164 @@
+/* Zebra's client header.
+ * Copyright (C) 1999 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 _ZEBRA_ZCLIENT_H
+#define _ZEBRA_ZCLIENT_H
+
+/* For struct interface and struct connected. */
+#include "if.h"
+
+/* For input/output buffer to zebra. */
+#define ZEBRA_MAX_PACKET_SIZ          4096
+
+/* Zebra header size. */
+#define ZEBRA_HEADER_SIZE                3
+
+/* Structure for the zebra client. */
+struct zclient
+{
+  /* Socket to zebra daemon. */
+  int sock;
+
+  /* Flag of communication to zebra is enabled or not.  Default is on.
+     This flag is disabled by `no router zebra' statement. */
+  int enable;
+
+  /* Connection failure count. */
+  int fail;
+
+  /* Input buffer for zebra message. */
+  struct stream *ibuf;
+
+  /* Output buffer for zebra message. */
+  struct stream *obuf;
+
+  /* Read and connect thread. */
+  struct thread *t_read;
+  struct thread *t_connect;
+
+  /* Redistribute information. */
+  u_char redist_default;
+  u_char redist[ZEBRA_ROUTE_MAX];
+
+  /* Redistribute defauilt. */
+  u_char default_information;
+
+  /* Pointer to the callback functions. */
+  int (*interface_add) (int, struct zclient *, zebra_size_t);
+  int (*interface_delete) (int, struct zclient *, zebra_size_t);
+  int (*interface_up) (int, struct zclient *, zebra_size_t);
+  int (*interface_down) (int, struct zclient *, zebra_size_t);
+  int (*interface_address_add) (int, struct zclient *, zebra_size_t);
+  int (*interface_address_delete) (int, struct zclient *, zebra_size_t);
+  int (*ipv4_route_add) (int, struct zclient *, zebra_size_t);
+  int (*ipv4_route_delete) (int, struct zclient *, zebra_size_t);
+  int (*ipv6_route_add) (int, struct zclient *, zebra_size_t);
+  int (*ipv6_route_delete) (int, struct zclient *, zebra_size_t);
+};
+
+/* Zebra API message flag. */
+#define ZAPI_MESSAGE_NEXTHOP  0x01
+#define ZAPI_MESSAGE_IFINDEX  0x02
+#define ZAPI_MESSAGE_DISTANCE 0x04
+#define ZAPI_MESSAGE_METRIC   0x08
+
+/* Zebra IPv4 route message API. */
+struct zapi_ipv4
+{
+  u_char type;
+
+  u_char flags;
+
+  u_char message;
+
+  u_char nexthop_num;
+  struct in_addr **nexthop;
+
+  u_char ifindex_num;
+  unsigned int *ifindex;
+
+  u_char distance;
+
+  u_int32_t metric;
+};
+
+int
+zapi_ipv4_add (struct zclient *, struct prefix_ipv4 *, struct zapi_ipv4 *);
+
+int
+zapi_ipv4_delete (struct zclient *, struct prefix_ipv4 *, struct zapi_ipv4 *);
+
+/* Prototypes of zebra client service functions. */
+struct zclient *zclient_new (void);
+void zclient_free (struct zclient *);
+void zclient_init (struct zclient *, int);
+int zclient_start (struct zclient *);
+void zclient_stop (struct zclient *);
+void zclient_reset (struct zclient *);
+int zclient_socket ();
+int zclient_socket_un (char *);
+
+void zclient_redistribute_set (struct zclient *, int);
+void zclient_redistribute_unset (struct zclient *, int);
+
+void zclient_redistribute_default_set (struct zclient *);
+void zclient_redistribute_default_unset (struct zclient *);
+
+/* struct zebra *zebra_new (); */
+int zebra_redistribute_send (int, int, int);
+
+struct interface *zebra_interface_add_read (struct stream *);
+struct interface *zebra_interface_state_read (struct stream *s);
+struct connected *zebra_interface_address_add_read (struct stream *);
+struct connected *zebra_interface_address_delete_read (struct stream *);
+
+#ifdef HAVE_IPV6
+/* IPv6 prefix add and delete function prototype. */
+
+struct zapi_ipv6
+{
+  u_char type;
+
+  u_char flags;
+
+  u_char message;
+
+  u_char nexthop_num;
+  struct in6_addr **nexthop;
+
+  u_char ifindex_num;
+  unsigned int *ifindex;
+
+  u_char distance;
+
+  u_int32_t metric;
+};
+
+int
+zapi_ipv6_add (struct zclient *zclient, struct prefix_ipv6 *p,
+	       struct zapi_ipv6 *api);
+int
+zapi_ipv6_delete (struct zclient *zclient, struct prefix_ipv6 *p,
+		  struct zapi_ipv6 *api);
+
+#endif /* HAVE_IPV6 */
+
+#endif /* _ZEBRA_ZCLIENT_H */
diff --git a/lib/zebra.h b/lib/zebra.h
new file mode 100644
index 0000000..06302b3
--- /dev/null
+++ b/lib/zebra.h
@@ -0,0 +1,312 @@
+/* Zebra common header.
+   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 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 _ZEBRA_H
+#define _ZEBRA_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef SUNOS_5
+#define _XPG4_2
+#define __EXTENSIONS__
+#endif /* SUNOS_5 */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#ifdef HAVE_STROPTS_H
+#include <stropts.h>
+#endif /* HAVE_STROPTS_H */
+#include <sys/fcntl.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif /* HAVE_SYS_SELECT_H */
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif /* HAVE_SYS_SYSCTL_H */
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_CONF_H
+#include <sys/conf.h>
+#endif /* HAVE_SYS_CONF_H */
+#ifdef HAVE_SYS_KSYM_H
+#include <sys/ksym.h>
+#endif /* HAVE_SYS_KSYM_H */
+#include <syslog.h>
+#include <time.h>
+#include <sys/uio.h>
+#include <sys/utsname.h>
+#ifdef HAVE_RUSAGE
+#include <sys/resource.h>
+#endif /* HAVE_RUSAGE */
+
+/* machine dependent includes */
+#ifdef SUNOS_5
+#include <limits.h>
+#include <strings.h>
+#endif /* SUNOS_5 */
+
+/* machine dependent includes */
+#ifdef HAVE_LINUX_VERSION_H
+#include <linux/version.h>
+#endif /* HAVE_LINUX_VERSION_H */
+
+#ifdef HAVE_ASM_TYPES_H
+#include <asm/types.h>
+#endif /* HAVE_ASM_TYPES_H */
+
+/* misc include group */
+#include <stdarg.h>
+#include <assert.h>
+
+/* network include group */
+
+#include <sys/socket.h>
+
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif /* HAVE_SYS_SOCKIO_H */
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif /* HAVE_NETINET_IN_H */
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+#ifdef HAVE_NET_NETOPT_H
+#include <net/netopt.h>
+#endif /* HAVE_NET_NETOPT_H */
+
+#include <net/if.h>
+
+#ifdef HAVE_NET_IF_DL_H
+#include <net/if_dl.h>
+#endif /* HAVE_NET_IF_DL_H */
+
+#ifdef HAVE_NET_IF_VAR_H
+#include <net/if_var.h>
+#endif /* HAVE_NET_IF_VAR_H */
+
+#include <net/route.h>
+
+#ifdef HAVE_NETLINK
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#else
+#define RT_TABLE_MAIN		0
+#endif /* HAVE_NETLINK */
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif /* HAVE_NETDB_H */
+
+#include <arpa/inet.h>
+#include <arpa/telnet.h>
+
+#ifdef HAVE_INET_ND_H
+#include <inet/nd.h>
+#endif /* HAVE_INET_ND_H */
+
+#ifdef HAVE_NETINET_IN_VAR_H
+#include <netinet/in_var.h>
+#endif /* HAVE_NETINET_IN_VAR_H */
+
+#ifdef HAVE_NETINET_IN6_VAR_H
+#include <netinet/in6_var.h>
+#endif /* HAVE_NETINET_IN6_VAR_H */
+
+#ifdef HAVE_NETINET6_IN_H
+#include <netinet6/in.h>
+#endif /* HAVE_NETINET6_IN_H */
+
+
+#ifdef HAVE_NETINET6_IP6_H
+#include <netinet6/ip6.h>
+#endif /* HAVE_NETINET6_IP6_H */
+
+#ifdef HAVE_NETINET_ICMP6_H
+#include <netinet/icmp6.h>
+#endif /* HAVE_NETINET_ICMP6_H */
+
+#ifdef HAVE_NETINET6_ND6_H
+#include <netinet6/nd6.h>
+#endif /* HAVE_NETINET6_ND6_H */
+
+#ifdef HAVE_LIBUTIL_H
+#include <libutil.h>
+#endif /* HAVE_LIBUTIL_H */
+
+#ifdef BSDI_NRL
+
+#ifdef HAVE_NETINET6_IN6_H
+#include <netinet6/in6.h>
+#endif /* HAVE_NETINET6_IN6_H */
+
+#ifdef NRL
+#include <netinet6/in6.h>
+#endif /* NRL */
+
+#define IN6_ARE_ADDR_EQUAL IN6_IS_ADDR_EQUAL
+
+/* BSD/OS 4.0 has lost belows defines, it should appear at
+   /usr/include/sys/socket.h.  */
+#define CMSG_ALIGN(n)           (((n) + 3) & ~3)
+#define CMSG_SPACE(l)   (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(l))
+#define CMSG_LEN(l)     (CMSG_ALIGN(sizeof(struct cmsghdr)) + (l))
+
+#endif /* BSDI_NRL */
+
+/*  The definition of struct in_pktinfo is missing in old version of
+    GLIBC 2.1 (Redhat 6.1).  */
+#if defined (GNU_LINUX) && ! defined (HAVE_INPKTINFO)
+struct in_pktinfo
+{
+  int ipi_ifindex;
+  struct in_addr ipi_spec_dst;
+  struct in_addr ipi_addr;
+};
+#endif
+
+/* For old definition. */
+#ifndef IN6_ARE_ADDR_EQUAL
+#define IN6_ARE_ADDR_EQUAL IN6_IS_ADDR_EQUAL
+#endif /* IN6_ARE_ADDR_EQUAL */
+
+/* Zebra message types. */
+#define ZEBRA_INTERFACE_ADD                1
+#define ZEBRA_INTERFACE_DELETE             2
+#define ZEBRA_INTERFACE_ADDRESS_ADD        3
+#define ZEBRA_INTERFACE_ADDRESS_DELETE     4
+#define ZEBRA_INTERFACE_UP                 5
+#define ZEBRA_INTERFACE_DOWN               6
+#define ZEBRA_IPV4_ROUTE_ADD               7
+#define ZEBRA_IPV4_ROUTE_DELETE            8
+#define ZEBRA_IPV6_ROUTE_ADD               9
+#define ZEBRA_IPV6_ROUTE_DELETE           10
+#define ZEBRA_REDISTRIBUTE_ADD            11
+#define ZEBRA_REDISTRIBUTE_DELETE         12
+#define ZEBRA_REDISTRIBUTE_DEFAULT_ADD    13
+#define ZEBRA_REDISTRIBUTE_DEFAULT_DELETE 14
+#define ZEBRA_IPV4_NEXTHOP_LOOKUP         15
+#define ZEBRA_IPV6_NEXTHOP_LOOKUP         16
+#define ZEBRA_IPV4_IMPORT_LOOKUP          17
+#define ZEBRA_IPV6_IMPORT_LOOKUP          18
+#define ZEBRA_MESSAGE_MAX                 19
+
+/* Zebra route's types. */
+#define ZEBRA_ROUTE_SYSTEM               0
+#define ZEBRA_ROUTE_KERNEL               1
+#define ZEBRA_ROUTE_CONNECT              2
+#define ZEBRA_ROUTE_STATIC               3
+#define ZEBRA_ROUTE_RIP                  4
+#define ZEBRA_ROUTE_RIPNG                5
+#define ZEBRA_ROUTE_OSPF                 6
+#define ZEBRA_ROUTE_OSPF6                7
+#define ZEBRA_ROUTE_BGP                  8
+#define ZEBRA_ROUTE_MAX                  9
+
+/* Zebra's family types. */
+#define ZEBRA_FAMILY_IPV4                1
+#define ZEBRA_FAMILY_IPV6                2
+#define ZEBRA_FAMILY_MAX                 3
+
+/* Error codes of zebra. */
+#define ZEBRA_ERR_RTEXIST               -1
+#define ZEBRA_ERR_RTUNREACH             -2
+#define ZEBRA_ERR_EPERM                 -3
+#define ZEBRA_ERR_RTNOEXIST             -4
+
+/* Zebra message flags */
+#define ZEBRA_FLAG_INTERNAL           0x01
+#define ZEBRA_FLAG_SELFROUTE          0x02
+#define ZEBRA_FLAG_BLACKHOLE          0x04
+#define ZEBRA_FLAG_IBGP               0x08
+#define ZEBRA_FLAG_SELECTED           0x10
+#define ZEBRA_FLAG_CHANGED            0x20
+#define ZEBRA_FLAG_STATIC             0x40
+
+/* Zebra nexthop flags. */
+#define ZEBRA_NEXTHOP_IFINDEX            1
+#define ZEBRA_NEXTHOP_IFNAME             2
+#define ZEBRA_NEXTHOP_IPV4               3
+#define ZEBRA_NEXTHOP_IPV4_IFINDEX       4
+#define ZEBRA_NEXTHOP_IPV4_IFNAME        5
+#define ZEBRA_NEXTHOP_IPV6               6
+#define ZEBRA_NEXTHOP_IPV6_IFINDEX       7
+#define ZEBRA_NEXTHOP_IPV6_IFNAME        8
+#define ZEBRA_NEXTHOP_BLACKHOLE          9 
+
+#ifndef INADDR_LOOPBACK
+#define	INADDR_LOOPBACK	0x7f000001	/* Internet address 127.0.0.1.  */
+#endif
+
+/* Address family numbers from RFC1700. */
+#define AFI_IP                    1
+#define AFI_IP6                   2
+#define AFI_MAX                   3
+
+/* Subsequent Address Family Identifier. */
+#define SAFI_UNICAST              1
+#define SAFI_MULTICAST            2
+#define SAFI_UNICAST_MULTICAST    3
+#define SAFI_MPLS_VPN             4
+#define SAFI_MAX                  5
+
+/* Filter direction.  */
+#define FILTER_IN                 0
+#define FILTER_OUT                1
+#define FILTER_MAX                2
+
+/* Default Administrative Distance of each protocol. */
+#define ZEBRA_KERNEL_DISTANCE_DEFAULT      0
+#define ZEBRA_CONNECT_DISTANCE_DEFAULT     0
+#define ZEBRA_STATIC_DISTANCE_DEFAULT      1
+#define ZEBRA_RIP_DISTANCE_DEFAULT       120
+#define ZEBRA_RIPNG_DISTANCE_DEFAULT     120
+#define ZEBRA_OSPF_DISTANCE_DEFAULT      110
+#define ZEBRA_OSPF6_DISTANCE_DEFAULT     110
+#define ZEBRA_IBGP_DISTANCE_DEFAULT      200
+#define ZEBRA_EBGP_DISTANCE_DEFAULT       20
+
+/* Flag manipulation macros. */
+#define CHECK_FLAG(V,F)      ((V) & (F))
+#define SET_FLAG(V,F)        (V) = (V) | (F)
+#define UNSET_FLAG(V,F)      (V) = (V) & ~(F)
+
+/* AFI and SAFI type. */
+typedef u_int16_t afi_t;
+typedef u_char safi_t;
+
+/* Zebra types. */
+typedef u_int16_t zebra_size_t;
+typedef u_int8_t zebra_command_t;
+
+#endif /* _ZEBRA_H */