Initial revision
diff --git a/ripd/.cvsignore b/ripd/.cvsignore
new file mode 100644
index 0000000..1f91515
--- /dev/null
+++ b/ripd/.cvsignore
@@ -0,0 +1,7 @@
+Makefile
+*.o
+ripd
+ripd.conf
+tags
+TAGS
+.deps
diff --git a/ripd/ChangeLog b/ripd/ChangeLog
new file mode 100644
index 0000000..42fced5
--- /dev/null
+++ b/ripd/ChangeLog
@@ -0,0 +1,749 @@
+2002-07-07  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+	* zebra-0.93 released.
+
+2002-06-30  Kunihiro Ishiguro  <kunihiro@ipinfusion.com>
+
+	* ripd.c (rip_output_process): When outgoing interface is same as
+	next hop interface, announce RIPv2 next hop otherwise set next hop
+	to 0.  Revert previous change then take 6WIND way.
+
+2001-09-14  Akihiro Mizutani <mizutani@dml.com>
+
+	* ripd.c: RIP enabled interface's route is advertised by default.
+
+2001-08-28  NOGUCHI Kay <kay@v6.access.co.jp>
+
+	* rip_snmp.c (rip_ifaddr_delete): Add route_node_lookup() return
+	value check.
+
+	* rip_interface.c (rip_multicast_leave): Fix bug of multiple IP
+	address on one interface multicast join/leave bug.
+
+2001-08-26  NOGUCHI Kay <kay@v6.access.co.jp>
+
+	* rip_interface.c (no_rip_passive_interface): Add NO_STR.
+
+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-06-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_routemap.c (route_match_ip_address_prefix_list): Add match
+	ip next-hop prefix-list WORD.
+
+2001-02-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_interface.c (rip_passive_interface_clean): Call
+	rip_passive_interface_apply_all.
+
+2001-02-12  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_response_process): Multicast address nexthop check
+	is moved from rip_nexthop_check.
+
+2001-02-08  Matthew Grant <grantma@anathoth.gen.nz>
+
+	* rip_interface.c (ipv4_multicast_join): Use
+	setsockopt_multicast_ipv4.
+	(ipv4_multicast_leave): Likewise.
+	(rip_if_ipv4_address_check): Interface which has IPv4 address can
+	be enabled.
+
+2001-02-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_interface.c (rip_interface_delete): To support pseudo
+	interface do not free interface structure.
+	* ripd.c (rip_output_process): If output interface is in simple
+	password authentication mode, we need space for authentication
+	data.
+
+2001-02-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_nexthop_check): Fix multicast address nexthop check.
+
+	* zebra-0.91 is released.
+
+2001-01-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (show_ip_rip): Show metric infinity route's timeout.
+	(rip_rte_process): If current route is metric infinity, route is
+	replaced with received rte.
+	(rip_redistribute_delete): When redistribute route is deleted,
+	perform poisoned reverse.
+	(rip_redistribute_withdraw): Likewise.
+
+2001-01-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_response_process): RIPv2 routing table entry with
+	non directly reachable nexthop was dropped.  The code is changed
+	to treat it as 0.0.0.0 nexthop.
+	(rip_destination_check): Check net 0 address destination.
+	(rip_nexthop_check): New function for checking nexthop address
+	validity.
+
+2001-01-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_request_process): Triggered update only send changed
+	route.
+
+	* rip_interface.c: Delete RIP_API part until new implementation
+	comes out.
+
+	* rip_snmp.: Likewise.
+
+	* rip_zebra.c: Likewise.
+
+	* ripd.c: Likewise. 
+
+2001-01-11  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_interface.c (rip_if_init): Remove HAVE_IF_PSEUDO part.
+
+2001-01-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra-0.90 is released.
+
+2001-01-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.h (RIP_VTYSH_PATH): Change "/tmp/ripd" to "/tmp/.ripd".
+
+2000-12-25  David Lipovkov <davidl@nbase.co.il>
+
+	* ripd.c (rip_rte_process): When a route is in garbage collection
+	process (invalid with metric 16) and a router receives the same
+	route with valid metric then route was not installed into zebra
+	rib, but only into ripd rib. Moreover , it will never get into
+	zebra rib, because ripd wrongly assumes it's already there.
+	(rip_redistribute_add): When doing redistribute into rip other
+	route (e.g. connected) and the same route exists in ripd rib we
+	changed it in place - bug. Now we don't forget to remove old route
+	from zebra.
+	(rip_timeout): When removing routes from zebra I made sure that we
+	remove route with the metric we have in zebra and not the new
+	one. It doesn't make a difference now,but could be significant
+	when multipath support is done.
+
+2000-12-25  David Lipovkov <davidl@nbase.co.il>
+
+	* rip_zebra.c (rip_metric_unset): Fix bug of metric value unset.
+
+2000-11-25  Frank van Maarseveen <F.vanMaarseveen@inter.NL.net>
+
+	* ripd.c (rip_request_process): Check passive flag of the
+	interface.
+
+2000-11-23  Frank van Maarseveen <F.vanMaarseveen@inter.NL.net>
+
+	* rip_interface.c (rip_multicast_join): When IP_ADD_MEMBERSHIP
+	failed do not set runnning flag to the interface.
+
+2000-11-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_output_process): Memory leak related classfull
+	network generation is fixed.
+
+2000-11-16  Frank van Maarseveen <F.vanMaarseveen@inter.NL.net>
+
+	* rip_interface.c (if_check_address): Obsolete pointopoint address
+	check is removed.
+
+2000-11-02  Frank van Maarseveen <F.vanMaarseveen@inter.NL.net>
+
+	* rip_interface.c (if_check_address): Add pointopoint address
+	check.
+	(rip_interface_up): Add check for passive interface when interface
+	goes up.
+
+2000-10-23  Jochen Friedrich <jochen@scram.de>
+
+	* rip_snmp.c: rip_oid and ripd_oid are used in smux_open after it
+	is registered.  So those variables must be static.
+
+2000-10-19  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_interface.c: Change to "no ip rip (send|receive)" command
+	accept version number argument.
+
+2000-10-17  Akihiro Mizutani <mizutani@dml.com>
+
+	* rip_routemap.c (route_set_ip_nexthop_compile): Change "match ip
+	next-hop" from IP address to access-list name.
+
+2000-10-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_peer.c: Change ot use linklist.c instaed of newlist.c.
+
+2000-10-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_offset.c: Change to use linklist.c instead of newlist.c.
+
+2000-10-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* zebra-0.89 is released.
+
+2000-09-26  Akihiro Mizutani <mizutani@dml.com>
+
+	* rip_routemap.c (match_ip_nexthop): Add next-hop format check.
+
+2000-09-18  David Lipovkov <dlipovkov@OpticalAccess.com>
+
+	* rip_interface.c (ripd_api_get_if_rx_version): Corrects rip SNMP
+	and rip API functions dealing with rip version.
+
+	* rip_snmp.c (Status_Valid): SNMPv2-TC TEXTUAL-CONVENTION.
+
+2000-09-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_snmp.c (rip2IfLookup): Use rip_ifaddr_lookup_next() instead
+	of rip_if_lookup_next().
+
+	* rip_interface.c (rip_enable_network_lookup): Interface enable
+	check by interface's address with /32 prefix.
+
+	* ripd.c (rip_read): When RIP is configured with authentication
+	and no authentication in incoming packet, drop the packet.
+
+	* rip_interface.c (rip_interface_reset): RIP_AUTH_SIMPLE_PASSWORD
+	is default mode of authentication.
+	(rip_interface_new): Likewise.
+	(no_ip_rip_authentication_mode): Likewise.
+
+	* ripd.c (rip_read): Likewise.
+
+2000-09-10  David Lipovkov <davidl@nbase.co.il>
+
+	* rip_snmp.c: Set ASN_INTEGER v->type where it is needed.
+
+2000-09-08  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_auth_simple_password): Simple password
+	authentication using key-chain.
+	(rip_write_rte): Likewise.
+
+	* rip_interface.c (ip_rip_authentication_key_chain): Add check for
+	authentication string configuration.
+
+2000-09-08  Akihiro Mizutani <mizutani@dml.com>
+
+	* ripd.c (rip_write_rte): Add check for ri->auth_str.
+
+2000-09-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd_api.h: New file is added.
+
+2000-08-22  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_rte_process): rip_route_process() is renamed to
+	rip_rte_process() to clarify meanings of the function.
+	rip_route_process() is newly added to process RIP route selection.
+
+2000-08-18  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_incoming_filter): Extract incoming filter code to
+	function from rip_route_process(). Add check for all interface
+	filter.
+	(rip_outgoing_filter): Extract incoming filter code to function
+	from rip_output_process().  Add check for all interface filter.
+
+	* rip_zebra.c (rip_redistribute_clean): Reset redistribute status
+	when "no router rip" is performed.
+
+	* rip_interface.c (rip_interface_clean): Reset interface's RIP
+	enable status.
+
+2000-08-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_route_process): When metric infinity is received the
+	route is removed from service immediately.
+	(rip_timeout): Likewise.
+	(rip_garbage_collect): Do not delete route in garbage collection.
+	(rip_output_process): Check metric_out exceed metric infinity.
+
+	* zebra-0.88 is released.
+
+2000-08-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_distance_apply): Unlock node when there is matched
+	node.
+
+2000-08-13  Akihiro Mizutani <mizutani@dml.com>
+
+	* rip_routemap.c (match_ip_nexthop): Add check for IP address
+	validness.
+	(no_set_metric): Add new ALIAS.
+
+2000-08-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.h (struct rip ): Add distance.
+
+2000-08-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_zebra.c (rip_zebra_ipv4_add): Use new Zebra api to register
+	routes.  Pass RIP metric value to zebra.
+
+2000-08-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_main.c (main): Make struct thread thread from global
+	variable to local variable in main.
+
+2000-08-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_packet_dump): Add MD5 authentication dump function.
+	(rip_auth_md5): RIP MD5 authentication packet receive works.
+
+2000-08-02  David Lipovkov <davidl@nbase.co.il>
+
+	* rip_interface.c (rip_if_init): Install interface "pseudo"
+	commands.
+	(rip_interface_delete): Do not call if_delete() when interface is
+	pseudo interface.
+
+2000-07-31  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_interface.c (ip_rip_authentication_mode): "ip rip
+	authentication mode (md5|text)" is added.
+	(ip_rip_authentication_key_chain): "ip rip authentication
+	key-chain KEY-CHAIN" is added.
+	(rip_interface_clean): Clean all interface configuration.
+	(rip_interface_reset): Reset all interface configuration.
+	(rip_clean_network): Clean rip_enable_network.
+
+	* ripd.h (struct rip_interface): Add key_chain member.
+
+	* ripd.c: Include md5-gnu.h.
+
+2000-07-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.h (RIP_NO_AUTH): Change RIP_NO_AUTH value from 1 to 0.
+
+	* ripd.c (rip_authentication): Use RIP_AUTH_SIMPLE_PASSWORD
+	instead of raw value 2.
+	(rip_write_rte): Likewise.
+	(rip_write_rte): Check ri->auth_type instead of ri->auth_str.
+
+2000-07-30  David Lipovkov <davidl@nbase.co.il>
+
+	* rip_interface.c (rip_if_down): Do not delete ZEBRA_ROUTE_KERNEL
+	route.
+
+2000-07-27  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_update_process): Add "passive-interface" command.
+
+	* ripd.h (struct rip_interface): Add passive member to struct
+	rip_interface.
+
+2000-07-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_interface.c (rip_if_init): Multiple RIP routes for one
+	prefix change.  The codes are enclosed by #ifdef NEW_RIP_TABLE.
+
+2000-07-24  Akihiro Mizutani <mizutani@dml.com>
+
+	* rip_interface.c (rip_if_init): Use install_default() for
+	INTERFACE_NODE.
+
+2000-07-24  Kunihiro Ishiguro <kunihiro@zebra.org>
+
+	* ripd.c: First update timer will be invoked in two seconds.
+
+2000-07-09  Jochen Friedrich <jochen@scram.de>
+
+	* rip_snmp.c: Local function definitions to static.  Add INTEGER
+	ASN_INTEGER and TIMETICKS ASN_TIMETICKS definition.
+	(rip2PeerLookup): Peer with domain lookup implemented.
+	(rip2PeerTable): Temporary disable RIP2PEERLASTUPDATE value
+	support due to unknown SNMP agent startup time.
+
+2000-07-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.h: Sweep obsolete definitions.
+
+	* rip_interface.c (rip_split_horizon): Add "ip split-horizon"
+	command.
+
+	* ripd.c (rip_output_process): Remove split_horizon argument.
+	(rip_update_process): Likewise.
+
+	* ripd.h (struct rip_interface): Add split_horizon flag to struct
+	rip_interface.
+
+2000-07-04  Akihiro Mizutani <mizutani@dml.com>
+
+	* ripd.c (rip_version): Change VERSION to <1-2>.
+	Add "no version" command.
+
+2000-07-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_zebra.c (rip_redistribute_type_metric): "redistribute TYPE
+	metric <0-16>" command is added.
+
+	* rip_routemap.c (route_set_metric): Set metric_set when metric is
+	modified.
+
+	* ripd.h (struct rip_info): To check route-map set metric or not,
+	new member metric_set is added to struct rip_info.
+
+	* ripd.c (rip_route_process): Move metric handling code from
+	rip_response_process() to rip_route_process().
+	(rip_output_process): Set output offset-list metric.
+
+2000-07-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_offset.c (rip_offset_list): New file for offset-list.
+
+2000-07-02  Akihiro Mizutani <mizutani@dml.com>
+
+	* ripd.h (struct rip ): Add default_metric.
+
+	* ripd.c (rip_default_metric): "default-metric <1-16>" command is
+	added.
+	(config_write_rip): Change configuration order.
+	
+	* rip_zebra.c: Fix help strings.
+
+2000-07-02  David Lipovkov <davidl@nbase.co.il>
+
+	* rip_interface.c (rip_if_init): Add IF_DELETE_HOOK.
+
+2000-07-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_output_process): If specified route-map does not
+	exist, it treated as deny all.
+
+2000-06-30  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_routemap.c (rip_route_map_init): Call rip_route_map_update
+	when route-map is deleted.
+
+2000-06-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_routemap.c (set_metric): For consistency with bgpd's set
+	metric, value range is set to <0-4294967295>.
+	
+2000-06-28  David Lipovkov <davidl@nbase.co.il>
+
+	* rip_routemap.c (rip_route_map_update): Add check for rip is
+	enabled or not for avoid core dump.
+
+	* rip_debug.c (debug_rip_packet_direct): Fix bug of setting
+	rip_debug_packet flag.
+
+2000-06-13  David Lipovkov <davidl@nbase.co.il>
+
+	* rip_interface.c (rip_interface_delete): All work is done in
+	rip_if_down().
+
+2000-06-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_redistribute_delete): Fix bug of missing
+	route_unlock_node() when redistribute route is not found.
+
+2000-06-05  Akihirof Mizutani <mizutani@dml.com>
+
+	* rip_debug.c (rip_debug_init): Disable show debugging in
+	VIEW_NODE like other protocol daemon.
+
+	* rip_routemap.c: Change command argument to more comprehensive.
+
+	METRIC       -> <0-16>
+	IFNAME       -> WORD
+	IP_ADDR      -> A.B.C.D
+	ACCSESS_LIST -> WORD
+
+2000-06-05  David Lipovkov <davidl@nbase.co.il>
+
+	* rip_interface.c (rip_interface_delete): Delete all routes
+	include static and kernel through the interface , because even if
+	the interface is added again there is no guarantee that it will
+	get the same ifindex as before.
+
+2000-05-31  Akihirof Mizutani <mizutani@dml.com>
+
+	* rip_debug.c: Fix rip debug help string.
+
+2000-04-27  Mirko Karanovic <mkaranov@torsel.alcatel.com>
+
+	* rip_interface.c (rip_interface_down): Remove interface from
+	multicast group when interface goes down.
+
+2000-04-03  David Lipovkov <davidl@nbase.co.il>
+
+	* rip_interface.c (rip_interface_down): Implemented rip functions
+	for interface up/down events: rip_interface_up() and
+	rip_interface_down()
+
+2000-03-16  David Lipovkov <davidl@nbase.co.il>
+
+	* rip_zebra.c (rip_zclient_init): Added rip functions for
+	interface up/down events.
+
+2000-02-15  Hidetoshi Shimokawa <simokawa@sat.t.u-tokyo.ac.jp>
+
+	* ripd.c (rip_write_rte): "set metic" in route-map has no effect
+	for RIPv1 in ripd.  It worked fine for RIPv2.
+
+2000-01-17  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (show_ip_protocols_rip): Fix bug of "show ip protocls"
+	mis-display RIP version.
+
+	* ripd.h (struct rip_peer): Add timeout thread to rip_peer
+	structure.
+
+2000-01-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_peer.c: Add new file for supporting RIP peer.
+
+1999-12-26  David Lipovkov <davidl@nbase.co.il>
+
+	* ripd.c (rip_authentication): RIP authantication string is 16
+	bytes long.
+
+1999-12-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_read): Add check for minimum packet length.
+	Authentication check is moved from rip_process_response() to
+	rip_read().  Patch from David Lipovkov <davidl@nbase.co.il> is
+	applied then add rte number check by Kunihiro Ishiguro
+	<kunihiro@zebra.org>.
+
+1999-12-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_response_process): In case of packet is RIPv2 and
+	network is non zero and netmask is zero, apply netmask rule as
+	same as RIPv1.
+
+1999-11-06  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_timers): Fix bug of timers basic argument format.
+
+1999-11-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_snmp.c (rip2IfConfAddress): Forgot to include
+	RIP2IFCONFDOMAIN.
+
+1999-10-28  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.h (struct rip_peer): New structure added.
+
+1999-10-26  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_zebra.c (rip_zebra_ipv4_add): Increment
+	rip_global_route_changes when route change occur.
+	(rip_zebra_ipv4_delete): Likewise.
+
+	* ripd.c (rip_request_process): Increment rip_global_queries when
+	reply to the query is sent.
+
+1999-10-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_debug.c (rip_debug_reset): Reset function added.
+
+	* ripd.c (rip_update_process): Logging bug is fixed. 
+
+1999-10-10  Marc Boucher <marc@mbsi.ca>
+
+	* ripd.c (config_write_rip): Add config_write_distribute() call.
+
+1999-09-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_distribute_update): Fix bug of access-list
+	prefix-list updates.
+
+1999-09-10  VOP <vop@unity.net>
+
+	* rip_zebra.c: Add redistribute route-map feature.
+
+1999-09-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_response_process): Add check for given prefix is
+	given mask applied one.
+
+1999-09-03  VOP <vop@unity.net>
+
+	* rip_interface.c (rip_interface_multicast_set): Bug fix about
+	setting multicast interface.
+
+1999-09-02  VOP <vop@unity.net>
+
+	* rip_routemap.c: New file added.
+
+1999-09-02  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (show_ip_protocols_rip): Show next update time.
+	(show_ip_protocols_rip): Show redistribute information.
+
+1999-08-25  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* RIPv2-MIB.txt: New file added.
+
+	* rip_snmp.c: New file added.
+
+1999-08-24  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_interface.c (ip_rip_authentication_string): RIPv2
+	authentication command is added.
+
+1999-08-23  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_interface.c (rip_interface_multicast_set): Process of
+	setting IP_MULTICAST_IF on specific interface.
+
+	* ripd.c (rip_read): Add packet size check.
+
+1999-08-16  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_request_process): Fill in RIP_METRIC_INFINITY with
+	network byte order using htonl ().
+	(rip_response_process): Pass host byte order address to IN_CLASSC
+	and IN_CLASSB macro.
+
+1999-08-08  davidm@nbase.co.il (David Mozes)
+
+	* rip_zebra.c (rip_zebra_read_ipv4): Fix split horizon problem.
+
+1999-07-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_timer_set): Function added.
+
+1999-07-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_debug.c: New file added.
+	rip_debug.h: New file added.
+
+1999-07-01  Rick Payne <rickp@rossfell.co.uk>
+
+	* rip_zebra.c (zebra_init): Install standard commands to
+	ZEBRA_NODE.
+
+1999-06-01  David Luyer <luyer@ucs.uwa.edu.au>
+
+	* ripd.c (rip_process_route): Add support for RIP version 1.
+
+1999-05-29  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_zebra.c: Change to use lib/zclient.[ch].
+
+1999-05-20  Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+	* ripd.c (rip_add_route): Change the existance route's metric check
+          to the condition specified by RFC2453. 
+	
+1999-05-17  Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+	* ripd.c (rip_process_route): Add the if metric to the route metric.
+
+	* ripd.c (rip_add_route): Deleted add if metric to the route.
+
+1999-05-16  Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+	* rip_interface.c (if_valid_neighbor): New function.
+
+	* ripd.c (rip_process_route): Added check whether the datagram
+	is from a valid neighbor.
+	
+1999-05-15  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_process_route): Set interface pointer to rinfo.
+
+1999-05-15  Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+	* ripd.c (rip_check_address): Unicast and not net 0 or 127 check
+	added.
+
+1999-05-14  Stephen R. van den Berg <srb@cuci.nl>
+
+	* rip_main.c (signal_init): SIGTERM call sigint.
+	(sigint): Loggging more better message.
+
+1999-05-10  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_add_route): Fix previous route_unlock_node() chenge.
+
+	* rip_main.c (main): Change default zlog output to ZLOG_STDOUT for
+	debugging.
+
+1999-05-09  Patrick Koppen <koppen@rhrk.uni-kl.de>
+
+	* rip_interface.c (rip_request): Fix old semantics for fetching
+	connected address.
+
+	* ripd.c (rip_add_route): Update timer when the route is updated.
+
+1999-05-09  Carlos Alberto Barcenilla <barce@frlp.utn.edu.ar>
+
+	* rip_zebra.c (struct zebra): Add ridist_static, ridist_connect,
+	redist_rip, redist_ripng.  
+
+	* rip_zebra.c (zebra_create): Updated for current zebra method.
+
+	* ripd.c (rip_add_route): Add missing route_unlock_node().
+
+1999-05-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_add_route): Add metric check.  Reported by Carlos
+	Alberto Barcenilla <barce@frlp.utn.edu.ar>.
+
+1999-02-18  Peter Galbavy  <Peter.Galbavy@knowledge.com>
+
+	* syslog support added
+
+1998-12-13  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_announce_func): Apply new lib functions.
+
+1998-12-09  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (config_write_rip): Delete vector v argument.
+	* rip_zebra.c (config_write_zebra): Likewise.
+	* rip_interface.c (interface_config_write): Likewise.
+
+1998-09-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_announce.c (rip_rib_close): When ripd terminates delete all
+	added route.
+
+1998-09-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_interface.c: return read packet size.
+
+1998-05-18  Yamshita TAKAO  <jargon@lares.dti.ne.jp>
+
+	* ripd.h: Modify for compile on Solaris.
+
+1998-05-07  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c: DEFUN function return CMD_SUCCESS.
+		  change xmalloc to XMALLOC macro.
+	
+1998-05-03  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_main.c: change CONFDIR to SYSCONFDIR.
+
+1998-05-01  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* .cvsignore: added.
+
+1998-02-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_interface.c (config_write_interface): correct ADVERTISE spell.
+
+	* rip_main.c (main): add usage() and make cleanup.
+
+1998-01-05  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* ripd.c (rip_version): add rip version command.
+
+1998-01-04  Kunihiro Ishiguro  <kunihiro@zebra.org>
+
+	* rip_interface.c (zebra_get_interface): added to get
+	interface's information.
+
+	* ChangeLog: create.
diff --git a/ripd/Makefile.am b/ripd/Makefile.am
new file mode 100644
index 0000000..fd25485
--- /dev/null
+++ b/ripd/Makefile.am
@@ -0,0 +1,37 @@
+## Process this file with automake to produce Makefile.in.
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+INSTALL_SDATA=@INSTALL@ -m 600
+
+noinst_LIBRARIES = librip.a
+sbin_PROGRAMS = ripd
+
+librip_a_SOURCES = \
+	ripd.c rip_zebra.c rip_interface.c rip_debug.c rip_snmp.c \
+	rip_routemap.c rip_peer.c rip_offset.c
+
+noinst_HEADERS = \
+	ripd.h rip_debug.h
+
+ripd_SOURCES = \
+	rip_main.c $(librip_a_SOURCES)
+
+ripd_LDADD = ../lib/libzebra.a
+
+sysconf_DATA = ripd.conf.sample
+
+EXTRA_DIST = $(sysconf_DATA) RIPv2-MIB.txt
+
+install-sysconfDATA: $(sysconf_DATA)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+	@list='$(sysconf_DATA)'; for p in $$list; do \
+	  if test -f $(srcdir)/$$p; then \
+	    echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+	    $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+	  else if test -f $$p; then \
+	    echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+	    $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+	  fi; fi; \
+	done
diff --git a/ripd/Makefile.in b/ripd/Makefile.in
new file mode 100644
index 0000000..fa355ef
--- /dev/null
+++ b/ripd/Makefile.in
@@ -0,0 +1,489 @@
+# Makefile.in generated by automake 1.7 from Makefile.am.
+# @configure_input@
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_triplet = @host@
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BGPD = @BGPD@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURSES = @CURSES@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+IF_METHOD = @IF_METHOD@
+IF_PROC = @IF_PROC@
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPFORWARD = @IPFORWARD@
+KERNEL_METHOD = @KERNEL_METHOD@
+LDFLAGS = @LDFLAGS@
+LIBPAM = @LIBPAM@
+LIBS = @LIBS@
+LIB_IPV6 = @LIB_IPV6@
+LIB_REGEX = @LIB_REGEX@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MULTIPATH_NUM = @MULTIPATH_NUM@
+OBJEXT = @OBJEXT@
+OSPF6D = @OSPF6D@
+OSPFD = @OSPFD@
+OTHER_METHOD = @OTHER_METHOD@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RIPD = @RIPD@
+RIPNGD = @RIPNGD@
+RTREAD_METHOD = @RTREAD_METHOD@
+RT_METHOD = @RT_METHOD@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VTYSH = @VTYSH@
+ZEBRA = @ZEBRA@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__quote = @am__quote@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+INSTALL_SDATA = @INSTALL@ -m 600
+
+noinst_LIBRARIES = librip.a
+sbin_PROGRAMS = ripd
+
+librip_a_SOURCES = \
+	ripd.c rip_zebra.c rip_interface.c rip_debug.c rip_snmp.c \
+	rip_routemap.c rip_peer.c rip_offset.c
+
+
+noinst_HEADERS = \
+	ripd.h rip_debug.h
+
+
+ripd_SOURCES = \
+	rip_main.c $(librip_a_SOURCES)
+
+
+ripd_LDADD = ../lib/libzebra.a
+
+sysconf_DATA = ripd.conf.sample
+
+EXTRA_DIST = $(sysconf_DATA) RIPv2-MIB.txt
+subdir = ripd
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+
+librip_a_AR = $(AR) cru
+librip_a_LIBADD =
+am_librip_a_OBJECTS = ripd.$(OBJEXT) rip_zebra.$(OBJEXT) \
+	rip_interface.$(OBJEXT) rip_debug.$(OBJEXT) rip_snmp.$(OBJEXT) \
+	rip_routemap.$(OBJEXT) rip_peer.$(OBJEXT) rip_offset.$(OBJEXT)
+librip_a_OBJECTS = $(am_librip_a_OBJECTS)
+sbin_PROGRAMS = ripd$(EXEEXT)
+PROGRAMS = $(sbin_PROGRAMS)
+
+am__objects_1 = ripd.$(OBJEXT) rip_zebra.$(OBJEXT) \
+	rip_interface.$(OBJEXT) rip_debug.$(OBJEXT) rip_snmp.$(OBJEXT) \
+	rip_routemap.$(OBJEXT) rip_peer.$(OBJEXT) rip_offset.$(OBJEXT)
+am_ripd_OBJECTS = rip_main.$(OBJEXT) $(am__objects_1)
+ripd_OBJECTS = $(am_ripd_OBJECTS)
+ripd_DEPENDENCIES = ../lib/libzebra.a
+ripd_LDFLAGS =
+
+DEFAULT_INCLUDES =  -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/rip_debug.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/rip_interface.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/rip_main.Po ./$(DEPDIR)/rip_offset.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/rip_peer.Po ./$(DEPDIR)/rip_routemap.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/rip_snmp.Po ./$(DEPDIR)/rip_zebra.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/ripd.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 = $(librip_a_SOURCES) $(ripd_SOURCES)
+DATA = $(sysconf_DATA)
+
+HEADERS = $(noinst_HEADERS)
+
+DIST_COMMON = $(noinst_HEADERS) ChangeLog Makefile.am Makefile.in
+SOURCES = $(librip_a_SOURCES) $(ripd_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  ripd/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)
+librip.a: $(librip_a_OBJECTS) $(librip_a_DEPENDENCIES) 
+	-rm -f librip.a
+	$(librip_a_AR) librip.a $(librip_a_OBJECTS) $(librip_a_LIBADD)
+	$(RANLIB) librip.a
+sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(sbindir)
+	@list='$(sbin_PROGRAMS)'; for p in $$list; do \
+	  p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  if test -f $$p \
+	  ; then \
+	    f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+	   echo " $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f"; \
+	   $(INSTALL_PROGRAM_ENV) $(sbinPROGRAMS_INSTALL) $$p $(DESTDIR)$(sbindir)/$$f || exit 1; \
+	  else :; fi; \
+	done
+
+uninstall-sbinPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(sbin_PROGRAMS)'; for p in $$list; do \
+	  f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+	  echo " rm -f $(DESTDIR)$(sbindir)/$$f"; \
+	  rm -f $(DESTDIR)$(sbindir)/$$f; \
+	done
+
+clean-sbinPROGRAMS:
+	-test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
+ripd$(EXEEXT): $(ripd_OBJECTS) $(ripd_DEPENDENCIES) 
+	@rm -f ripd$(EXEEXT)
+	$(LINK) $(ripd_LDFLAGS) $(ripd_OBJECTS) $(ripd_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_debug.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_interface.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_offset.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_peer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_routemap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_snmp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_zebra.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripd.Po@am__quote@
+
+distclean-depend:
+	-rm -rf ./$(DEPDIR)
+
+.c.o:
+@am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@	  -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \
+@am__fastdepCC_TRUE@	then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@	else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@	fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
+
+.c.obj:
+@am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@	  -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`; \
+@am__fastdepCC_TRUE@	then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@	else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@	fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'`
+uninstall-info-am:
+sysconfDATA_INSTALL = $(INSTALL_DATA)
+
+uninstall-sysconfDATA:
+	@$(NORMAL_UNINSTALL)
+	@list='$(sysconf_DATA)'; for p in $$list; do \
+	  f="`echo $$p | sed -e 's|^.*/||'`"; \
+	  echo " rm -f $(DESTDIR)$(sysconfdir)/$$f"; \
+	  rm -f $(DESTDIR)$(sysconfdir)/$$f; \
+	done
+
+ETAGS = etags
+ETAGSFLAGS =
+
+CTAGS = ctags
+CTAGSFLAGS =
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$tags$$unique" \
+	  || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	     $$tags $$unique
+
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkinstalldirs) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS)
+
+installdirs:
+	$(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(sysconfdir)
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-noinstLIBRARIES clean-sbinPROGRAMS \
+	mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+	distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-sbinPROGRAMS install-sysconfDATA
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS \
+	uninstall-sysconfDATA
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+	clean-noinstLIBRARIES clean-sbinPROGRAMS ctags distclean \
+	distclean-compile distclean-depend distclean-generic \
+	distclean-tags distdir dvi dvi-am info info-am install \
+	install-am install-data install-data-am install-exec \
+	install-exec-am install-info install-info-am install-man \
+	install-sbinPROGRAMS install-strip install-sysconfDATA \
+	installcheck installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
+	uninstall-am uninstall-info-am uninstall-sbinPROGRAMS \
+	uninstall-sysconfDATA
+
+
+install-sysconfDATA: $(sysconf_DATA)
+	@$(NORMAL_INSTALL)
+	$(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+	@list='$(sysconf_DATA)'; for p in $$list; do \
+	  if test -f $(srcdir)/$$p; then \
+	    echo " $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \
+	    $(INSTALL_SDATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \
+	  else if test -f $$p; then \
+	    echo " $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \
+	    $(INSTALL_SDATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \
+	  fi; fi; \
+	done
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/ripd/RIPv2-MIB.txt b/ripd/RIPv2-MIB.txt
new file mode 100644
index 0000000..6c92fb5
--- /dev/null
+++ b/ripd/RIPv2-MIB.txt
@@ -0,0 +1,530 @@
+   RIPv2-MIB DEFINITIONS ::= BEGIN
+
+   IMPORTS
+       MODULE-IDENTITY, OBJECT-TYPE, Counter32,
+       TimeTicks, IpAddress                     FROM SNMPv2-SMI
+       TEXTUAL-CONVENTION, RowStatus            FROM SNMPv2-TC
+       MODULE-COMPLIANCE, OBJECT-GROUP          FROM SNMPv2-CONF
+       mib-2                                    FROM RFC1213-MIB;
+
+   --  This MIB module uses the extended OBJECT-TYPE macro as
+   --  defined in [9].
+
+   rip2  MODULE-IDENTITY
+           LAST-UPDATED "9407272253Z"      -- Wed Jul 27 22:53:04 PDT 1994
+           ORGANIZATION "IETF RIP-II Working Group"
+           CONTACT-INFO
+          "       Fred Baker
+          Postal: Cisco Systems
+                  519 Lado Drive
+                  Santa Barbara, California 93111
+          Tel:    +1 805 681 0115
+          E-Mail: fbaker@cisco.com
+
+          Postal: Gary Malkin
+                  Xylogics, Inc.
+                  53 Third Avenue
+                  Burlington, MA  01803
+
+          Phone:  (617) 272-8140
+          EMail:  gmalkin@Xylogics.COM"
+      DESCRIPTION
+         "The MIB module to describe the RIP2 Version 2 Protocol"
+     ::= { mib-2 23 }
+
+ --  RIP-2 Management Information Base
+
+ -- the RouteTag type represents the contents of the
+ -- Route Domain field in the packet header or route entry.
+ -- The use of the Route Domain is deprecated.
+
+ RouteTag ::= TEXTUAL-CONVENTION
+     STATUS      current
+     DESCRIPTION
+        "the RouteTag type represents the contents of the Route Domain
+        field in the packet header or route entry"
+    SYNTAX      OCTET STRING (SIZE (2))
+
+--4.1 Global Counters
+
+--      The RIP-2 Globals Group.
+--      Implementation of this group is mandatory for systems
+--      which implement RIP-2.
+
+-- These counters are intended to facilitate debugging quickly
+-- changing routes or failing neighbors
+
+rip2Globals OBJECT IDENTIFIER ::= { rip2 1 }
+
+    rip2GlobalRouteChanges OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of route changes made to the IP Route
+           Database by RIP.  This does not include the refresh
+           of a route's age."
+       ::= { rip2Globals 1 }
+
+    rip2GlobalQueries OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of responses sent to RIP queries
+           from other systems."
+       ::= { rip2Globals 2 }
+
+--4.2 RIP Interface Tables
+
+--  RIP Interfaces Groups
+--  Implementation of these Groups is mandatory for systems
+--  which implement RIP-2.
+
+-- The RIP Interface Status Table.
+
+    rip2IfStatTable OBJECT-TYPE
+        SYNTAX   SEQUENCE OF Rip2IfStatEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "A list of subnets which require separate
+           status monitoring in RIP."
+       ::= { rip2 2 }
+
+   rip2IfStatEntry OBJECT-TYPE
+       SYNTAX   Rip2IfStatEntry
+       MAX-ACCESS   not-accessible
+       STATUS   current
+       DESCRIPTION
+          "A Single Routing Domain in a single Subnet."
+      INDEX { rip2IfStatAddress }
+      ::= { rip2IfStatTable 1 }
+
+    Rip2IfStatEntry ::=
+        SEQUENCE {
+            rip2IfStatAddress
+                IpAddress,
+            rip2IfStatRcvBadPackets
+                Counter32,
+            rip2IfStatRcvBadRoutes
+                Counter32,
+            rip2IfStatSentUpdates
+                Counter32,
+            rip2IfStatStatus
+                RowStatus
+    }
+
+    rip2IfStatAddress OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The IP Address of this system on the indicated
+           subnet. For unnumbered interfaces, the value 0.0.0.N,
+           where the least significant 24 bits (N) is the ifIndex
+           for the IP Interface in network byte order."
+       ::= { rip2IfStatEntry 1 }
+
+    rip2IfStatRcvBadPackets OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of RIP response packets received by
+           the RIP process which were subsequently discarded
+           for any reason (e.g. a version 0 packet, or an
+           unknown command type)."
+       ::= { rip2IfStatEntry 2 }
+
+    rip2IfStatRcvBadRoutes OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of routes, in valid RIP packets,
+           which were ignored for any reason (e.g. unknown
+           address family, or invalid metric)."
+       ::= { rip2IfStatEntry 3 }
+
+    rip2IfStatSentUpdates OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of triggered RIP updates actually
+           sent on this interface.  This explicitly does
+           NOT include full updates sent containing new
+           information."
+       ::= { rip2IfStatEntry 4 }
+
+    rip2IfStatStatus OBJECT-TYPE
+        SYNTAX   RowStatus
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "Writing invalid has the effect of deleting
+           this interface."
+       ::= { rip2IfStatEntry 5 }
+
+-- The RIP Interface Configuration Table.
+
+    rip2IfConfTable OBJECT-TYPE
+        SYNTAX   SEQUENCE OF Rip2IfConfEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "A list of subnets which require separate
+           configuration in RIP."
+       ::= { rip2 3 }
+
+   rip2IfConfEntry OBJECT-TYPE
+       SYNTAX   Rip2IfConfEntry
+       MAX-ACCESS   not-accessible
+       STATUS   current
+       DESCRIPTION
+          "A Single Routing Domain in a single Subnet."
+      INDEX { rip2IfConfAddress }
+      ::= { rip2IfConfTable 1 }
+
+    Rip2IfConfEntry ::=
+        SEQUENCE {
+            rip2IfConfAddress
+                IpAddress,
+            rip2IfConfDomain
+                RouteTag,
+            rip2IfConfAuthType
+                INTEGER,
+            rip2IfConfAuthKey
+                OCTET STRING (SIZE(0..16)),
+            rip2IfConfSend
+                INTEGER,
+            rip2IfConfReceive
+                INTEGER,
+            rip2IfConfDefaultMetric
+                INTEGER,
+            rip2IfConfStatus
+                RowStatus,
+            rip2IfConfSrcAddress
+                IpAddress
+    }
+
+    rip2IfConfAddress OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The IP Address of this system on the indicated
+           subnet.  For unnumbered interfaces, the value 0.0.0.N,
+           where the least significant 24 bits (N) is the ifIndex
+           for the IP Interface in network byte order."
+       ::= { rip2IfConfEntry 1 }
+
+    rip2IfConfDomain OBJECT-TYPE
+        SYNTAX   RouteTag
+        MAX-ACCESS   read-create
+        STATUS   obsolete
+        DESCRIPTION
+           "Value inserted into the Routing Domain field
+           of all RIP packets sent on this interface."
+       DEFVAL { '0000'h }
+       ::= { rip2IfConfEntry 2 }
+
+    rip2IfConfAuthType OBJECT-TYPE
+        SYNTAX   INTEGER {
+                    noAuthentication (1),
+                    simplePassword (2),
+                    md5 (3)
+                 }
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The type of Authentication used on this
+           interface."
+       DEFVAL { noAuthentication }
+       ::= { rip2IfConfEntry 3 }
+
+    rip2IfConfAuthKey OBJECT-TYPE
+        SYNTAX   OCTET STRING (SIZE(0..16))
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The value to be used as the Authentication Key
+           whenever the corresponding instance of
+           rip2IfConfAuthType has a value other than
+           noAuthentication.  A modification of the corresponding
+           instance of rip2IfConfAuthType does not modify
+           the rip2IfConfAuthKey value.  If a string shorter
+           than 16 octets is supplied, it will be left-
+           justified and padded to 16 octets, on the right,
+           with nulls (0x00).
+
+           Reading this object always results in an  OCTET
+           STRING of length zero; authentication may not
+           be bypassed by reading the MIB object."
+       DEFVAL { ''h }
+       ::= { rip2IfConfEntry 4 }
+
+    rip2IfConfSend OBJECT-TYPE
+        SYNTAX   INTEGER {
+                    doNotSend (1),
+                    ripVersion1 (2),
+                    rip1Compatible (3),
+                    ripVersion2 (4),
+                    ripV1Demand (5),
+                    ripV2Demand (6)
+                 }
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "What the router sends on this interface.
+           ripVersion1 implies sending RIP updates compliant
+           with  RFC  1058.   rip1Compatible implies
+           broadcasting RIP-2 updates using RFC 1058 route
+           subsumption rules.  ripVersion2 implies
+           multicasting RIP-2 updates.  ripV1Demand indicates
+           the use of Demand RIP on a WAN interface under RIP
+           Version 1 rules.  ripV2Demand indicates the use of
+           Demand RIP on a WAN interface under Version 2 rules."
+       DEFVAL { rip1Compatible }
+       ::= { rip2IfConfEntry 5 }
+
+    rip2IfConfReceive OBJECT-TYPE
+        SYNTAX   INTEGER {
+                    rip1 (1),
+                    rip2 (2),
+                    rip1OrRip2 (3),
+                    doNotRecieve (4)
+                 }
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "This indicates which version of RIP updates
+           are to be accepted.  Note that rip2 and
+           rip1OrRip2 implies reception of multicast
+           packets."
+       DEFVAL { rip1OrRip2 }
+       ::= { rip2IfConfEntry 6 }
+
+    rip2IfConfDefaultMetric OBJECT-TYPE
+        SYNTAX   INTEGER ( 0..15 )
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "This variable indicates the metric that is to
+           be used for the default route entry in RIP updates
+           originated on this interface.  A value of zero
+           indicates that no default route should be
+           originated; in this case, a default route via
+           another router may be propagated."
+       ::= { rip2IfConfEntry 7 }
+
+    rip2IfConfStatus OBJECT-TYPE
+        SYNTAX   RowStatus
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "Writing invalid has  the  effect  of  deleting
+           this interface."
+       ::= { rip2IfConfEntry 8 }
+
+    rip2IfConfSrcAddress OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-create
+        STATUS   current
+        DESCRIPTION
+           "The IP Address this system will use as a source
+            address on this interface.  If it is a numbered
+            interface, this MUST be the same value as
+            rip2IfConfAddress.  On unnumbered interfaces,
+            it must be the value of rip2IfConfAddress for
+            some interface on the system."
+       ::= { rip2IfConfEntry 9 }
+
+--4.3 Peer Table
+
+--  Peer Table
+
+--      The RIP Peer Group
+--      Implementation of this Group is Optional
+
+--      This group provides information about active peer
+--      relationships intended to assist in debugging.  An
+--      active peer is a router from which a valid RIP
+--      updated has been heard in the last 180 seconds.
+
+    rip2PeerTable OBJECT-TYPE
+        SYNTAX   SEQUENCE OF Rip2PeerEntry
+        MAX-ACCESS   not-accessible
+        STATUS   current
+        DESCRIPTION
+           "A list of RIP Peers."
+       ::= { rip2 4 }
+
+   rip2PeerEntry OBJECT-TYPE
+       SYNTAX   Rip2PeerEntry
+       MAX-ACCESS   not-accessible
+       STATUS   current
+       DESCRIPTION
+          "Information regarding a single routing peer."
+      INDEX { rip2PeerAddress, rip2PeerDomain }
+      ::= { rip2PeerTable 1 }
+
+    Rip2PeerEntry ::=
+        SEQUENCE {
+            rip2PeerAddress
+                IpAddress,
+            rip2PeerDomain
+                RouteTag,
+            rip2PeerLastUpdate
+                TimeTicks,
+            rip2PeerVersion
+                INTEGER,
+            rip2PeerRcvBadPackets
+                Counter32,
+            rip2PeerRcvBadRoutes
+                Counter32
+            }
+
+    rip2PeerAddress OBJECT-TYPE
+        SYNTAX   IpAddress
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The IP Address that the peer is using as its source
+            address.  Note that on an unnumbered link, this may
+            not be a member of any subnet on the system."
+       ::= { rip2PeerEntry 1 }
+
+    rip2PeerDomain OBJECT-TYPE
+        SYNTAX   RouteTag
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The value in the Routing Domain field  in  RIP
+           packets received from the peer.  As domain suuport
+           is deprecated, this must be zero."
+       ::= { rip2PeerEntry 2 }
+
+    rip2PeerLastUpdate OBJECT-TYPE
+        SYNTAX   TimeTicks
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The value of sysUpTime when the most recent
+           RIP update was received from this system."
+       ::= { rip2PeerEntry 3 }
+
+    rip2PeerVersion OBJECT-TYPE
+        SYNTAX   INTEGER ( 0..255 )
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The RIP version number in the header of the
+           last RIP packet received."
+       ::= { rip2PeerEntry 4 }
+
+    rip2PeerRcvBadPackets OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of RIP response packets from this
+           peer discarded as invalid."
+       ::= { rip2PeerEntry 5 }
+
+
+    rip2PeerRcvBadRoutes OBJECT-TYPE
+        SYNTAX   Counter32
+        MAX-ACCESS   read-only
+        STATUS   current
+        DESCRIPTION
+           "The number of routes from this peer that were
+           ignored because the entry format was invalid."
+       ::= { rip2PeerEntry 6 }
+
+-- conformance information
+
+rip2Conformance OBJECT IDENTIFIER ::= { rip2 5 }
+
+rip2Groups      OBJECT IDENTIFIER ::= { rip2Conformance 1 }
+rip2Compliances OBJECT IDENTIFIER ::= { rip2Conformance 2 }
+
+-- compliance statements
+rip2Compliance MODULE-COMPLIANCE
+    STATUS  current
+    DESCRIPTION
+       "The compliance statement "
+    MODULE  -- this module
+    MANDATORY-GROUPS {
+                 rip2GlobalGroup,
+                 rip2IfStatGroup,
+                 rip2IfConfGroup,
+                 rip2PeerGroup
+        }
+    GROUP       rip2GlobalGroup
+    DESCRIPTION
+       "This group defines global controls for RIP-II systems."
+    GROUP       rip2IfStatGroup
+    DESCRIPTION
+       "This group defines interface statistics for RIP-II systems."
+    GROUP       rip2IfConfGroup
+    DESCRIPTION
+       "This group defines interface configuration for RIP-II systems."
+    GROUP       rip2PeerGroup
+    DESCRIPTION
+       "This group defines peer information for RIP-II systems."
+    ::= { rip2Compliances 1 }
+
+-- units of conformance
+
+rip2GlobalGroup    OBJECT-GROUP
+    OBJECTS {
+                rip2GlobalRouteChanges,
+                rip2GlobalQueries
+    }
+    STATUS  current
+    DESCRIPTION
+       "This group defines global controls for RIP-II systems."
+    ::= { rip2Groups 1 }
+rip2IfStatGroup    OBJECT-GROUP
+    OBJECTS {
+            rip2IfStatAddress,
+            rip2IfStatRcvBadPackets,
+            rip2IfStatRcvBadRoutes,
+            rip2IfStatSentUpdates,
+            rip2IfStatStatus
+    }
+    STATUS  current
+    DESCRIPTION
+       "This group defines interface statistics for RIP-II systems."
+    ::= { rip2Groups 2 }
+rip2IfConfGroup    OBJECT-GROUP
+    OBJECTS {
+            rip2IfConfAddress,
+            rip2IfConfAuthType,
+            rip2IfConfAuthKey,
+            rip2IfConfSend,
+            rip2IfConfReceive,
+            rip2IfConfDefaultMetric,
+            rip2IfConfStatus,
+            rip2IfConfSrcAddress
+    }
+    STATUS  current
+    DESCRIPTION
+       "This group defines interface configuration for RIP-II systems."
+    ::= { rip2Groups 3 }
+rip2PeerGroup    OBJECT-GROUP
+    OBJECTS {
+            rip2PeerAddress,
+            rip2PeerDomain,
+            rip2PeerLastUpdate,
+            rip2PeerVersion,
+            rip2PeerRcvBadPackets,
+            rip2PeerRcvBadRoutes
+    }
+    STATUS  current
+    DESCRIPTION
+       "This group defines peer information for RIP-II systems."
+    ::= { rip2Groups 4 }
+END
diff --git a/ripd/rip_debug.c b/ripd/rip_debug.c
new file mode 100644
index 0000000..4f09200
--- /dev/null
+++ b/ripd/rip_debug.c
@@ -0,0 +1,290 @@
+/* RIP debug routines
+ * 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>
+#include "command.h"
+#include "ripd/rip_debug.h"
+
+/* For debug statement. */
+unsigned long rip_debug_event = 0;
+unsigned long rip_debug_packet = 0;
+unsigned long rip_debug_zebra = 0;
+
+DEFUN (show_debugging_rip,
+       show_debugging_rip_cmd,
+       "show debugging rip",
+       SHOW_STR
+       DEBUG_STR
+       RIP_STR)
+{
+  vty_out (vty, "Zebra debugging status:%s", VTY_NEWLINE);
+
+  if (IS_RIP_DEBUG_EVENT)
+    vty_out (vty, "  RIP event debugging is on%s", VTY_NEWLINE);
+
+  if (IS_RIP_DEBUG_PACKET)
+    {
+      if (IS_RIP_DEBUG_SEND && IS_RIP_DEBUG_RECV)
+	{
+	  vty_out (vty, "  RIP packet%s debugging is on%s",
+		   IS_RIP_DEBUG_DETAIL ? " detail" : "",
+		   VTY_NEWLINE);
+	}
+      else
+	{
+	  if (IS_RIP_DEBUG_SEND)
+	    vty_out (vty, "  RIP packet send%s debugging is on%s",
+		     IS_RIP_DEBUG_DETAIL ? " detail" : "",
+		     VTY_NEWLINE);
+	  else
+	    vty_out (vty, "  RIP packet receive%s debugging is on%s",
+		     IS_RIP_DEBUG_DETAIL ? " detail" : "",
+		     VTY_NEWLINE);
+	}
+    }
+
+  if (IS_RIP_DEBUG_ZEBRA)
+    vty_out (vty, "  RIP zebra debugging is on%s", VTY_NEWLINE);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_rip_events,
+       debug_rip_events_cmd,
+       "debug rip events",
+       DEBUG_STR
+       RIP_STR
+       "RIP events\n")
+{
+  rip_debug_event = RIP_DEBUG_EVENT;
+  return CMD_WARNING;
+}
+
+DEFUN (debug_rip_packet,
+       debug_rip_packet_cmd,
+       "debug rip packet",
+       DEBUG_STR
+       RIP_STR
+       "RIP packet\n")
+{
+  rip_debug_packet = RIP_DEBUG_PACKET;
+  rip_debug_packet |= RIP_DEBUG_SEND;
+  rip_debug_packet |= RIP_DEBUG_RECV;
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_rip_packet_direct,
+       debug_rip_packet_direct_cmd,
+       "debug rip packet (recv|send)",
+       DEBUG_STR
+       RIP_STR
+       "RIP packet\n"
+       "RIP receive packet\n"
+       "RIP send packet\n")
+{
+  rip_debug_packet |= RIP_DEBUG_PACKET;
+  if (strncmp ("send", argv[0], strlen (argv[0])) == 0)
+    rip_debug_packet |= RIP_DEBUG_SEND;
+  if (strncmp ("recv", argv[0], strlen (argv[0])) == 0)
+    rip_debug_packet |= RIP_DEBUG_RECV;
+  rip_debug_packet &= ~RIP_DEBUG_DETAIL;
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_rip_packet_detail,
+       debug_rip_packet_detail_cmd,
+       "debug rip packet (recv|send) detail",
+       DEBUG_STR
+       RIP_STR
+       "RIP packet\n"
+       "RIP receive packet\n"
+       "RIP send packet\n"
+       "Detailed information display\n")
+{
+  rip_debug_packet |= RIP_DEBUG_PACKET;
+  if (strncmp ("send", argv[0], strlen (argv[0])) == 0)
+    rip_debug_packet |= RIP_DEBUG_SEND;
+  if (strncmp ("recv", argv[0], strlen (argv[0])) == 0)
+    rip_debug_packet |= RIP_DEBUG_RECV;
+  rip_debug_packet |= RIP_DEBUG_DETAIL;
+  return CMD_SUCCESS;
+}
+
+DEFUN (debug_rip_zebra,
+       debug_rip_zebra_cmd,
+       "debug rip zebra",
+       DEBUG_STR
+       RIP_STR
+       "RIP and ZEBRA communication\n")
+{
+  rip_debug_zebra = RIP_DEBUG_ZEBRA;
+  return CMD_WARNING;
+}
+
+DEFUN (no_debug_rip_events,
+       no_debug_rip_events_cmd,
+       "no debug rip events",
+       NO_STR
+       DEBUG_STR
+       RIP_STR
+       "RIP events\n")
+{
+  rip_debug_event = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_rip_packet,
+       no_debug_rip_packet_cmd,
+       "no debug rip packet",
+       NO_STR
+       DEBUG_STR
+       RIP_STR
+       "RIP packet\n")
+{
+  rip_debug_packet = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_rip_packet_direct,
+       no_debug_rip_packet_direct_cmd,
+       "no debug rip packet (recv|send)",
+       NO_STR
+       DEBUG_STR
+       RIP_STR
+       "RIP packet\n"
+       "RIP option set for receive packet\n"
+       "RIP option set for send packet\n")
+{
+  if (strncmp ("send", argv[0], strlen (argv[0])) == 0)
+    {
+      if (IS_RIP_DEBUG_RECV)
+       rip_debug_packet &= ~RIP_DEBUG_SEND;
+      else
+       rip_debug_packet = 0;
+    }
+  else if (strncmp ("recv", argv[0], strlen (argv[0])) == 0)
+    {
+      if (IS_RIP_DEBUG_SEND)
+       rip_debug_packet &= ~RIP_DEBUG_RECV;
+      else
+       rip_debug_packet = 0;
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_rip_zebra,
+       no_debug_rip_zebra_cmd,
+       "no debug rip zebra",
+       NO_STR
+       DEBUG_STR
+       RIP_STR
+       "RIP and ZEBRA communication\n")
+{
+  rip_debug_zebra = 0;
+  return CMD_WARNING;
+}
+
+/* Debug node. */
+struct cmd_node debug_node =
+{
+  DEBUG_NODE,
+  "",				/* Debug node has no interface. */
+  1
+};
+
+int
+config_write_debug (struct vty *vty)
+{
+  int write = 0;
+
+  if (IS_RIP_DEBUG_EVENT)
+    {
+      vty_out (vty, "debug rip events%s", VTY_NEWLINE);
+      write++;
+    }
+  if (IS_RIP_DEBUG_PACKET)
+    {
+      if (IS_RIP_DEBUG_SEND && IS_RIP_DEBUG_RECV)
+	{
+	  vty_out (vty, "debug rip packet%s%s",
+		   IS_RIP_DEBUG_DETAIL ? " detail" : "",
+		   VTY_NEWLINE);
+	  write++;
+	}
+      else
+	{
+	  if (IS_RIP_DEBUG_SEND)
+	    vty_out (vty, "debug rip packet send%s%s",
+		     IS_RIP_DEBUG_DETAIL ? " detail" : "",
+		     VTY_NEWLINE);
+	  else
+	    vty_out (vty, "debug rip packet recv%s%s",
+		     IS_RIP_DEBUG_DETAIL ? " detail" : "",
+		     VTY_NEWLINE);
+	  write++;
+	}
+    }
+  if (IS_RIP_DEBUG_ZEBRA)
+    {
+      vty_out (vty, "debug rip zebra%s", VTY_NEWLINE);
+      write++;
+    }
+  return write;
+}
+
+void
+rip_debug_reset ()
+{
+  rip_debug_event = 0;
+  rip_debug_packet = 0;
+  rip_debug_zebra = 0;
+}
+
+void
+rip_debug_init ()
+{
+  rip_debug_event = 0;
+  rip_debug_packet = 0;
+  rip_debug_zebra = 0;
+
+  install_node (&debug_node, config_write_debug);
+
+  install_element (ENABLE_NODE, &show_debugging_rip_cmd);
+  install_element (ENABLE_NODE, &debug_rip_events_cmd);
+  install_element (ENABLE_NODE, &debug_rip_packet_cmd);
+  install_element (ENABLE_NODE, &debug_rip_packet_direct_cmd);
+  install_element (ENABLE_NODE, &debug_rip_packet_detail_cmd);
+  install_element (ENABLE_NODE, &debug_rip_zebra_cmd);
+  install_element (ENABLE_NODE, &no_debug_rip_events_cmd);
+  install_element (ENABLE_NODE, &no_debug_rip_packet_cmd);
+  install_element (ENABLE_NODE, &no_debug_rip_packet_direct_cmd);
+  install_element (ENABLE_NODE, &no_debug_rip_zebra_cmd);
+
+  install_element (CONFIG_NODE, &debug_rip_events_cmd);
+  install_element (CONFIG_NODE, &debug_rip_packet_cmd);
+  install_element (CONFIG_NODE, &debug_rip_packet_direct_cmd);
+  install_element (CONFIG_NODE, &debug_rip_packet_detail_cmd);
+  install_element (CONFIG_NODE, &debug_rip_zebra_cmd);
+  install_element (CONFIG_NODE, &no_debug_rip_events_cmd);
+  install_element (CONFIG_NODE, &no_debug_rip_packet_cmd);
+  install_element (CONFIG_NODE, &no_debug_rip_packet_direct_cmd);
+  install_element (CONFIG_NODE, &no_debug_rip_zebra_cmd);
+}
diff --git a/ripd/rip_debug.h b/ripd/rip_debug.h
new file mode 100644
index 0000000..3b44d0c
--- /dev/null
+++ b/ripd/rip_debug.h
@@ -0,0 +1,54 @@
+/* RIP debug routines
+ * 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_RIP_DEBUG_H
+#define _ZEBRA_RIP_DEBUG_H
+
+/* RIP debug event flags. */
+#define RIP_DEBUG_EVENT   0x01
+
+/* RIP debug packet flags. */
+#define RIP_DEBUG_PACKET  0x01
+#define RIP_DEBUG_SEND    0x20
+#define RIP_DEBUG_RECV    0x40
+#define RIP_DEBUG_DETAIL  0x80
+
+/* RIP debug zebra flags. */
+#define RIP_DEBUG_ZEBRA   0x01
+
+/* Debug related macro. */
+#define IS_RIP_DEBUG_EVENT  (rip_debug_event & RIP_DEBUG_EVENT)
+
+#define IS_RIP_DEBUG_PACKET (rip_debug_packet & RIP_DEBUG_PACKET)
+#define IS_RIP_DEBUG_SEND   (rip_debug_packet & RIP_DEBUG_SEND)
+#define IS_RIP_DEBUG_RECV   (rip_debug_packet & RIP_DEBUG_RECV)
+#define IS_RIP_DEBUG_DETAIL (rip_debug_packet & RIP_DEBUG_DETAIL)
+
+#define IS_RIP_DEBUG_ZEBRA  (rip_debug_zebra & RIP_DEBUG_ZEBRA)
+
+extern unsigned long rip_debug_event;
+extern unsigned long rip_debug_packet;
+extern unsigned long rip_debug_zebra;
+
+void rip_debug_init ();
+void rip_debug_reset ();
+
+#endif /* _ZEBRA_RIP_DEBUG_H */
diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c
new file mode 100644
index 0000000..06d4416
--- /dev/null
+++ b/ripd/rip_interface.c
@@ -0,0 +1,2001 @@
+/* Interface related function for RIP.
+ * Copyright (C) 1997, 98 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>
+
+#include "command.h"
+#include "if.h"
+#include "sockunion.h"
+#include "prefix.h"
+#include "memory.h"
+#include "network.h"
+#include "table.h"
+#include "log.h"
+#include "stream.h"
+#include "thread.h"
+#include "zclient.h"
+#include "filter.h"
+#include "sockopt.h"
+
+#include "zebra/connected.h"
+
+#include "ripd/ripd.h"
+#include "ripd/rip_debug.h"
+
+void rip_enable_apply (struct interface *);
+void rip_passive_interface_apply (struct interface *);
+int rip_if_down(struct interface *ifp);
+
+struct message ri_version_msg[] = 
+{
+  {RI_RIP_VERSION_1,       "1"},
+  {RI_RIP_VERSION_2,       "2"},
+  {RI_RIP_VERSION_1_AND_2, "1 2"},
+  {0,                      NULL}
+};
+
+/* RIP enabled network vector. */
+vector rip_enable_interface;
+
+/* RIP enabled interface table. */
+struct route_table *rip_enable_network;
+
+/* Vector to store passive-interface name. */
+vector Vrip_passive_interface;
+
+/* Join to the RIP version 2 multicast group. */
+int
+ipv4_multicast_join (int sock, 
+		     struct in_addr group, 
+		     struct in_addr ifa,
+		     unsigned int ifindex)
+{
+  int ret;
+
+  ret = setsockopt_multicast_ipv4 (sock, 
+				   IP_ADD_MEMBERSHIP, 
+				   ifa, 
+				   group.s_addr, 
+				   ifindex); 
+
+  if (ret < 0) 
+    zlog (NULL, LOG_INFO, "can't setsockopt IP_ADD_MEMBERSHIP %s",
+	  strerror (errno));
+
+  return ret;
+}
+
+/* Leave from the RIP version 2 multicast group. */
+int
+ipv4_multicast_leave (int sock, 
+		      struct in_addr group, 
+		      struct in_addr ifa,
+		      unsigned int ifindex)
+{
+  int ret;
+
+  ret = setsockopt_multicast_ipv4 (sock, 
+				   IP_DROP_MEMBERSHIP, 
+				   ifa, 
+				   group.s_addr, 
+				   ifindex);
+
+  if (ret < 0) 
+    zlog (NULL, LOG_INFO, "can't setsockopt IP_DROP_MEMBERSHIP");
+
+  return ret;
+}
+
+/* Allocate new RIP's interface configuration. */
+struct rip_interface *
+rip_interface_new ()
+{
+  struct rip_interface *ri;
+
+  ri = XMALLOC (MTYPE_RIP_INTERFACE, sizeof (struct rip_interface));
+  memset (ri, 0, sizeof (struct rip_interface));
+
+  /* Default authentication type is simple password for Cisco
+     compatibility. */
+  /* ri->auth_type = RIP_NO_AUTH; */
+  ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD;
+
+  /* Set default split-horizon behavior.  If the interface is Frame
+     Relay or SMDS is enabled, the default value for split-horizon is
+     off.  But currently Zebra does detect Frame Relay or SMDS
+     interface.  So all interface is set to split horizon.  */
+  ri->split_horizon_default = 1;
+  ri->split_horizon = ri->split_horizon_default;
+
+  return ri;
+}
+
+void
+rip_interface_multicast_set (int sock, struct interface *ifp)
+{
+  int ret;
+  listnode node;
+  struct servent *sp;
+  struct sockaddr_in from;
+
+  for (node = listhead (ifp->connected); node; nextnode (node))
+    {
+      struct prefix_ipv4 *p;
+      struct connected *connected;
+      struct in_addr addr;
+
+      connected = getdata (node);
+      p = (struct prefix_ipv4 *) connected->address;
+
+      if (p->family == AF_INET)
+	{
+	  addr = p->prefix;
+
+	  if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF,
+					 addr, 0, ifp->ifindex) < 0) 
+	    {
+	      zlog_warn ("Can't setsockopt IP_MULTICAST_IF to fd %d", sock);
+	      return;
+	    }
+
+	  /* Bind myself. */
+	  memset (&from, 0, sizeof (struct sockaddr_in));
+
+	  /* Set RIP port. */
+	  sp = getservbyname ("router", "udp");
+	  if (sp) 
+	    from.sin_port = sp->s_port;
+	  else 
+	    from.sin_port = htons (RIP_PORT_DEFAULT);
+
+	  /* Address shoud be any address. */
+	  from.sin_family = AF_INET;
+	  from.sin_addr = addr;
+#ifdef HAVE_SIN_LEN
+	  from.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+
+	  ret = bind (sock, (struct sockaddr *) & from, 
+		      sizeof (struct sockaddr_in));
+	  if (ret < 0)
+	    {
+	      zlog_warn ("Can't bind socket: %s", strerror (errno));
+	      return;
+	    }
+
+	  return;
+
+	}
+    }
+}
+
+/* Send RIP request packet to specified interface. */
+void
+rip_request_interface_send (struct interface *ifp, u_char version)
+{
+  struct sockaddr_in to;
+
+  /* RIPv2 support multicast. */
+  if (version == RIPv2 && if_is_multicast (ifp))
+    {
+      
+      if (IS_RIP_DEBUG_EVENT)
+	zlog_info ("multicast request on %s", ifp->name);
+
+      rip_request_send (NULL, ifp, version);
+      return;
+    }
+
+  /* RIPv1 and non multicast interface. */
+  if (if_is_pointopoint (ifp) || if_is_broadcast (ifp))
+    {
+      listnode cnode;
+
+      if (IS_RIP_DEBUG_EVENT)
+	zlog_info ("broadcast request to %s", ifp->name);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+	{
+	  struct prefix_ipv4 *p;
+	  struct connected *connected;
+
+	  connected = getdata (cnode);
+	  p = (struct prefix_ipv4 *) connected->destination;
+
+	  if (p->family == AF_INET)
+	    {
+	      memset (&to, 0, sizeof (struct sockaddr_in));
+	      to.sin_port = htons (RIP_PORT_DEFAULT);
+	      to.sin_addr = p->prefix;
+
+#if 0
+	      if (IS_RIP_DEBUG_EVENT)
+		zlog_info ("SEND request to %s", inet_ntoa (to.sin_addr));
+#endif /* 0 */
+	      
+	      rip_request_send (&to, ifp, version);
+	    }
+	}
+    }
+}
+
+/* This will be executed when interface goes up. */
+void
+rip_request_interface (struct interface *ifp)
+{
+  struct rip_interface *ri;
+
+  /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */
+  if (if_is_loopback (ifp))
+    return;
+
+  /* If interface is down, don't send RIP packet. */
+  if (! if_is_up (ifp))
+    return;
+
+  /* Fetch RIP interface information. */
+  ri = ifp->info;
+
+
+  /* If there is no version configuration in the interface,
+     use rip's version setting. */
+  if (ri->ri_send == RI_RIP_UNSPEC)
+    {
+      if (rip->version == RIPv1)
+	rip_request_interface_send (ifp, RIPv1);
+      else
+	rip_request_interface_send (ifp, RIPv2);
+    }
+  /* If interface has RIP version configuration use it. */
+  else
+    {
+      if (ri->ri_send & RIPv1)
+	rip_request_interface_send (ifp, RIPv1);
+      if (ri->ri_send & RIPv2)
+	rip_request_interface_send (ifp, RIPv2);
+    }
+}
+
+/* Send RIP request to the neighbor. */
+void
+rip_request_neighbor (struct in_addr addr)
+{
+  struct sockaddr_in to;
+
+  memset (&to, 0, sizeof (struct sockaddr_in));
+  to.sin_port = htons (RIP_PORT_DEFAULT);
+  to.sin_addr = addr;
+
+  rip_request_send (&to, NULL, rip->version);
+}
+
+/* Request routes at all interfaces. */
+void
+rip_request_neighbor_all ()
+{
+  struct route_node *rp;
+
+  if (! rip)
+    return;
+
+  if (IS_RIP_DEBUG_EVENT)
+    zlog_info ("request to the all neighbor");
+
+  /* Send request to all neighbor. */
+  for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
+    if (rp->info)
+      rip_request_neighbor (rp->p.u.prefix4);
+}
+
+/* Multicast packet receive socket. */
+int
+rip_multicast_join (struct interface *ifp, int sock)
+{
+  listnode cnode;
+
+  if (if_is_up (ifp) && if_is_multicast (ifp))
+    {
+      if (IS_RIP_DEBUG_EVENT)
+	zlog_info ("multicast join at %s", ifp->name);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+	{
+	  struct prefix_ipv4 *p;
+	  struct connected *connected;
+	  struct in_addr group;
+	      
+	  connected = getdata (cnode);
+	  p = (struct prefix_ipv4 *) connected->address;
+      
+	  if (p->family != AF_INET)
+	    continue;
+      
+	  group.s_addr = htonl (INADDR_RIP_GROUP);
+	  if (ipv4_multicast_join (sock, group, p->prefix, ifp->ifindex) < 0)
+	    return -1;
+	  else
+	    return 0;
+	}
+    }
+  return 0;
+}
+
+/* Leave from multicast group. */
+void
+rip_multicast_leave (struct interface *ifp, int sock)
+{
+  listnode cnode;
+
+  if (if_is_up (ifp) && if_is_multicast (ifp))
+    {
+      if (IS_RIP_DEBUG_EVENT)
+	zlog_info ("multicast leave from %s", ifp->name);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+	{
+	  struct prefix_ipv4 *p;
+	  struct connected *connected;
+	  struct in_addr group;
+	      
+	  connected = getdata (cnode);
+	  p = (struct prefix_ipv4 *) connected->address;
+      
+	  if (p->family != AF_INET)
+	    continue;
+      
+	  group.s_addr = htonl (INADDR_RIP_GROUP);
+          if (ipv4_multicast_leave (sock, group, p->prefix, ifp->ifindex) == 0)
+	    return;
+        }
+    }
+}
+
+/* Is there and address on interface that I could use ? */
+int
+rip_if_ipv4_address_check (struct interface *ifp)
+{
+  struct listnode *nn;
+  struct connected *connected;
+  int count = 0;
+
+  for (nn = listhead (ifp->connected); nn; nextnode (nn))
+    if ((connected = getdata (nn)) != NULL)
+      {
+	struct prefix *p;
+
+	p = connected->address;
+
+	if (p->family == AF_INET)
+          {
+	    count++;
+	  }
+      }
+						
+  return count;
+}
+						
+						
+						
+
+/* Does this address belongs to me ? */
+int
+if_check_address (struct in_addr addr)
+{
+  listnode node;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      listnode cnode;
+      struct interface *ifp;
+
+      ifp = getdata (node);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+	{
+	  struct connected *connected;
+	  struct prefix_ipv4 *p;
+
+	  connected = getdata (cnode);
+	  p = (struct prefix_ipv4 *) connected->address;
+
+	  if (p->family != AF_INET)
+	    continue;
+
+	  if (IPV4_ADDR_CMP (&p->prefix, &addr) == 0)
+	    return 1;
+	}
+    }
+  return 0;
+}
+
+/* is this address from a valid neighbor? (RFC2453 - Sec. 3.9.2) */
+int
+if_valid_neighbor (struct in_addr addr)
+{
+  listnode node;
+  struct connected *connected = NULL;
+  struct prefix_ipv4 *p;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      listnode cnode;
+      struct interface *ifp;
+
+      ifp = getdata (node);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+	{
+	  struct prefix *pxn = NULL; /* Prefix of the neighbor */
+	  struct prefix *pxc = NULL; /* Prefix of the connected network */
+
+	  connected = getdata (cnode);
+
+	  if (if_is_pointopoint (ifp))
+	    {
+	      p = (struct prefix_ipv4 *) connected->address;
+
+	      if (p && p->family == AF_INET)
+		{
+		  if (IPV4_ADDR_SAME (&p->prefix, &addr))
+		    return 1;
+
+		  p = (struct prefix_ipv4 *) connected->destination;
+		  if (p && IPV4_ADDR_SAME (&p->prefix, &addr))
+		    return 1;
+		}
+	    }
+	  else
+	    {
+	      p = (struct prefix_ipv4 *) connected->address;
+
+	      if (p->family != AF_INET)
+		continue;
+
+	      pxn = prefix_new();
+	      pxn->family = AF_INET;
+	      pxn->prefixlen = 32;
+	      pxn->u.prefix4 = addr;
+	      
+	      pxc = prefix_new();
+	      prefix_copy(pxc, (struct prefix *) p);
+	      apply_mask(pxc);
+	  
+	      if (prefix_match (pxc, pxn)) 
+		{
+		  prefix_free (pxn);
+		  prefix_free (pxc);
+		  return 1;
+		}
+	      prefix_free(pxc);
+	      prefix_free(pxn);
+	    }
+	}
+    }
+  return 0;
+}
+
+/* Inteface link down message processing. */
+int
+rip_interface_down (int command, struct zclient *zclient, zebra_size_t length)
+{
+  struct interface *ifp;
+  struct stream *s;
+
+  s = zclient->ibuf;  
+
+  /* zebra_interface_state_read() updates interface structure in
+     iflist. */
+  ifp = zebra_interface_state_read(s);
+
+  if (ifp == NULL)
+    return 0;
+
+  rip_if_down(ifp);
+ 
+  if (IS_RIP_DEBUG_ZEBRA)
+    zlog_info ("interface %s index %d flags %ld metric %d mtu %d is down",
+	       ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+
+  return 0;
+}
+
+/* Inteface link up message processing */
+int
+rip_interface_up (int command, struct zclient *zclient, zebra_size_t length)
+{
+  struct interface *ifp;
+
+  /* zebra_interface_state_read () updates interface structure in
+     iflist. */
+  ifp = zebra_interface_state_read (zclient->ibuf);
+
+  if (ifp == NULL)
+    return 0;
+
+  if (IS_RIP_DEBUG_ZEBRA)
+    zlog_info ("interface %s index %d flags %ld metric %d mtu %d is up",
+	       ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+
+  /* Check if this interface is RIP enabled or not.*/
+  rip_enable_apply (ifp);
+ 
+  /* Check for a passive interface */
+  rip_passive_interface_apply (ifp);
+
+  /* Apply distribute list to the all interface. */
+  rip_distribute_update_interface (ifp);
+
+  return 0;
+}
+
+/* Inteface addition message from zebra. */
+int
+rip_interface_add (int command, struct zclient *zclient, zebra_size_t length)
+{
+  struct interface *ifp;
+
+  ifp = zebra_interface_add_read (zclient->ibuf);
+
+  if (IS_RIP_DEBUG_ZEBRA)
+    zlog_info ("interface add %s index %d flags %ld metric %d mtu %d",
+	       ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
+
+  /* Check if this interface is RIP enabled or not.*/
+  rip_enable_apply (ifp);
+
+  /* Apply distribute list to the all interface. */
+  rip_distribute_update_interface (ifp);
+
+  /* rip_request_neighbor_all (); */
+
+  return 0;
+}
+
+int
+rip_interface_delete (int command, struct zclient *zclient,
+		      zebra_size_t length)
+{
+  struct interface *ifp;
+  struct stream *s;
+
+
+  s = zclient->ibuf;  
+  /* zebra_interface_state_read() updates interface structure in iflist */
+  ifp = zebra_interface_state_read(s);
+
+  if (ifp == NULL)
+    return 0;
+
+  if (if_is_up (ifp)) {
+    rip_if_down(ifp);
+  } 
+  
+  zlog_info("interface delete %s index %d flags %ld metric %d mtu %d",
+	    ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);  
+  
+  /* To support pseudo interface do not free interface structure.  */
+  /* if_delete(ifp); */
+
+  return 0;
+}
+
+void
+rip_interface_clean ()
+{
+  listnode node;
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      ri = ifp->info;
+
+      ri->enable_network = 0;
+      ri->enable_interface = 0;
+      ri->running = 0;
+
+      if (ri->t_wakeup)
+	{
+	  thread_cancel (ri->t_wakeup);
+	  ri->t_wakeup = NULL;
+	}
+    }
+}
+
+void
+rip_interface_reset ()
+{
+  listnode node;
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      ri = ifp->info;
+
+      ri->enable_network = 0;
+      ri->enable_interface = 0;
+      ri->running = 0;
+
+      ri->ri_send = RI_RIP_UNSPEC;
+      ri->ri_receive = RI_RIP_UNSPEC;
+
+      /* ri->auth_type = RIP_NO_AUTH; */
+      ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD;
+
+      if (ri->auth_str)
+	{
+	  free (ri->auth_str);
+	  ri->auth_str = NULL;
+	}
+      if (ri->key_chain)
+	{
+	  free (ri->key_chain);
+	  ri->key_chain = NULL;
+	}
+
+      ri->split_horizon = 0;
+      ri->split_horizon_default = 0;
+
+      ri->list[RIP_FILTER_IN] = NULL;
+      ri->list[RIP_FILTER_OUT] = NULL;
+
+      ri->prefix[RIP_FILTER_IN] = NULL;
+      ri->prefix[RIP_FILTER_OUT] = NULL;
+      
+      if (ri->t_wakeup)
+	{
+	  thread_cancel (ri->t_wakeup);
+	  ri->t_wakeup = NULL;
+	}
+
+      ri->recv_badpackets = 0;
+      ri->recv_badroutes = 0;
+      ri->sent_updates = 0;
+
+      ri->passive = 0;
+    }
+}
+
+int
+rip_if_down(struct interface *ifp)
+{
+  struct route_node *rp;
+  struct rip_info *rinfo;
+  struct rip_interface *ri = NULL;
+  if (rip)
+    {
+      for (rp = route_top (rip->table); rp; rp = route_next (rp))
+	if ((rinfo = rp->info) != NULL)
+	  {
+	    /* Routes got through this interface. */
+	    if (rinfo->ifindex == ifp->ifindex &&
+		rinfo->type == ZEBRA_ROUTE_RIP &&
+		rinfo->sub_type == RIP_ROUTE_RTE)
+	      {
+		rip_zebra_ipv4_delete ((struct prefix_ipv4 *) &rp->p,
+				       &rinfo->nexthop,
+				       rinfo->ifindex);
+
+		rip_redistribute_delete (rinfo->type,rinfo->sub_type,
+					 (struct prefix_ipv4 *)&rp->p,
+					 rinfo->ifindex);
+	      }
+	    else
+	      {
+		/* All redistributed routes but static and system */
+		if ((rinfo->ifindex == ifp->ifindex) &&
+		    (rinfo->type != ZEBRA_ROUTE_STATIC) &&
+		    (rinfo->type != ZEBRA_ROUTE_SYSTEM))
+		  rip_redistribute_delete (rinfo->type,rinfo->sub_type,
+					   (struct prefix_ipv4 *)&rp->p,
+					   rinfo->ifindex);
+	      }
+	  }
+    }
+	    
+  ri = ifp->info;
+  
+  if (ri->running)
+   {
+     if (IS_RIP_DEBUG_EVENT)
+       zlog_info ("turn off %s", ifp->name);
+
+     /* Leave from multicast group. */
+     rip_multicast_leave (ifp, rip->sock);
+
+     ri->running = 0;
+   }
+
+  return 0;
+}
+
+/* Needed for stop RIP process. */
+void
+rip_if_down_all ()
+{
+  struct interface *ifp;
+  listnode node;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      rip_if_down (ifp);
+    }
+}
+
+int
+rip_interface_address_add (int command, struct zclient *zclient,
+			   zebra_size_t length)
+{
+  struct connected *ifc;
+  struct prefix *p;
+
+  ifc = zebra_interface_address_add_read (zclient->ibuf);
+
+  if (ifc == NULL)
+    return 0;
+
+  p = ifc->address;
+
+  if (p->family == AF_INET)
+    {
+      if (IS_RIP_DEBUG_ZEBRA)
+	zlog_info ("connected address %s/%d is added", 
+		   inet_ntoa (p->u.prefix4), p->prefixlen);
+      
+      /* Check is this interface is RIP enabled or not.*/
+      rip_enable_apply (ifc->ifp);
+
+#ifdef HAVE_SNMP
+      rip_ifaddr_add (ifc->ifp, ifc);
+#endif /* HAVE_SNMP */
+    }
+
+  return 0;
+}
+
+int
+rip_interface_address_delete (int command, struct zclient *zclient,
+			      zebra_size_t length)
+{
+  struct connected *ifc;
+  struct prefix *p;
+
+  ifc = zebra_interface_address_delete_read (zclient->ibuf);
+  
+  if (ifc)
+    {
+      p = ifc->address;
+      if (p->family == AF_INET)
+	{
+	  if (IS_RIP_DEBUG_ZEBRA)
+
+	    zlog_info ("connected address %s/%d is deleted",
+		       inet_ntoa (p->u.prefix4), p->prefixlen);
+
+#ifdef HAVE_SNMP
+	  rip_ifaddr_delete (ifc->ifp, ifc);
+#endif /* HAVE_SNMP */
+
+	  /* Check if this interface is RIP enabled or not.*/
+	  rip_enable_apply (ifc->ifp);
+	}
+
+      connected_free (ifc);
+
+    }
+
+  return 0;
+}
+
+/* Check interface is enabled by network statement. */
+int
+rip_enable_network_lookup (struct interface *ifp)
+{
+  struct listnode *nn;
+  struct connected *connected;
+  struct prefix_ipv4 address;
+
+  for (nn = listhead (ifp->connected); nn; nextnode (nn))
+    if ((connected = getdata (nn)) != NULL)
+      {
+	struct prefix *p; 
+	struct route_node *node;
+
+	p = connected->address;
+
+	if (p->family == AF_INET)
+	  {
+	    address.family = AF_INET;
+	    address.prefix = p->u.prefix4;
+	    address.prefixlen = IPV4_MAX_BITLEN;
+	    
+	    node = route_node_match (rip_enable_network,
+				     (struct prefix *)&address);
+	    if (node)
+	      {
+		route_unlock_node (node);
+		return 1;
+	      }
+	  }
+      }
+  return -1;
+}
+
+/* Add RIP enable network. */
+int
+rip_enable_network_add (struct prefix *p)
+{
+  struct route_node *node;
+
+  node = route_node_get (rip_enable_network, p);
+
+  if (node->info)
+    {
+      route_unlock_node (node);
+      return -1;
+    }
+  else
+    node->info = "enabled";
+
+  return 1;
+}
+
+/* Delete RIP enable network. */
+int
+rip_enable_network_delete (struct prefix *p)
+{
+  struct route_node *node;
+
+  node = route_node_lookup (rip_enable_network, p);
+  if (node)
+    {
+      node->info = NULL;
+
+      /* Unlock info lock. */
+      route_unlock_node (node);
+
+      /* Unlock lookup lock. */
+      route_unlock_node (node);
+
+      return 1;
+    }
+  return -1;
+}
+
+/* Check interface is enabled by ifname statement. */
+int
+rip_enable_if_lookup (char *ifname)
+{
+  int i;
+  char *str;
+
+  for (i = 0; i < vector_max (rip_enable_interface); i++)
+    if ((str = vector_slot (rip_enable_interface, i)) != NULL)
+      if (strcmp (str, ifname) == 0)
+	return i;
+  return -1;
+}
+
+/* Add interface to rip_enable_if. */
+int
+rip_enable_if_add (char *ifname)
+{
+  int ret;
+
+  ret = rip_enable_if_lookup (ifname);
+  if (ret >= 0)
+    return -1;
+
+  vector_set (rip_enable_interface, strdup (ifname));
+
+  return 1;
+}
+
+/* Delete interface from rip_enable_if. */
+int
+rip_enable_if_delete (char *ifname)
+{
+  int index;
+  char *str;
+
+  index = rip_enable_if_lookup (ifname);
+  if (index < 0)
+    return -1;
+
+  str = vector_slot (rip_enable_interface, index);
+  free (str);
+  vector_unset (rip_enable_interface, index);
+
+  return 1;
+}
+
+/* Join to multicast group and send request to the interface. */
+int
+rip_interface_wakeup (struct thread *t)
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  /* Get interface. */
+  ifp = THREAD_ARG (t);
+
+  ri = ifp->info;
+  ri->t_wakeup = NULL;
+
+  /* Join to multicast group. */
+  if (rip_multicast_join (ifp, rip->sock) < 0)
+    {
+      zlog_err ("multicast join failed, interface %s not running", ifp->name);
+      return 0;
+    }
+
+  /* Set running flag. */
+  ri->running = 1;
+
+  /* Send RIP request to the interface. */
+  rip_request_interface (ifp);
+
+  return 0;
+}
+
+int rip_redistribute_check (int);
+
+void
+rip_connect_set (struct interface *ifp, int set)
+{
+  struct listnode *nn;
+  struct connected *connected;
+  struct prefix_ipv4 address;
+
+  for (nn = listhead (ifp->connected); nn; nextnode (nn))
+    if ((connected = getdata (nn)) != NULL)
+      {
+	struct prefix *p; 
+	p = connected->address;
+
+	if (p->family != AF_INET)
+	  continue;
+
+	address.family = AF_INET;
+	address.prefix = p->u.prefix4;
+	address.prefixlen = p->prefixlen;
+	apply_mask_ipv4 (&address);
+
+	if (set)
+	  rip_redistribute_add (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE,
+				&address, connected->ifp->ifindex, NULL);
+	else
+	  {
+	    rip_redistribute_delete (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE,
+				     &address, connected->ifp->ifindex);
+	    if (rip_redistribute_check (ZEBRA_ROUTE_CONNECT))
+	      rip_redistribute_add (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_REDISTRIBUTE,
+				    &address, connected->ifp->ifindex, NULL);
+	  }
+      }
+}
+
+/* Update interface status. */
+void
+rip_enable_apply (struct interface *ifp)
+{
+  int ret;
+  struct rip_interface *ri = NULL;
+
+  /* Check interface. */
+  if (if_is_loopback (ifp))
+    return;
+
+  if (! if_is_up (ifp))
+    return;
+
+  ri = ifp->info;
+
+  /* Check network configuration. */
+  ret = rip_enable_network_lookup (ifp);
+
+  /* If the interface is matched. */
+  if (ret > 0)
+    ri->enable_network = 1;
+  else
+    ri->enable_network = 0;
+
+  /* Check interface name configuration. */
+  ret = rip_enable_if_lookup (ifp->name);
+  if (ret >= 0)
+    ri->enable_interface = 1;
+  else
+    ri->enable_interface = 0;
+
+  /* any interface MUST have an IPv4 address */
+  if ( ! rip_if_ipv4_address_check (ifp) )
+    {
+      ri->enable_network = 0;
+      ri->enable_interface = 0;
+    }
+
+  /* Update running status of the interface. */
+  if (ri->enable_network || ri->enable_interface)
+    {
+      if (! ri->running)
+	{
+	  if (IS_RIP_DEBUG_EVENT)
+	    zlog_info ("turn on %s", ifp->name);
+
+	  /* Add interface wake up thread. */
+	  if (! ri->t_wakeup)
+	    ri->t_wakeup = thread_add_timer (master, rip_interface_wakeup,
+					     ifp, 1);
+          rip_connect_set (ifp, 1);
+	}
+    }
+  else
+    {
+      if (ri->running)
+	{
+	  if (IS_RIP_DEBUG_EVENT)
+	    zlog_info ("turn off %s", ifp->name);
+
+	  /* Might as well clean up the route table as well */ 
+	  rip_if_down(ifp);
+
+	  ri->running = 0;
+          rip_connect_set (ifp, 0);
+	}
+    }
+}
+
+/* Apply network configuration to all interface. */
+void
+rip_enable_apply_all ()
+{
+  struct interface *ifp;
+  listnode node;
+
+  /* Check each interface. */
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      rip_enable_apply (ifp);
+    }
+}
+
+int
+rip_neighbor_lookup (struct sockaddr_in *from)
+{
+  struct prefix_ipv4 p;
+  struct route_node *node;
+
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefix = from->sin_addr;
+  p.prefixlen = IPV4_MAX_BITLEN;
+
+  node = route_node_lookup (rip->neighbor, (struct prefix *) &p);
+  if (node)
+    {
+      route_unlock_node (node);
+      return 1;
+    }
+  return 0;
+}
+
+/* Add new RIP neighbor to the neighbor tree. */
+int
+rip_neighbor_add (struct prefix_ipv4 *p)
+{
+  struct route_node *node;
+
+  node = route_node_get (rip->neighbor, (struct prefix *) p);
+
+  if (node->info)
+    return -1;
+
+  node->info = rip->neighbor;
+
+  return 0;
+}
+
+/* Delete RIP neighbor from the neighbor tree. */
+int
+rip_neighbor_delete (struct prefix_ipv4 *p)
+{
+  struct route_node *node;
+
+  /* Lock for look up. */
+  node = route_node_lookup (rip->neighbor, (struct prefix *) p);
+  if (! node)
+    return -1;
+  
+  node->info = NULL;
+
+  /* Unlock lookup lock. */
+  route_unlock_node (node);
+
+  /* Unlock real neighbor information lock. */
+  route_unlock_node (node);
+
+  return 0;
+}
+
+/* Clear all network and neighbor configuration. */
+void
+rip_clean_network ()
+{
+  int i;
+  char *str;
+  struct route_node *rn;
+
+  /* rip_enable_network. */
+  for (rn = route_top (rip_enable_network); rn; rn = route_next (rn))
+    if (rn->info)
+      {
+	rn->info = NULL;
+	route_unlock_node (rn);
+      }
+
+  /* rip_enable_interface. */
+  for (i = 0; i < vector_max (rip_enable_interface); i++)
+    if ((str = vector_slot (rip_enable_interface, i)) != NULL)
+      {
+	free (str);
+	vector_slot (rip_enable_interface, i) = NULL;
+      }
+}
+
+/* Utility function for looking up passive interface settings. */
+int
+rip_passive_interface_lookup (char *ifname)
+{
+  int i;
+  char *str;
+
+  for (i = 0; i < vector_max (Vrip_passive_interface); i++)
+    if ((str = vector_slot (Vrip_passive_interface, i)) != NULL)
+      if (strcmp (str, ifname) == 0)
+	return i;
+  return -1;
+}
+
+void
+rip_passive_interface_apply (struct interface *ifp)
+{
+  int ret;
+  struct rip_interface *ri;
+
+  ri = ifp->info;
+
+  ret = rip_passive_interface_lookup (ifp->name);
+  if (ret < 0)
+    ri->passive = 0;
+  else
+    ri->passive = 1;
+}
+
+void
+rip_passive_interface_apply_all ()
+{
+  struct interface *ifp;
+  listnode node;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      rip_passive_interface_apply (ifp);
+    }
+}
+
+/* Passive interface. */
+int
+rip_passive_interface_set (struct vty *vty, char *ifname)
+{
+  if (rip_passive_interface_lookup (ifname) >= 0)
+    return CMD_WARNING;
+
+  vector_set (Vrip_passive_interface, strdup (ifname));
+
+  rip_passive_interface_apply_all ();
+
+  return CMD_SUCCESS;
+}
+
+int
+rip_passive_interface_unset (struct vty *vty, char *ifname)
+{
+  int i;
+  char *str;
+
+  i = rip_passive_interface_lookup (ifname);
+  if (i < 0)
+    return CMD_WARNING;
+
+  str = vector_slot (Vrip_passive_interface, i);
+  free (str);
+  vector_unset (Vrip_passive_interface, i);
+
+  rip_passive_interface_apply_all ();
+
+  return CMD_SUCCESS;
+}
+
+/* Free all configured RIP passive-interface settings. */
+void
+rip_passive_interface_clean ()
+{
+  int i;
+  char *str;
+
+  for (i = 0; i < vector_max (Vrip_passive_interface); i++)
+    if ((str = vector_slot (Vrip_passive_interface, i)) != NULL)
+      {
+	free (str);
+	vector_slot (Vrip_passive_interface, i) = NULL;
+      }
+  rip_passive_interface_apply_all ();
+}
+
+/* RIP enable network or interface configuration. */
+DEFUN (rip_network,
+       rip_network_cmd,
+       "network (A.B.C.D/M|WORD)",
+       "Enable routing on an IP network\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Interface name\n")
+{
+  int ret;
+  struct prefix_ipv4 p;
+
+  ret = str2prefix_ipv4 (argv[0], &p);
+
+  if (ret)
+    ret = rip_enable_network_add ((struct prefix *) &p);
+  else
+    ret = rip_enable_if_add (argv[0]);
+
+  if (ret < 0)
+    {
+      vty_out (vty, "There is a same network configuration %s%s", argv[0],
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  rip_enable_apply_all ();
+
+  return CMD_SUCCESS;
+}
+
+/* RIP enable network or interface configuration. */
+DEFUN (no_rip_network,
+       no_rip_network_cmd,
+       "no network (A.B.C.D/M|WORD)",
+       NO_STR
+       "Enable routing on an IP network\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
+       "Interface name\n")
+{
+  int ret;
+  struct prefix_ipv4 p;
+
+  ret = str2prefix_ipv4 (argv[0], &p);
+
+  if (ret)
+    ret = rip_enable_network_delete ((struct prefix *) &p);
+  else
+    ret = rip_enable_if_delete (argv[0]);
+
+  if (ret < 0)
+    {
+      vty_out (vty, "Can't find network configuration %s%s", argv[0],
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  rip_enable_apply_all ();
+
+  return CMD_SUCCESS;
+}
+
+/* RIP neighbor configuration set. */
+DEFUN (rip_neighbor,
+       rip_neighbor_cmd,
+       "neighbor A.B.C.D",
+       "Specify a neighbor router\n"
+       "Neighbor address\n")
+{
+  int ret;
+  struct prefix_ipv4 p;
+
+  ret = str2prefix_ipv4 (argv[0], &p);
+
+  if (ret <= 0)
+    {
+      vty_out (vty, "Please specify address by A.B.C.D%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  rip_neighbor_add (&p);
+  
+  return CMD_SUCCESS;
+}
+
+/* RIP neighbor configuration unset. */
+DEFUN (no_rip_neighbor,
+       no_rip_neighbor_cmd,
+       "no neighbor A.B.C.D",
+       NO_STR
+       "Specify a neighbor router\n"
+       "Neighbor address\n")
+{
+  int ret;
+  struct prefix_ipv4 p;
+
+  ret = str2prefix_ipv4 (argv[0], &p);
+
+  if (ret <= 0)
+    {
+      vty_out (vty, "Please specify address by A.B.C.D%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  rip_neighbor_delete (&p);
+  
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_rip_receive_version,
+       ip_rip_receive_version_cmd,
+       "ip rip receive version (1|2)",
+       IP_STR
+       "Routing Information Protocol\n"
+       "Advertisement reception\n"
+       "Version control\n"
+       "RIP version 1\n"
+       "RIP version 2\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  /* Version 1. */
+  if (atoi (argv[0]) == 1)
+    {
+      ri->ri_receive = RI_RIP_VERSION_1;
+      return CMD_SUCCESS;
+    }
+  if (atoi (argv[0]) == 2)
+    {
+      ri->ri_receive = RI_RIP_VERSION_2;
+      return CMD_SUCCESS;
+    }
+  return CMD_WARNING;
+}
+
+DEFUN (ip_rip_receive_version_1,
+       ip_rip_receive_version_1_cmd,
+       "ip rip receive version 1 2",
+       IP_STR
+       "Routing Information Protocol\n"
+       "Advertisement reception\n"
+       "Version control\n"
+       "RIP version 1\n"
+       "RIP version 2\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  /* Version 1 and 2. */
+  ri->ri_receive = RI_RIP_VERSION_1_AND_2;
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_rip_receive_version_2,
+       ip_rip_receive_version_2_cmd,
+       "ip rip receive version 2 1",
+       IP_STR
+       "Routing Information Protocol\n"
+       "Advertisement reception\n"
+       "Version control\n"
+       "RIP version 2\n"
+       "RIP version 1\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  /* Version 1 and 2. */
+  ri->ri_receive = RI_RIP_VERSION_1_AND_2;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_rip_receive_version,
+       no_ip_rip_receive_version_cmd,
+       "no ip rip receive version",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Advertisement reception\n"
+       "Version control\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  ri->ri_receive = RI_RIP_UNSPEC;
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_rip_receive_version,
+       no_ip_rip_receive_version_num_cmd,
+       "no ip rip receive version (1|2)",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Advertisement reception\n"
+       "Version control\n"
+       "Version 1\n"
+       "Version 2\n")
+
+DEFUN (ip_rip_send_version,
+       ip_rip_send_version_cmd,
+       "ip rip send version (1|2)",
+       IP_STR
+       "Routing Information Protocol\n"
+       "Advertisement transmission\n"
+       "Version control\n"
+       "RIP version 1\n"
+       "RIP version 2\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  /* Version 1. */
+  if (atoi (argv[0]) == 1)
+    {
+      ri->ri_send = RI_RIP_VERSION_1;
+      return CMD_SUCCESS;
+    }
+  if (atoi (argv[0]) == 2)
+    {
+      ri->ri_send = RI_RIP_VERSION_2;
+      return CMD_SUCCESS;
+    }
+  return CMD_WARNING;
+}
+
+DEFUN (ip_rip_send_version_1,
+       ip_rip_send_version_1_cmd,
+       "ip rip send version 1 2",
+       IP_STR
+       "Routing Information Protocol\n"
+       "Advertisement transmission\n"
+       "Version control\n"
+       "RIP version 1\n"
+       "RIP version 2\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  /* Version 1 and 2. */
+  ri->ri_send = RI_RIP_VERSION_1_AND_2;
+  return CMD_SUCCESS;
+}
+
+DEFUN (ip_rip_send_version_2,
+       ip_rip_send_version_2_cmd,
+       "ip rip send version 2 1",
+       IP_STR
+       "Routing Information Protocol\n"
+       "Advertisement transmission\n"
+       "Version control\n"
+       "RIP version 2\n"
+       "RIP version 1\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  /* Version 1 and 2. */
+  ri->ri_send = RI_RIP_VERSION_1_AND_2;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_rip_send_version,
+       no_ip_rip_send_version_cmd,
+       "no ip rip send version",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Advertisement transmission\n"
+       "Version control\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  ri->ri_send = RI_RIP_UNSPEC;
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_rip_send_version,
+       no_ip_rip_send_version_num_cmd,
+       "no ip rip send version (1|2)",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Advertisement transmission\n"
+       "Version control\n"
+       "Version 1\n"
+       "Version 2\n")
+
+DEFUN (ip_rip_authentication_mode,
+       ip_rip_authentication_mode_cmd,
+       "ip rip authentication mode (md5|text)",
+       IP_STR
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication mode\n"
+       "Keyed message digest\n"
+       "Clear text authentication\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  if (strncmp ("md5", argv[0], strlen (argv[0])) == 0)
+    ri->auth_type = RIP_AUTH_MD5;
+  else if (strncmp ("text", argv[0], strlen (argv[0])) == 0)
+    ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD;
+  else
+    {
+      vty_out (vty, "mode should be md5 or text%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_rip_authentication_mode,
+       no_ip_rip_authentication_mode_cmd,
+       "no ip rip authentication mode",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication mode\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  /* ri->auth_type = RIP_NO_AUTH; */
+  ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD;
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_rip_authentication_mode,
+       no_ip_rip_authentication_mode_type_cmd,
+       "no ip rip authentication mode (md5|text)",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication mode\n"
+       "Keyed message digest\n"
+       "Clear text authentication\n")
+
+DEFUN (ip_rip_authentication_string,
+       ip_rip_authentication_string_cmd,
+       "ip rip authentication string LINE",
+       IP_STR
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication string\n"
+       "Authentication string\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  if (strlen (argv[0]) > 16)
+    {
+      vty_out (vty, "%% RIPv2 authentication string must be shorter than 16%s",
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (ri->key_chain)
+    {
+      vty_out (vty, "%% key-chain configuration exists%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (ri->auth_str)
+    free (ri->auth_str);
+
+  ri->auth_str = strdup (argv[0]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_rip_authentication_string,
+       no_ip_rip_authentication_string_cmd,
+       "no ip rip authentication string",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication string\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *)vty->index;
+  ri = ifp->info;
+
+  if (ri->auth_str)
+    free (ri->auth_str);
+
+  ri->auth_str = NULL;
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_rip_authentication_string,
+       no_ip_rip_authentication_string2_cmd,
+       "no ip rip authentication string LINE",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication string\n"
+       "Authentication string\n")
+
+DEFUN (ip_rip_authentication_key_chain,
+       ip_rip_authentication_key_chain_cmd,
+       "ip rip authentication key-chain LINE",
+       IP_STR
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication key-chain\n"
+       "name of key-chain\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *) vty->index;
+  ri = ifp->info;
+
+  if (ri->auth_str)
+    {
+      vty_out (vty, "%% authentication string configuration exists%s",
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if (ri->key_chain)
+    free (ri->key_chain);
+
+  ri->key_chain = strdup (argv[0]);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_rip_authentication_key_chain,
+       no_ip_rip_authentication_key_chain_cmd,
+       "no ip rip authentication key-chain",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication key-chain\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = (struct interface *) vty->index;
+  ri = ifp->info;
+
+  if (ri->key_chain)
+    free (ri->key_chain);
+
+  ri->key_chain = NULL;
+
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_rip_authentication_key_chain,
+       no_ip_rip_authentication_key_chain2_cmd,
+       "no ip rip authentication key-chain LINE",
+       NO_STR
+       IP_STR
+       "Routing Information Protocol\n"
+       "Authentication control\n"
+       "Authentication key-chain\n"
+       "name of key-chain\n")
+
+DEFUN (rip_split_horizon,
+       rip_split_horizon_cmd,
+       "ip split-horizon",
+       IP_STR
+       "Perform split horizon\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = vty->index;
+  ri = ifp->info;
+
+  ri->split_horizon = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_split_horizon,
+       no_rip_split_horizon_cmd,
+       "no ip split-horizon",
+       NO_STR
+       IP_STR
+       "Perform split horizon\n")
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  ifp = vty->index;
+  ri = ifp->info;
+
+  ri->split_horizon = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (rip_passive_interface,
+       rip_passive_interface_cmd,
+       "passive-interface IFNAME",
+       "Suppress routing updates on an interface\n"
+       "Interface name\n")
+{
+  return rip_passive_interface_set (vty, argv[0]);
+}
+
+DEFUN (no_rip_passive_interface,
+       no_rip_passive_interface_cmd,
+       "no passive-interface IFNAME",
+       NO_STR
+       "Suppress routing updates on an interface\n"
+       "Interface name\n")
+{
+  return rip_passive_interface_unset (vty, argv[0]);
+}
+
+/* Write rip configuration of each interface. */
+int
+rip_interface_config_write (struct vty *vty)
+{
+  listnode node;
+  struct interface *ifp;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      struct rip_interface *ri;
+
+      ifp = getdata (node);
+      ri = ifp->info;
+
+      vty_out (vty, "interface %s%s", ifp->name,
+	       VTY_NEWLINE);
+
+      if (ifp->desc)
+	vty_out (vty, " description %s%s", ifp->desc,
+		 VTY_NEWLINE);
+
+      /* Split horizon. */
+      if (ri->split_horizon != ri->split_horizon_default)
+	{
+	  if (ri->split_horizon)
+	    vty_out (vty, " ip split-horizon%s", VTY_NEWLINE);
+	  else
+	    vty_out (vty, " no ip split-horizon%s", VTY_NEWLINE);
+	}
+
+      /* RIP version setting. */
+      if (ri->ri_send != RI_RIP_UNSPEC)
+	vty_out (vty, " ip rip send version %s%s",
+		 lookup (ri_version_msg, ri->ri_send),
+		 VTY_NEWLINE);
+
+      if (ri->ri_receive != RI_RIP_UNSPEC)
+	vty_out (vty, " ip rip receive version %s%s",
+		 lookup (ri_version_msg, ri->ri_receive),
+		 VTY_NEWLINE);
+
+      /* RIP authentication. */
+#if 0 
+      /* RIP_AUTH_SIMPLE_PASSWORD becomes default mode. */
+      if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
+	vty_out (vty, " ip rip authentication mode text%s", VTY_NEWLINE);
+#endif /* 0 */
+      if (ri->auth_type == RIP_AUTH_MD5)
+	vty_out (vty, " ip rip authentication mode md5%s", VTY_NEWLINE);
+
+      if (ri->auth_str)
+	vty_out (vty, " ip rip authentication string %s%s",
+		 ri->auth_str, VTY_NEWLINE);
+
+      if (ri->key_chain)
+	vty_out (vty, " ip rip authentication key-chain %s%s",
+		 ri->key_chain, VTY_NEWLINE);
+
+      vty_out (vty, "!%s", VTY_NEWLINE);
+    }
+  return 0;
+}
+
+int
+config_write_rip_network (struct vty *vty, int config_mode)
+{
+  int i;
+  char *ifname;
+  struct route_node *node;
+
+  /* Network type RIP enable interface statement. */
+  for (node = route_top (rip_enable_network); node; node = route_next (node))
+    if (node->info)
+      vty_out (vty, "%s%s/%d%s", 
+	       config_mode ? " network " : "    ",
+	       inet_ntoa (node->p.u.prefix4),
+	       node->p.prefixlen,
+	       VTY_NEWLINE);
+
+  /* Interface name RIP enable statement. */
+  for (i = 0; i < vector_max (rip_enable_interface); i++)
+    if ((ifname = vector_slot (rip_enable_interface, i)) != NULL)
+      vty_out (vty, "%s%s%s",
+	       config_mode ? " network " : "    ",
+	       ifname,
+	       VTY_NEWLINE);
+
+  /* RIP neighbors listing. */
+  for (node = route_top (rip->neighbor); node; node = route_next (node))
+    if (node->info)
+      vty_out (vty, "%s%s%s", 
+	       config_mode ? " neighbor " : "    ",
+	       inet_ntoa (node->p.u.prefix4),
+	       VTY_NEWLINE);
+
+  /* RIP passive interface listing. */
+  if (config_mode)
+    for (i = 0; i < vector_max (Vrip_passive_interface); i++)
+      if ((ifname = vector_slot (Vrip_passive_interface, i)) != NULL)
+	vty_out (vty, " passive-interface %s%s", ifname, VTY_NEWLINE);
+
+  return 0;
+}
+
+struct cmd_node interface_node =
+{
+  INTERFACE_NODE,
+  "%s(config-if)# ",
+  1,
+};
+
+/* Called when interface structure allocated. */
+int
+rip_interface_new_hook (struct interface *ifp)
+{
+  ifp->info = rip_interface_new ();
+  return 0;
+}
+
+/* Called when interface structure deleted. */
+int
+rip_interface_delete_hook (struct interface *ifp)
+{
+  XFREE (MTYPE_RIP_INTERFACE, ifp->info);
+  return 0;
+}
+
+/* Allocate and initialize interface vector. */
+void
+rip_if_init ()
+{
+  /* Default initial size of interface vector. */
+  if_init();
+  if_add_hook (IF_NEW_HOOK, rip_interface_new_hook);
+  if_add_hook (IF_DELETE_HOOK, rip_interface_delete_hook);
+  
+  /* RIP network init. */
+  rip_enable_interface = vector_init (1);
+  rip_enable_network = route_table_init ();
+
+  /* RIP passive interface. */
+  Vrip_passive_interface = vector_init (1);
+
+  /* Install interface node. */
+  install_node (&interface_node, rip_interface_config_write);
+
+  /* Install commands. */
+  install_element (CONFIG_NODE, &interface_cmd);
+  install_default (INTERFACE_NODE);
+  install_element (INTERFACE_NODE, &interface_desc_cmd);
+  install_element (INTERFACE_NODE, &no_interface_desc_cmd);
+  install_element (RIP_NODE, &rip_network_cmd);
+  install_element (RIP_NODE, &no_rip_network_cmd);
+  install_element (RIP_NODE, &rip_neighbor_cmd);
+  install_element (RIP_NODE, &no_rip_neighbor_cmd);
+
+  install_element (RIP_NODE, &rip_passive_interface_cmd);
+  install_element (RIP_NODE, &no_rip_passive_interface_cmd);
+
+  install_element (INTERFACE_NODE, &ip_rip_send_version_cmd);
+  install_element (INTERFACE_NODE, &ip_rip_send_version_1_cmd);
+  install_element (INTERFACE_NODE, &ip_rip_send_version_2_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_send_version_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_send_version_num_cmd);
+
+  install_element (INTERFACE_NODE, &ip_rip_receive_version_cmd);
+  install_element (INTERFACE_NODE, &ip_rip_receive_version_1_cmd);
+  install_element (INTERFACE_NODE, &ip_rip_receive_version_2_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_receive_version_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_receive_version_num_cmd);
+
+  install_element (INTERFACE_NODE, &ip_rip_authentication_mode_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_type_cmd);
+
+  install_element (INTERFACE_NODE, &ip_rip_authentication_key_chain_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain2_cmd);
+
+  install_element (INTERFACE_NODE, &ip_rip_authentication_string_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_authentication_string_cmd);
+  install_element (INTERFACE_NODE, &no_ip_rip_authentication_string2_cmd);
+
+  install_element (INTERFACE_NODE, &rip_split_horizon_cmd);
+  install_element (INTERFACE_NODE, &no_rip_split_horizon_cmd);
+}
diff --git a/ripd/rip_main.c b/ripd/rip_main.c
new file mode 100644
index 0000000..1070fb4
--- /dev/null
+++ b/ripd/rip_main.c
@@ -0,0 +1,270 @@
+/* RIPd main routine.
+ * Copyright (C) 1997, 98 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>
+
+#include "version.h"
+#include "getopt.h"
+#include "thread.h"
+#include "command.h"
+#include "memory.h"
+#include "prefix.h"
+#include "filter.h"
+#include "keychain.h"
+#include "log.h"
+
+#include "ripd/ripd.h"
+
+/* ripd options. */
+static struct option longopts[] = 
+{
+  { "daemon",      no_argument,       NULL, 'd'},
+  { "config_file", required_argument, NULL, 'f'},
+  { "pid_file",    required_argument, NULL, 'i'},
+  { "help",        no_argument,       NULL, 'h'},
+  { "vty_addr",    required_argument, NULL, 'A'},
+  { "vty_port",    required_argument, NULL, 'P'},
+  { "retain",      no_argument,       NULL, 'r'},
+  { "version",     no_argument,       NULL, 'v'},
+  { 0 }
+};
+
+/* Configuration file and directory. */
+char config_current[] = RIPD_DEFAULT_CONFIG;
+char config_default[] = SYSCONFDIR RIPD_DEFAULT_CONFIG;
+char *config_file = NULL;
+
+/* ripd program name */
+
+/* Route retain mode flag. */
+int retain_mode = 0;
+
+/* RIP VTY bind address. */
+char *vty_addr = NULL;
+
+/* RIP VTY connection port. */
+int vty_port = RIP_VTY_PORT;
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* Process ID saved for use by init system */
+char *pid_file = PATH_RIPD_PID;
+
+/* Help information display. */
+static void
+usage (char *progname, int status)
+{
+  if (status != 0)
+    fprintf (stderr, "Try `%s --help' for more information.\n", progname);
+  else
+    {    
+      printf ("Usage : %s [OPTION...]\n\
+Daemon which manages RIP version 1 and 2.\n\n\
+-d, --daemon       Runs in daemon mode\n\
+-f, --config_file  Set configuration file name\n\
+-i, --pid_file     Set process identifier file name\n\
+-A, --vty_addr     Set vty's bind address\n\
+-P, --vty_port     Set vty's port number\n\
+-r, --retain       When program terminates, retain added route by ripd.\n\
+-v, --version      Print program version\n\
+-h, --help         Display this help and exit\n\
+\n\
+Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
+    }
+
+  exit (status);
+}
+
+/* Signale wrapper. */
+RETSIGTYPE *
+signal_set (int signo, void (*func)(int))
+{
+  int ret;
+  struct sigaction sig;
+  struct sigaction osig;
+
+  sig.sa_handler = func;
+  sigemptyset (&sig.sa_mask);
+  sig.sa_flags = 0;
+#ifdef SA_RESTART
+  sig.sa_flags |= SA_RESTART;
+#endif /* SA_RESTART */
+
+  ret = sigaction (signo, &sig, &osig);
+
+  if (ret < 0) 
+    return (SIG_ERR);
+  else
+    return (osig.sa_handler);
+}
+
+/* SIGHUP handler. */
+void 
+sighup (int sig)
+{
+  zlog_info ("SIGHUP received");
+  rip_clean ();
+  rip_reset ();
+  zlog_info ("ripd restarting!");
+
+  /* Reload config file. */
+  vty_read_config (config_file, config_current, config_default);
+
+  /* Create VTY's socket */
+  vty_serv_sock (vty_addr, vty_port, RIP_VTYSH_PATH);
+
+  /* Try to return to normal operation. */
+}
+
+/* SIGINT handler. */
+void
+sigint (int sig)
+{
+  zlog (NULL, LOG_INFO, "Terminating on signal");
+
+  if (! retain_mode)
+    rip_clean ();
+
+  exit (0);
+}
+
+/* SIGUSR1 handler. */
+void
+sigusr1 (int sig)
+{
+  zlog_rotate (NULL);
+}
+
+/* Initialization of signal handles. */
+void
+signal_init ()
+{
+  signal_set (SIGHUP, sighup);
+  signal_set (SIGINT, sigint);
+  signal_set (SIGTERM, sigint);
+  signal_set (SIGPIPE, SIG_IGN);
+  signal_set (SIGUSR1, sigusr1);
+}
+
+/* Main routine of ripd. */
+int
+main (int argc, char **argv)
+{
+  char *p;
+  int daemon_mode = 0;
+  char *progname;
+  struct thread thread;
+
+  /* Set umask before anything for security */
+  umask (0027);
+
+  /* Get program name. */
+  progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]);
+
+  /* First of all we need logging init. */
+  zlog_default = openzlog (progname, ZLOG_NOLOG, ZLOG_RIP,
+			   LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
+
+  /* Command line option parse. */
+  while (1) 
+    {
+      int opt;
+
+      opt = getopt_long (argc, argv, "df:hA:P:rv", longopts, 0);
+    
+      if (opt == EOF)
+	break;
+
+      switch (opt) 
+	{
+	case 0:
+	  break;
+	case 'd':
+	  daemon_mode = 1;
+	  break;
+	case 'f':
+	  config_file = optarg;
+	  break;
+	case 'A':
+	  vty_addr = optarg;
+	  break;
+        case 'i':
+          pid_file = optarg;
+          break;
+	case 'P':
+	  vty_port = atoi (optarg);
+	  break;
+	case 'r':
+	  retain_mode = 1;
+	  break;
+	case 'v':
+	  print_version (progname);
+	  exit (0);
+	  break;
+	case 'h':
+	  usage (progname, 0);
+	  break;
+	default:
+	  usage (progname, 1);
+	  break;
+	}
+    }
+
+  /* Prepare master thread. */
+  master = thread_master_create ();
+
+  /* Library initialization. */
+  signal_init ();
+  cmd_init (1);
+  vty_init ();
+  memory_init ();
+  keychain_init ();
+
+  /* RIP related initialization. */
+  rip_init ();
+  rip_if_init ();
+  rip_zclient_init ();
+  rip_peer_init ();
+
+  /* Sort all installed commands. */
+  sort_node ();
+
+  /* Get configuration file. */
+  vty_read_config (config_file, config_current, config_default);
+
+  /* Change to the daemon program. */
+  if (daemon_mode)
+    daemon (0, 0);
+
+  /* Pid file create. */
+  pid_output (pid_file);
+
+  /* Create VTY's socket */
+  vty_serv_sock (vty_addr, vty_port, RIP_VTYSH_PATH);
+
+  /* Execute each thread. */
+  while (thread_fetch (master, &thread))
+    thread_call (&thread);
+
+  /* Not reached. */
+  exit (0);
+}
diff --git a/ripd/rip_offset.c b/ripd/rip_offset.c
new file mode 100644
index 0000000..0d47348
--- /dev/null
+++ b/ripd/rip_offset.c
@@ -0,0 +1,414 @@
+/* RIP offset-list
+ * Copyright (C) 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.  
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "prefix.h"
+#include "filter.h"
+#include "command.h"
+#include "linklist.h"
+#include "memory.h"
+
+#define RIP_OFFSET_LIST_IN  0
+#define RIP_OFFSET_LIST_OUT 1
+#define RIP_OFFSET_LIST_MAX 2
+
+struct rip_offset_list
+{
+  char *ifname;
+
+  struct 
+  {
+    char *alist_name;
+    /* struct access_list *alist; */
+    int metric;
+  } direct[RIP_OFFSET_LIST_MAX];
+};
+
+static struct list *rip_offset_list_master;
+
+int
+strcmp_safe (char *s1, char *s2)
+{
+  if (s1 == NULL && s2 == NULL)
+    return 0;
+  if (s1 == NULL)
+    return -1;
+  if (s2 == NULL)
+    return 1;
+  return strcmp (s1, s2);
+}
+
+struct rip_offset_list *
+rip_offset_list_new ()
+{
+  struct rip_offset_list *new;
+
+  new = XMALLOC (MTYPE_RIP_OFFSET_LIST, sizeof (struct rip_offset_list));
+  memset (new, 0, sizeof (struct rip_offset_list));
+  return new;
+}
+
+void
+rip_offset_list_free (struct rip_offset_list *offset)
+{
+  XFREE (MTYPE_RIP_OFFSET_LIST, offset);
+}
+
+struct rip_offset_list *
+rip_offset_list_lookup (char *ifname)
+{
+  struct rip_offset_list *offset;
+  struct listnode *nn;
+
+  LIST_LOOP (rip_offset_list_master, offset, nn)
+    {
+      if (strcmp_safe (offset->ifname, ifname) == 0)
+	return offset;
+    }
+  return NULL;
+}
+
+struct rip_offset_list *
+rip_offset_list_get (char *ifname)
+{
+  struct rip_offset_list *offset;
+  
+  offset = rip_offset_list_lookup (ifname);
+  if (offset)
+    return offset;
+
+  offset = rip_offset_list_new ();
+  if (ifname)
+    offset->ifname = strdup (ifname);
+  listnode_add_sort (rip_offset_list_master, offset);
+
+  return offset;
+}
+
+int
+rip_offset_list_set (struct vty *vty, char *alist, char *direct_str,
+		     char *metric_str, char *ifname)
+{
+  int direct;
+  int metric;
+  struct rip_offset_list *offset;
+
+  /* Check direction. */
+  if (strncmp (direct_str, "i", 1) == 0)
+    direct = RIP_OFFSET_LIST_IN;
+  else if (strncmp (direct_str, "o", 1) == 0)
+    direct = RIP_OFFSET_LIST_OUT;
+  else
+    {
+      vty_out (vty, "Invalid direction: %s%s", direct_str, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Check metric. */
+  metric = atoi (metric_str);
+  if (metric < 0 || metric > 16)
+    {
+      vty_out (vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Get offset-list structure with interface name. */
+  offset = rip_offset_list_get (ifname);
+
+  if (offset->direct[direct].alist_name)
+    free (offset->direct[direct].alist_name);
+  offset->direct[direct].alist_name = strdup (alist);
+  offset->direct[direct].metric = metric;
+
+  return CMD_SUCCESS;
+}
+
+int
+rip_offset_list_unset (struct vty *vty, char *alist, char *direct_str,
+		       char *metric_str, char *ifname)
+{
+  int direct;
+  int metric;
+  struct rip_offset_list *offset;
+
+  /* Check direction. */
+  if (strncmp (direct_str, "i", 1) == 0)
+    direct = RIP_OFFSET_LIST_IN;
+  else if (strncmp (direct_str, "o", 1) == 0)
+    direct = RIP_OFFSET_LIST_OUT;
+  else
+    {
+      vty_out (vty, "Invalid direction: %s%s", direct_str, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Check metric. */
+  metric = atoi (metric_str);
+  if (metric < 0 || metric > 16)
+    {
+      vty_out (vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Get offset-list structure with interface name. */
+  offset = rip_offset_list_lookup (ifname);
+
+  if (offset)
+    {
+      if (offset->direct[direct].alist_name)
+	free (offset->direct[direct].alist_name);
+      offset->direct[direct].alist_name = NULL;
+
+      if (offset->direct[RIP_OFFSET_LIST_IN].alist_name == NULL &&
+	  offset->direct[RIP_OFFSET_LIST_OUT].alist_name == NULL)
+	{
+	  listnode_delete (rip_offset_list_master, offset);
+	  if (offset->ifname)
+	    free (offset->ifname);
+	  rip_offset_list_free (offset);
+	}
+    }
+  else
+    {
+      vty_out (vty, "Can't find offset-list%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  return CMD_SUCCESS;
+}
+
+#define OFFSET_LIST_IN_NAME(O)  ((O)->direct[RIP_OFFSET_LIST_IN].alist_name)
+#define OFFSET_LIST_IN_METRIC(O)  ((O)->direct[RIP_OFFSET_LIST_IN].metric)
+
+#define OFFSET_LIST_OUT_NAME(O)  ((O)->direct[RIP_OFFSET_LIST_OUT].alist_name)
+#define OFFSET_LIST_OUT_METRIC(O)  ((O)->direct[RIP_OFFSET_LIST_OUT].metric)
+
+/* If metric is modifed return 1. */
+int
+rip_offset_list_apply_in (struct prefix_ipv4 *p, struct interface *ifp,
+			  u_int32_t *metric)
+{
+  struct rip_offset_list *offset;
+  struct access_list *alist;
+
+  /* Look up offset-list with interface name. */
+  offset = rip_offset_list_lookup (ifp->name);
+  if (offset && OFFSET_LIST_IN_NAME (offset))
+    {
+      alist = access_list_lookup (AFI_IP, OFFSET_LIST_IN_NAME (offset));
+
+      if (alist 
+	  && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT)
+	{
+	  *metric += OFFSET_LIST_IN_METRIC (offset);
+	  return 1;
+	}
+      return 0;
+    }
+  /* Look up offset-list without interface name. */
+  offset = rip_offset_list_lookup (NULL);
+  if (offset && OFFSET_LIST_IN_NAME (offset))
+    {
+      alist = access_list_lookup (AFI_IP, OFFSET_LIST_IN_NAME (offset));
+
+      if (alist 
+	  && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT)
+	{
+	  *metric += OFFSET_LIST_IN_METRIC (offset);
+	  return 1;
+	}
+      return 0;
+    }
+  return 0;
+}
+
+/* If metric is modifed return 1. */
+int
+rip_offset_list_apply_out (struct prefix_ipv4 *p, struct interface *ifp,
+			  u_int32_t *metric)
+{
+  struct rip_offset_list *offset;
+  struct access_list *alist;
+
+  /* Look up offset-list with interface name. */
+  offset = rip_offset_list_lookup (ifp->name);
+  if (offset && OFFSET_LIST_OUT_NAME (offset))
+    {
+      alist = access_list_lookup (AFI_IP, OFFSET_LIST_OUT_NAME (offset));
+
+      if (alist 
+	  && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT)
+	{
+	  *metric += OFFSET_LIST_OUT_METRIC (offset);
+	  return 1;
+	}
+      return 0;
+    }
+
+  /* Look up offset-list without interface name. */
+  offset = rip_offset_list_lookup (NULL);
+  if (offset && OFFSET_LIST_OUT_NAME (offset))
+    {
+      alist = access_list_lookup (AFI_IP, OFFSET_LIST_OUT_NAME (offset));
+
+      if (alist 
+	  && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT)
+	{
+	  *metric += OFFSET_LIST_OUT_METRIC (offset);
+	  return 1;
+	}
+      return 0;
+    }
+  return 0;
+}
+
+DEFUN (rip_offset_list,
+       rip_offset_list_cmd,
+       "offset-list WORD (in|out) <0-16>",
+       "Modify RIP metric\n"
+       "Access-list name\n"
+       "For incoming updates\n"
+       "For outgoing updates\n"
+       "Metric value\n")
+{
+  return rip_offset_list_set (vty, argv[0], argv[1], argv[2], NULL);
+}
+
+DEFUN (rip_offset_list_ifname,
+       rip_offset_list_ifname_cmd,
+       "offset-list WORD (in|out) <0-16> IFNAME",
+       "Modify RIP metric\n"
+       "Access-list name\n"
+       "For incoming updates\n"
+       "For outgoing updates\n"
+       "Metric value\n"
+       "Interface to match\n")
+{
+  return rip_offset_list_set (vty, argv[0], argv[1], argv[2], argv[3]);
+}
+
+DEFUN (no_rip_offset_list,
+       no_rip_offset_list_cmd,
+       "no offset-list WORD (in|out) <0-16>",
+       NO_STR
+       "Modify RIP metric\n"
+       "Access-list name\n"
+       "For incoming updates\n"
+       "For outgoing updates\n"
+       "Metric value\n")
+{
+  return rip_offset_list_unset (vty, argv[0], argv[1], argv[2], NULL);
+}
+
+DEFUN (no_rip_offset_list_ifname,
+       no_rip_offset_list_ifname_cmd,
+       "no offset-list WORD (in|out) <0-16> IFNAME",
+       NO_STR
+       "Modify RIP metric\n"
+       "Access-list name\n"
+       "For incoming updates\n"
+       "For outgoing updates\n"
+       "Metric value\n"
+       "Interface to match\n")
+{
+  return rip_offset_list_unset (vty, argv[0], argv[1], argv[2], argv[3]);
+}
+
+int
+offset_list_cmp (struct rip_offset_list *o1, struct rip_offset_list *o2)
+{
+  return strcmp_safe (o1->ifname, o2->ifname);
+}
+
+void
+offset_list_del (struct rip_offset_list *offset)
+{
+  if (OFFSET_LIST_IN_NAME (offset))
+    free (OFFSET_LIST_IN_NAME (offset));
+  if (OFFSET_LIST_OUT_NAME (offset))
+    free (OFFSET_LIST_OUT_NAME (offset));
+  if (offset->ifname)
+    free (offset->ifname);
+  rip_offset_list_free (offset);
+}
+
+void
+rip_offset_init ()
+{
+  rip_offset_list_master = list_new ();
+  rip_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp;
+  rip_offset_list_master->del = (void (*)(void *)) offset_list_del;
+
+  install_element (RIP_NODE, &rip_offset_list_cmd);
+  install_element (RIP_NODE, &rip_offset_list_ifname_cmd);
+  install_element (RIP_NODE, &no_rip_offset_list_cmd);
+  install_element (RIP_NODE, &no_rip_offset_list_ifname_cmd);
+}
+
+void
+rip_offset_clean ()
+{
+  list_delete (rip_offset_list_master);
+
+  rip_offset_list_master = list_new ();
+  rip_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp;
+  rip_offset_list_master->del = (void (*)(void *)) offset_list_del;
+}
+
+int
+config_write_rip_offset_list (struct vty *vty)
+{
+  struct listnode *nn;
+  struct rip_offset_list *offset;
+
+  LIST_LOOP (rip_offset_list_master, offset, nn)
+    {
+      if (! offset->ifname)
+	{
+	  if (offset->direct[RIP_OFFSET_LIST_IN].alist_name)
+	    vty_out (vty, " offset-list %s in %d%s",
+		     offset->direct[RIP_OFFSET_LIST_IN].alist_name,
+		     offset->direct[RIP_OFFSET_LIST_IN].metric,
+		     VTY_NEWLINE);
+	  if (offset->direct[RIP_OFFSET_LIST_OUT].alist_name)
+	    vty_out (vty, " offset-list %s out %d%s",
+		     offset->direct[RIP_OFFSET_LIST_OUT].alist_name,
+		     offset->direct[RIP_OFFSET_LIST_OUT].metric,
+		     VTY_NEWLINE);
+	}
+      else
+	{
+	  if (offset->direct[RIP_OFFSET_LIST_IN].alist_name)
+	    vty_out (vty, " offset-list %s in %d %s%s",
+		     offset->direct[RIP_OFFSET_LIST_IN].alist_name,
+		     offset->direct[RIP_OFFSET_LIST_IN].metric,
+		     offset->ifname, VTY_NEWLINE);
+	  if (offset->direct[RIP_OFFSET_LIST_OUT].alist_name)
+	    vty_out (vty, " offset-list %s out %d %s%s",
+		     offset->direct[RIP_OFFSET_LIST_OUT].alist_name,
+		     offset->direct[RIP_OFFSET_LIST_OUT].metric,
+		     offset->ifname, VTY_NEWLINE);
+	}
+    }
+
+  return 0;
+}
diff --git a/ripd/rip_peer.c b/ripd/rip_peer.c
new file mode 100644
index 0000000..20c2da7
--- /dev/null
+++ b/ripd/rip_peer.c
@@ -0,0 +1,211 @@
+/* RIP peer support
+ * Copyright (C) 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.  
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "prefix.h"
+#include "command.h"
+#include "linklist.h"
+#include "thread.h"
+#include "memory.h"
+
+#include "ripd/ripd.h"
+
+/* Linked list of RIP peer. */
+struct list *peer_list;
+
+struct rip_peer *
+rip_peer_new ()
+{
+  struct rip_peer *new;
+
+  new = XMALLOC (MTYPE_RIP_PEER, sizeof (struct rip_peer));
+  memset (new, 0, sizeof (struct rip_peer));
+  return new;
+}
+
+void
+rip_peer_free (struct rip_peer *peer)
+{
+  XFREE (MTYPE_RIP_PEER, peer);
+}
+
+struct rip_peer *
+rip_peer_lookup (struct in_addr *addr)
+{
+  struct rip_peer *peer;
+  struct listnode *nn;
+
+  LIST_LOOP (peer_list, peer, nn)
+    {
+      if (IPV4_ADDR_SAME (&peer->addr, addr))
+	return peer;
+    }
+  return NULL;
+}
+
+struct rip_peer *
+rip_peer_lookup_next (struct in_addr *addr)
+{
+  struct rip_peer *peer;
+  struct listnode *nn;
+
+  LIST_LOOP (peer_list, peer, nn)
+    {
+      if (htonl (peer->addr.s_addr) > htonl (addr->s_addr))
+	return peer;
+    }
+  return NULL;
+}
+
+/* RIP peer is timeout. */
+int
+rip_peer_timeout (struct thread *t)
+{
+  struct rip_peer *peer;
+
+  peer = THREAD_ARG (t);
+  listnode_delete (peer_list, peer);
+  rip_peer_free (peer);
+
+  return 0;
+}
+
+/* Get RIP peer.  At the same time update timeout thread. */
+struct rip_peer *
+rip_peer_get (struct in_addr *addr)
+{
+  struct rip_peer *peer;
+
+  peer = rip_peer_lookup (addr);
+
+  if (peer)
+    {
+      if (peer->t_timeout)
+	thread_cancel (peer->t_timeout);
+    }
+  else
+    {
+      peer = rip_peer_new ();
+      peer->addr = *addr;
+      listnode_add_sort (peer_list, peer);
+    }
+
+  /* Update timeout thread. */
+  peer->t_timeout = thread_add_timer (master, rip_peer_timeout, peer,
+				      RIP_PEER_TIMER_DEFAULT);
+
+  /* Last update time set. */
+  time (&peer->uptime);
+  
+  return peer;
+}
+
+void
+rip_peer_update (struct sockaddr_in *from, u_char version)
+{
+  struct rip_peer *peer;
+  peer = rip_peer_get (&from->sin_addr);
+  peer->version = version;
+}
+
+void
+rip_peer_bad_route (struct sockaddr_in *from)
+{
+  struct rip_peer *peer;
+  peer = rip_peer_get (&from->sin_addr);
+  peer->recv_badroutes++;
+}
+
+void
+rip_peer_bad_packet (struct sockaddr_in *from)
+{
+  struct rip_peer *peer;
+  peer = rip_peer_get (&from->sin_addr);
+  peer->recv_badpackets++;
+}
+
+/* Display peer uptime. */
+char *
+rip_peer_uptime (struct rip_peer *peer, char *buf, size_t len)
+{
+  time_t uptime;
+  struct tm *tm;
+
+  /* If there is no connection has been done before print `never'. */
+  if (peer->uptime == 0)
+    {
+      snprintf (buf, len, "never   ");
+      return buf;
+    }
+
+  /* Get current time. */
+  uptime = time (NULL);
+  uptime -= peer->uptime;
+  tm = gmtime (&uptime);
+
+  /* Making formatted timer strings. */
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+
+  if (uptime < ONE_DAY_SECOND)
+    snprintf (buf, len, "%02d:%02d:%02d", 
+	      tm->tm_hour, tm->tm_min, tm->tm_sec);
+  else if (uptime < ONE_WEEK_SECOND)
+    snprintf (buf, len, "%dd%02dh%02dm", 
+	      tm->tm_yday, tm->tm_hour, tm->tm_min);
+  else
+    snprintf (buf, len, "%02dw%dd%02dh", 
+	      tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+  return buf;
+}
+
+void
+rip_peer_display (struct vty *vty)
+{
+  struct rip_peer *peer;
+  struct listnode *nn;
+#define RIP_UPTIME_LEN 25
+  char timebuf[RIP_UPTIME_LEN];
+
+  LIST_LOOP (peer_list, peer, nn)
+    {
+      vty_out (vty, "    %-16s %9d %9d %9d   %s%s", inet_ntoa (peer->addr),
+	       peer->recv_badpackets, peer->recv_badroutes,
+	       ZEBRA_RIP_DISTANCE_DEFAULT,
+	       rip_peer_uptime (peer, timebuf, RIP_UPTIME_LEN),
+	       VTY_NEWLINE);
+    }
+}
+
+int
+rip_peer_list_cmp (struct rip_peer *p1, struct rip_peer *p2)
+{
+  return htonl (p1->addr.s_addr) > htonl (p2->addr.s_addr);
+}
+
+void
+rip_peer_init ()
+{
+  peer_list = list_new ();
+  peer_list->cmp = (int (*)(void *, void *)) rip_peer_list_cmp;
+}
diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c
new file mode 100644
index 0000000..791de41
--- /dev/null
+++ b/ripd/rip_routemap.c
@@ -0,0 +1,898 @@
+/* RIPv2 routemap.
+ * 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>
+
+#include "memory.h"
+#include "prefix.h"
+#include "routemap.h"
+#include "command.h"
+#include "filter.h"
+#include "log.h"
+#include "sockunion.h"		/* for inet_aton () */
+#include "plist.h"
+
+#include "ripd/ripd.h"
+
+/* Add rip route map rule. */
+int
+rip_route_match_add (struct vty *vty, struct route_map_index *index,
+		     char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_add_match (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+	{
+	case RMAP_RULE_MISSING:
+	  vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	  break;
+	case RMAP_COMPILE_ERROR:
+	  vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	  break;
+	}
+    }
+  return CMD_SUCCESS;
+}
+
+/* Delete rip route map rule. */
+int
+rip_route_match_delete (struct vty *vty, struct route_map_index *index,
+			char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_delete_match (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+	{
+	case RMAP_RULE_MISSING:
+	  vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	  break;
+	case RMAP_COMPILE_ERROR:
+	  vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	  break;
+	}
+    }
+  return CMD_SUCCESS;
+}
+
+/* Add rip route map rule. */
+int
+rip_route_set_add (struct vty *vty, struct route_map_index *index,
+		   char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_add_set (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+	{
+	case RMAP_RULE_MISSING:
+	  vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	  break;
+	case RMAP_COMPILE_ERROR:
+	  vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	  break;
+	}
+    }
+  return CMD_SUCCESS;
+}
+
+/* Delete rip route map rule. */
+int
+rip_route_set_delete (struct vty *vty, struct route_map_index *index,
+		      char *command, char *arg)
+{
+  int ret;
+
+  ret = route_map_delete_set (index, command, arg);
+  if (ret)
+    {
+      switch (ret)
+	{
+	case RMAP_RULE_MISSING:
+	  vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	  break;
+	case RMAP_COMPILE_ERROR:
+	  vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	  break;
+	}
+    }
+  return CMD_SUCCESS;
+}
+
+/* Hook function for updating route_map assignment. */
+void
+rip_route_map_update ()
+{
+  int i;
+
+  if (rip) 
+    {
+      for (i = 0; i < ZEBRA_ROUTE_MAX; i++) 
+	{
+	  if (rip->route_map[i].name)
+	    rip->route_map[i].map = 
+	      route_map_lookup_by_name (rip->route_map[i].name);
+	}
+    }
+}
+
+/* `match metric METRIC' */
+/* Match function return 1 if match is success else return zero. */
+route_map_result_t
+route_match_metric (void *rule, struct prefix *prefix, 
+		    route_map_object_t type, void *object)
+{
+  u_int32_t *metric;
+  struct rip_info *rinfo;
+
+  if (type == RMAP_RIP)
+    {
+      metric = rule;
+      rinfo = object;
+    
+      if (rinfo->metric == *metric)
+	return RMAP_MATCH;
+      else
+	return RMAP_NOMATCH;
+    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `match metric' match statement. `arg' is METRIC value */
+void *
+route_match_metric_compile (char *arg)
+{
+  u_int32_t *metric;
+
+  metric = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+  *metric = atoi (arg);
+
+  if(*metric > 0)
+    return metric;
+
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, metric);
+  return NULL;
+}
+
+/* Free route map's compiled `match metric' value. */
+void
+route_match_metric_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for metric matching. */
+struct route_map_rule_cmd route_match_metric_cmd =
+{
+  "metric",
+  route_match_metric,
+  route_match_metric_compile,
+  route_match_metric_free
+};
+
+/* `match interface IFNAME' */
+/* Match function return 1 if match is success else return zero. */
+route_map_result_t
+route_match_interface (void *rule, struct prefix *prefix,
+		       route_map_object_t type, void *object)
+{
+  struct rip_info *rinfo;
+  struct interface *ifp;
+  char *ifname;
+
+  if (type == RMAP_RIP)
+    {
+      ifname = rule;
+      ifp = if_lookup_by_name(ifname);
+
+      if (!ifp)
+	return RMAP_NOMATCH;
+
+      rinfo = object;
+
+      if (rinfo->ifindex_out == ifp->ifindex)
+	return RMAP_MATCH;
+      else
+	return RMAP_NOMATCH;
+    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `match interface' match statement. `arg' is IFNAME value */
+/* XXX I don`t know if I need to check does interface exist? */
+void *
+route_match_interface_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `match interface' value. */
+void
+route_match_interface_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for interface matching. */
+struct route_map_rule_cmd route_match_interface_cmd =
+{
+  "interface",
+  route_match_interface,
+  route_match_interface_compile,
+  route_match_interface_free
+};
+
+/* `match ip next-hop IP_ACCESS_LIST' */
+
+/* Match function return 1 if match is success else return zero. */
+route_map_result_t
+route_match_ip_next_hop (void *rule, struct prefix *prefix,
+			route_map_object_t type, void *object)
+{
+  struct access_list *alist;
+  struct rip_info *rinfo;
+  struct prefix_ipv4 p;
+
+  if (type == RMAP_RIP)
+    {
+      rinfo = object;
+      p.family = AF_INET;
+      p.prefix = rinfo->nexthop;
+      p.prefixlen = IPV4_MAX_BITLEN;
+
+      alist = access_list_lookup (AFI_IP, (char *) rule);
+      if (alist == NULL)
+	return RMAP_NOMATCH;
+
+      return (access_list_apply (alist, &p) == FILTER_DENY ?
+	      RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `ip next-hop' match statement.  `arg' should be
+   access-list name. */
+void *
+route_match_ip_next_hop_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `. */
+void
+route_match_ip_next_hop_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip next-hop matching. */
+struct route_map_rule_cmd route_match_ip_next_hop_cmd =
+{
+  "ip next-hop",
+  route_match_ip_next_hop,
+  route_match_ip_next_hop_compile,
+  route_match_ip_next_hop_free
+};
+
+/* `match ip next-hop prefix-list PREFIX_LIST' */
+
+route_map_result_t
+route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix,
+                                    route_map_object_t type, void *object)
+{
+  struct prefix_list *plist;
+  struct rip_info *rinfo;
+  struct prefix_ipv4 p;
+
+  if (type == RMAP_RIP)
+    {
+      rinfo = object;
+      p.family = AF_INET;
+      p.prefix = rinfo->nexthop;
+      p.prefixlen = IPV4_MAX_BITLEN;
+
+      plist = prefix_list_lookup (AFI_IP, (char *) rule);
+      if (plist == NULL)
+        return RMAP_NOMATCH;
+
+      return (prefix_list_apply (plist, &p) == PREFIX_DENY ?
+              RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+void *
+route_match_ip_next_hop_prefix_list_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+route_match_ip_next_hop_prefix_list_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd =
+{
+  "ip next-hop prefix-list",
+  route_match_ip_next_hop_prefix_list,
+  route_match_ip_next_hop_prefix_list_compile,
+  route_match_ip_next_hop_prefix_list_free
+};
+
+/* `match ip address IP_ACCESS_LIST' */
+
+/* Match function should return 1 if match is success else return
+   zero. */
+route_map_result_t
+route_match_ip_address (void *rule, struct prefix *prefix, 
+			route_map_object_t type, void *object)
+{
+  struct access_list *alist;
+
+  if (type == RMAP_RIP)
+    {
+      alist = access_list_lookup (AFI_IP, (char *) rule);
+      if (alist == NULL)
+	return RMAP_NOMATCH;
+    
+      return (access_list_apply (alist, prefix) == FILTER_DENY ?
+	      RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+/* Route map `ip address' match statement.  `arg' should be
+   access-list name. */
+void *
+route_match_ip_address_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `ip address' value. */
+void
+route_match_ip_address_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip address matching. */
+struct route_map_rule_cmd route_match_ip_address_cmd =
+{
+  "ip address",
+  route_match_ip_address,
+  route_match_ip_address_compile,
+  route_match_ip_address_free
+};
+
+/* `match ip address prefix-list PREFIX_LIST' */
+
+route_map_result_t
+route_match_ip_address_prefix_list (void *rule, struct prefix *prefix, 
+				    route_map_object_t type, void *object)
+{
+  struct prefix_list *plist;
+
+  if (type == RMAP_RIP)
+    {
+      plist = prefix_list_lookup (AFI_IP, (char *) rule);
+      if (plist == NULL)
+	return RMAP_NOMATCH;
+    
+      return (prefix_list_apply (plist, prefix) == PREFIX_DENY ?
+	      RMAP_NOMATCH : RMAP_MATCH);
+    }
+  return RMAP_NOMATCH;
+}
+
+void *
+route_match_ip_address_prefix_list_compile (char *arg)
+{
+  return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+route_match_ip_address_prefix_list_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd =
+{
+  "ip address prefix-list",
+  route_match_ip_address_prefix_list,
+  route_match_ip_address_prefix_list_compile,
+  route_match_ip_address_prefix_list_free
+};
+
+/* `set metric METRIC' */
+
+/* Set metric to attribute. */
+route_map_result_t
+route_set_metric (void *rule, struct prefix *prefix, 
+		  route_map_object_t type, void *object)
+{
+  u_int32_t *metric;
+  struct rip_info *rinfo;
+
+  if (type == RMAP_RIP)
+    {
+      /* Fetch routemap's rule information. */
+      metric = rule;
+      rinfo = object;
+    
+      /* Set metric out value. */
+      rinfo->metric_out = *metric;
+      rinfo->metric_set = 1;
+    }
+  return RMAP_OKAY;
+}
+
+/* set metric compilation. */
+void *
+route_set_metric_compile (char *arg)
+{
+  u_int32_t *metric;
+
+  metric = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+  *metric = atoi (arg);
+
+  return metric;
+
+#if 0
+  /* To make it consistent to other daemon, metric check is commented
+     out.*/
+  if (*metric >= 0 && *metric <= 16)
+    return metric;
+
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, metric);
+  return NULL;
+#endif /* 0 */
+}
+
+/* Free route map's compiled `set metric' value. */
+void
+route_set_metric_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set metric rule structure. */
+struct route_map_rule_cmd route_set_metric_cmd = 
+{
+  "metric",
+  route_set_metric,
+  route_set_metric_compile,
+  route_set_metric_free,
+};
+
+/* `set ip next-hop IP_ADDRESS' */
+
+/* Set nexthop to object.  ojbect must be pointer to struct attr. */
+route_map_result_t
+route_set_ip_nexthop (void *rule, struct prefix *prefix, 
+		      route_map_object_t type, void *object)
+{
+  struct in_addr *address;
+  struct rip_info *rinfo;
+
+  if(type == RMAP_RIP)
+    {
+      /* Fetch routemap's rule information. */
+      address = rule;
+      rinfo = object;
+    
+      /* Set next hop value. */ 
+      rinfo->nexthop_out = *address;
+    }
+
+  return RMAP_OKAY;
+}
+
+/* Route map `ip nexthop' compile function.  Given string is converted
+   to struct in_addr structure. */
+void *
+route_set_ip_nexthop_compile (char *arg)
+{
+  int ret;
+  struct in_addr *address;
+
+  address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr));
+
+  ret = inet_aton (arg, address);
+
+  if (ret == 0)
+    {
+      XFREE (MTYPE_ROUTE_MAP_COMPILED, address);
+      return NULL;
+    }
+
+  return address;
+}
+
+/* Free route map's compiled `ip nexthop' value. */
+void
+route_set_ip_nexthop_free (void *rule)
+{
+  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip nexthop set. */
+struct route_map_rule_cmd route_set_ip_nexthop_cmd =
+{
+  "ip next-hop",
+  route_set_ip_nexthop,
+  route_set_ip_nexthop_compile,
+  route_set_ip_nexthop_free
+};
+
+#define MATCH_STR "Match values from routing table\n"
+#define SET_STR "Set values in destination routing protocol\n"
+
+DEFUN (match_metric, 
+       match_metric_cmd,
+       "match metric <0-4294967295>",
+       MATCH_STR
+       "Match metric of route\n"
+       "Metric value\n")
+{
+  return rip_route_match_add (vty, vty->index, "metric", argv[0]);
+}
+
+DEFUN (no_match_metric,
+       no_match_metric_cmd,
+       "no match metric",
+       NO_STR
+       MATCH_STR
+       "Match metric of route\n")
+{
+  if (argc == 0)
+    return rip_route_match_delete (vty, vty->index, "metric", NULL);
+
+  return rip_route_match_delete (vty, vty->index, "metric", argv[0]);
+}
+
+ALIAS (no_match_metric,
+       no_match_metric_val_cmd,
+       "no match metric <0-4294967295>",
+       NO_STR
+       MATCH_STR
+       "Match metric of route\n"
+       "Metric value\n")
+
+DEFUN (match_interface,
+       match_interface_cmd,
+       "match interface WORD",
+       MATCH_STR
+       "Match first hop interface of route\n"
+       "Interface name\n")
+{
+  return rip_route_match_add (vty, vty->index, "interface", argv[0]);
+}
+
+DEFUN (no_match_interface,
+       no_match_interface_cmd,
+       "no match interface",
+       NO_STR
+       MATCH_STR
+       "Match first hop interface of route\n")
+{
+  if (argc == 0)
+    return rip_route_match_delete (vty, vty->index, "interface", NULL);
+
+  return rip_route_match_delete (vty, vty->index, "interface", argv[0]);
+}
+
+ALIAS (no_match_interface,
+       no_match_interface_val_cmd,
+       "no match interface WORD",
+       NO_STR
+       MATCH_STR
+       "Match first hop interface of route\n"
+       "Interface name\n")
+
+DEFUN (match_ip_next_hop,
+       match_ip_next_hop_cmd,
+       "match ip next-hop WORD",
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "IP access-list name\n")
+{
+  return rip_route_match_add (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+DEFUN (no_match_ip_next_hop,
+       no_match_ip_next_hop_cmd,
+       "no match ip next-hop",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n")
+{
+  if (argc == 0)
+    return rip_route_match_delete (vty, vty->index, "ip next-hop", NULL);
+
+  return rip_route_match_delete (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+ALIAS (no_match_ip_next_hop,
+       no_match_ip_next_hop_val_cmd,
+       "no match ip next-hop WORD",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "IP access-list name\n")
+
+DEFUN (match_ip_next_hop_prefix_list,
+       match_ip_next_hop_prefix_list_cmd,
+       "match ip next-hop prefix-list WORD",
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+{
+  return rip_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+}
+
+DEFUN (no_match_ip_next_hop_prefix_list,
+       no_match_ip_next_hop_prefix_list_cmd,
+       "no match ip next-hop prefix-list",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "Match entries of prefix-lists\n")
+{
+  if (argc == 0)
+    return rip_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL);
+
+  return rip_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+}
+
+ALIAS (no_match_ip_next_hop_prefix_list,
+       no_match_ip_next_hop_prefix_list_val_cmd,
+       "no match ip next-hop prefix-list WORD",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match next-hop address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+
+DEFUN (match_ip_address, 
+       match_ip_address_cmd,
+       "match ip address WORD",
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "IP access-list name\n")
+{
+  return rip_route_match_add (vty, vty->index, "ip address", argv[0]);
+}
+
+DEFUN (no_match_ip_address, 
+       no_match_ip_address_cmd,
+       "no match ip address",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n")
+{
+  if (argc == 0)
+    return rip_route_match_delete (vty, vty->index, "ip address", NULL);
+
+  return rip_route_match_delete (vty, vty->index, "ip address", argv[0]);
+}
+
+ALIAS (no_match_ip_address, 
+       no_match_ip_address_val_cmd,
+       "no match ip address WORD",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "IP access-list name\n")
+
+DEFUN (match_ip_address_prefix_list, 
+       match_ip_address_prefix_list_cmd,
+       "match ip address prefix-list WORD",
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+{
+  return rip_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]);
+}
+
+DEFUN (no_match_ip_address_prefix_list,
+       no_match_ip_address_prefix_list_cmd,
+       "no match ip address prefix-list",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n")
+{
+  if (argc == 0)
+    return rip_route_match_delete (vty, vty->index, "ip address prefix-list", NULL);
+
+  return rip_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]);
+}
+
+ALIAS (no_match_ip_address_prefix_list,
+       no_match_ip_address_prefix_list_val_cmd,
+       "no match ip address prefix-list WORD",
+       NO_STR
+       MATCH_STR
+       IP_STR
+       "Match address of route\n"
+       "Match entries of prefix-lists\n"
+       "IP prefix-list name\n")
+
+/* set functions */
+
+DEFUN (set_metric,
+       set_metric_cmd,
+       "set metric <0-4294967295>",
+       SET_STR
+       "Metric value for destination routing protocol\n"
+       "Metric value\n")
+{
+  return rip_route_set_add (vty, vty->index, "metric", argv[0]);
+}
+
+DEFUN (no_set_metric,
+       no_set_metric_cmd,
+       "no set metric",
+       NO_STR
+       SET_STR
+       "Metric value for destination routing protocol\n")
+{
+  if (argc == 0)
+    return rip_route_set_delete (vty, vty->index, "metric", NULL);
+
+  return rip_route_set_delete (vty, vty->index, "metric", argv[0]);
+}
+
+ALIAS (no_set_metric,
+       no_set_metric_val_cmd,
+       "no set metric <0-4294967295>",
+       NO_STR
+       SET_STR
+       "Metric value for destination routing protocol\n"
+       "Metric value\n")
+
+DEFUN (set_ip_nexthop,
+       set_ip_nexthop_cmd,
+       "set ip next-hop A.B.C.D",
+       SET_STR
+       IP_STR
+       "Next hop address\n"
+       "IP address of next hop\n")
+{
+  union sockunion su;
+  int ret;
+
+  ret = str2sockunion (argv[0], &su);
+  if (ret < 0)
+    {
+      vty_out (vty, "%% Malformed next-hop address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return rip_route_set_add (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+DEFUN (no_set_ip_nexthop,
+       no_set_ip_nexthop_cmd,
+       "no set ip next-hop",
+       NO_STR
+       SET_STR
+       IP_STR
+       "Next hop address\n")
+{
+  if (argc == 0)
+    return rip_route_set_delete (vty, vty->index, "ip next-hop", NULL);
+  
+  return rip_route_set_delete (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+ALIAS (no_set_ip_nexthop,
+       no_set_ip_nexthop_val_cmd,
+       "no set ip next-hop A.B.C.D",
+       NO_STR
+       SET_STR
+       IP_STR
+       "Next hop address\n"
+       "IP address of next hop\n")
+
+void
+rip_route_map_reset ()
+{
+  ;
+}
+
+/* Route-map init */
+void
+rip_route_map_init ()
+{
+  route_map_init ();
+  route_map_init_vty ();
+  route_map_add_hook (rip_route_map_update);
+  route_map_delete_hook (rip_route_map_update);
+
+  route_map_install_match (&route_match_metric_cmd);
+  route_map_install_match (&route_match_interface_cmd);
+  route_map_install_match (&route_match_ip_next_hop_cmd);
+  route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd);
+  route_map_install_match (&route_match_ip_address_cmd);
+  route_map_install_match (&route_match_ip_address_prefix_list_cmd);
+
+  route_map_install_set (&route_set_metric_cmd);
+  route_map_install_set (&route_set_ip_nexthop_cmd);
+
+  install_element (RMAP_NODE, &match_metric_cmd);
+  install_element (RMAP_NODE, &no_match_metric_cmd);
+  install_element (RMAP_NODE, &no_match_metric_val_cmd);
+  install_element (RMAP_NODE, &match_interface_cmd);
+  install_element (RMAP_NODE, &no_match_interface_cmd);
+  install_element (RMAP_NODE, &no_match_interface_val_cmd);
+  install_element (RMAP_NODE, &match_ip_next_hop_cmd);
+  install_element (RMAP_NODE, &no_match_ip_next_hop_cmd);
+  install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd);
+  install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
+  install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
+  install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd);
+  install_element (RMAP_NODE, &match_ip_address_cmd);
+  install_element (RMAP_NODE, &no_match_ip_address_cmd);
+  install_element (RMAP_NODE, &no_match_ip_address_val_cmd);
+  install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd);
+  install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
+  install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd);
+
+  install_element (RMAP_NODE, &set_metric_cmd);
+  install_element (RMAP_NODE, &no_set_metric_cmd);
+  install_element (RMAP_NODE, &no_set_metric_val_cmd);
+  install_element (RMAP_NODE, &set_ip_nexthop_cmd);
+  install_element (RMAP_NODE, &no_set_ip_nexthop_cmd);
+  install_element (RMAP_NODE, &no_set_ip_nexthop_val_cmd);
+}
diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c
new file mode 100644
index 0000000..dc2b621
--- /dev/null
+++ b/ripd/rip_snmp.c
@@ -0,0 +1,577 @@
+/* RIP 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 "if.h"
+#include "log.h"
+#include "prefix.h"
+#include "command.h"
+#include "table.h"
+#include "smux.h"
+
+#include "ripd/ripd.h"
+
+/* RIPv2-MIB. */
+#define RIPV2MIB 1,3,6,1,2,1,23
+
+/* Zebra enterprise RIP MIB.  This variable is used for register
+   RIPv2-MIB to SNMP agent under SMUX protocol.  */
+#define RIPDOID 1,3,6,1,4,1,3317,1,2,3
+
+/* RIPv2-MIB rip2Globals values. */
+#define RIP2GLOBALROUTECHANGES  1
+#define RIP2GLOBALQUERIES       2
+
+/* RIPv2-MIB rip2IfStatEntry. */
+#define RIP2IFSTATENTRY         1
+
+/* RIPv2-MIB rip2IfStatTable. */
+#define RIP2IFSTATADDRESS       1
+#define RIP2IFSTATRCVBADPACKETS 2
+#define RIP2IFSTATRCVBADROUTES  3
+#define RIP2IFSTATSENTUPDATES   4
+#define RIP2IFSTATSTATUS        5
+
+/* RIPv2-MIB rip2IfConfTable. */
+#define RIP2IFCONFADDRESS       1
+#define RIP2IFCONFDOMAIN        2
+#define RIP2IFCONFAUTHTYPE      3
+#define RIP2IFCONFAUTHKEY       4
+#define RIP2IFCONFSEND          5
+#define RIP2IFCONFRECEIVE       6
+#define RIP2IFCONFDEFAULTMETRIC 7
+#define RIP2IFCONFSTATUS        8
+#define RIP2IFCONFSRCADDRESS    9
+
+/* RIPv2-MIB rip2PeerTable. */
+#define RIP2PEERADDRESS         1
+#define RIP2PEERDOMAIN          2
+#define RIP2PEERLASTUPDATE      3
+#define RIP2PEERVERSION         4
+#define RIP2PEERRCVBADPACKETS   5
+#define RIP2PEERRCVBADROUTES    6
+
+/* SNMP value hack. */
+#define COUNTER     ASN_COUNTER
+#define INTEGER     ASN_INTEGER
+#define TIMETICKS   ASN_TIMETICKS
+#define IPADDRESS   ASN_IPADDRESS
+#define STRING      ASN_OCTET_STR
+
+/* Define SNMP local variables. */
+SNMP_LOCAL_VARIABLES
+
+/* RIP-MIB instances. */
+oid rip_oid [] = { RIPV2MIB };
+oid ripd_oid [] = { RIPDOID };
+
+/* Interface cache table sorted by interface's address. */
+struct route_table *rip_ifaddr_table;
+
+/* Hook functions. */
+static u_char *rip2Globals ();
+static u_char *rip2IfStatEntry ();
+static u_char *rip2IfConfAddress ();
+static u_char *rip2PeerTable ();
+
+struct variable rip_variables[] = 
+{
+  /* RIP Global Counters. */
+  {RIP2GLOBALROUTECHANGES,    COUNTER, RONLY, rip2Globals,
+   2, {1, 1}},
+  {RIP2GLOBALQUERIES,         COUNTER, RONLY, rip2Globals,
+   2, {1, 2}},
+  /* RIP Interface Tables. */
+  {RIP2IFSTATADDRESS,         IPADDRESS, RONLY, rip2IfStatEntry,
+   3, {2, 1, 1}},
+  {RIP2IFSTATRCVBADPACKETS,   COUNTER, RONLY, rip2IfStatEntry,
+   3, {2, 1, 2}},
+  {RIP2IFSTATRCVBADROUTES,    COUNTER, RONLY, rip2IfStatEntry,
+   3, {2, 1, 3}},
+  {RIP2IFSTATSENTUPDATES,     COUNTER, RONLY, rip2IfStatEntry,
+   3, {2, 1, 4}},
+  {RIP2IFSTATSTATUS,          COUNTER, RWRITE, rip2IfStatEntry,
+   3, {2, 1, 5}},
+  {RIP2IFCONFADDRESS,         IPADDRESS, RONLY, rip2IfConfAddress,
+   /* RIP Interface Configuration Table. */
+   3, {3, 1, 1}},
+  {RIP2IFCONFDOMAIN,          STRING, RONLY, rip2IfConfAddress,
+   3, {3, 1, 2}},
+  {RIP2IFCONFAUTHTYPE,        COUNTER, RONLY, rip2IfConfAddress,
+   3, {3, 1, 3}},
+  {RIP2IFCONFAUTHKEY,         STRING, RONLY, rip2IfConfAddress,
+   3, {3, 1, 4}},
+  {RIP2IFCONFSEND,            COUNTER, RONLY, rip2IfConfAddress,
+   3, {3, 1, 5}},
+  {RIP2IFCONFRECEIVE,         COUNTER, RONLY, rip2IfConfAddress,
+   3, {3, 1, 6}},
+  {RIP2IFCONFDEFAULTMETRIC,   COUNTER, RONLY, rip2IfConfAddress,
+   3, {3, 1, 7}},
+  {RIP2IFCONFSTATUS,          COUNTER, RONLY, rip2IfConfAddress,
+   3, {3, 1, 8}},
+  {RIP2IFCONFSRCADDRESS,      IPADDRESS, RONLY, rip2IfConfAddress,
+   3, {3, 1, 9}},
+  {RIP2PEERADDRESS,           IPADDRESS, RONLY, rip2PeerTable,
+   /* RIP Peer Table. */
+   3, {4, 1, 1}},
+  {RIP2PEERDOMAIN,            INTEGER, RONLY, rip2PeerTable,
+   3, {4, 1, 2}},
+  {RIP2PEERLASTUPDATE,        TIMETICKS, RONLY, rip2PeerTable,
+   3, {4, 1, 3}},
+  {RIP2PEERVERSION,           INTEGER, RONLY, rip2PeerTable,
+   3, {4, 1, 4}},
+  {RIP2PEERRCVBADPACKETS,     COUNTER, RONLY, rip2PeerTable,
+   3, {4, 1, 5}},
+  {RIP2PEERRCVBADROUTES,      COUNTER, RONLY, rip2PeerTable,
+   3, {4, 1, 6}}
+};
+
+static u_char *
+rip2Globals (struct variable *v, oid name[], size_t *length,
+	     int exact, size_t *var_len, WriteMethod **write_method)
+{
+  if (smux_header_generic(v, name, length, exact, var_len, write_method)
+      == MATCH_FAILED)
+    return NULL;
+
+  /* Retrun global counter. */
+  switch (v->magic)
+    {
+    case RIP2GLOBALROUTECHANGES:
+      return SNMP_INTEGER (rip_global_route_changes);
+      break;
+    case RIP2GLOBALQUERIES:
+      return SNMP_INTEGER (rip_global_queries);
+      break;
+    default:
+      return NULL;
+      break;
+    }
+  return NULL;
+}
+
+void
+rip_ifaddr_add (struct interface *ifp, struct connected *ifc)
+{
+  struct prefix *p;
+  struct route_node *rn;
+
+  p = ifc->address;
+
+  if (p->family != AF_INET)
+    return;
+
+  rn = route_node_get (rip_ifaddr_table, p);
+  rn->info = ifp;
+}
+
+void
+rip_ifaddr_delete (struct interface *ifp, struct connected *ifc)
+{
+  struct prefix *p;
+  struct route_node *rn;
+  struct interface *i;
+
+  p = ifc->address;
+
+  if (p->family != AF_INET)
+    return;
+
+  rn = route_node_lookup (rip_ifaddr_table, p);
+  if (! rn)
+    return;
+  i = rn->info;
+  if (rn && !strncmp(i->name,ifp->name,INTERFACE_NAMSIZ))
+    {
+      rn->info = NULL;
+      route_unlock_node (rn);
+      route_unlock_node (rn);
+    }
+}
+
+struct interface *
+rip_ifaddr_lookup_next (struct in_addr *addr)
+{
+  struct prefix_ipv4 p;
+  struct route_node *rn;
+  struct interface *ifp;
+
+  p.family = AF_INET;
+  p.prefixlen = IPV4_MAX_BITLEN;
+  p.prefix = *addr;
+
+  rn = route_node_get (rip_ifaddr_table, (struct prefix *) &p);
+
+  for (rn = route_next (rn); rn; rn = route_next (rn))
+    if (rn->info)
+      break;
+
+  if (rn && rn->info)
+    {
+      ifp = rn->info;
+      *addr = rn->p.u.prefix4;
+      route_unlock_node (rn);
+      return ifp;
+    }
+  return NULL;
+}
+
+static struct interface *
+rip2IfLookup (struct variable *v, oid name[], size_t *length, 
+	      struct in_addr *addr, int exact)
+{
+  int len;
+  struct interface *ifp;
+  
+  if (exact)
+    {
+      /* Check the length. */
+      if (*length - v->namelen != sizeof (struct in_addr))
+	return NULL;
+
+      oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr);
+
+      return if_lookup_exact_address (*addr);
+    }
+  else
+    {
+      len = *length - v->namelen;
+      if (len > 4) len = 4;
+
+      oid2in_addr (name + v->namelen, len, addr);
+
+      ifp = rip_ifaddr_lookup_next (addr);
+
+      if (ifp == NULL)
+	return NULL;
+
+      oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr));
+
+      *length = v->namelen + sizeof (struct in_addr);
+
+      return ifp;
+    }
+  return NULL;
+}
+
+static struct rip_peer *
+rip2PeerLookup (struct variable *v, oid name[], size_t *length, 
+		struct in_addr *addr, int exact)
+{
+  int len;
+  struct rip_peer *peer;
+  
+  if (exact)
+    {
+      /* Check the length. */
+      if (*length - v->namelen != sizeof (struct in_addr) + 1)
+	return NULL;
+
+      oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr);
+
+      peer = rip_peer_lookup (addr);
+
+      if (peer->domain == name[v->namelen + sizeof (struct in_addr)])
+	return peer;
+
+      return NULL;
+    }
+  else
+    {
+      len = *length - v->namelen;
+      if (len > 4) len = 4;
+
+      oid2in_addr (name + v->namelen, len, addr);
+
+      len = *length - v->namelen;
+      peer = rip_peer_lookup (addr);
+      if (peer)
+	{
+	  if ((len < sizeof (struct in_addr) + 1) ||
+	      (peer->domain > name[v->namelen + sizeof (struct in_addr)]))
+	    {
+	      oid_copy_addr (name + v->namelen, &peer->addr,
+			     sizeof (struct in_addr));
+	      name[v->namelen + sizeof (struct in_addr)] = peer->domain;
+	      *length = sizeof (struct in_addr) + v->namelen + 1;
+	      return peer;
+	    }
+        } 
+      peer = rip_peer_lookup_next (addr);
+
+      if (! peer)
+	return NULL;
+
+      oid_copy_addr (name + v->namelen, &peer->addr,
+		     sizeof (struct in_addr));
+      name[v->namelen + sizeof (struct in_addr)] = peer->domain;
+      *length = sizeof (struct in_addr) + v->namelen + 1;
+
+      return peer;
+    }
+  return NULL;
+}
+
+static u_char *
+rip2IfStatEntry (struct variable *v, oid name[], size_t *length,
+	         int exact, size_t *var_len, WriteMethod **write_method)
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+  static struct in_addr addr;
+  static long valid = SNMP_VALID;
+
+  memset (&addr, 0, sizeof (struct in_addr));
+  
+  /* Lookup interface. */
+  ifp = rip2IfLookup (v, name, length, &addr, exact);
+  if (! ifp)
+    return NULL;
+
+  /* Fetch rip_interface information. */
+  ri = ifp->info;
+
+  switch (v->magic)
+    {
+    case RIP2IFSTATADDRESS:
+      return SNMP_IPADDRESS (addr);
+      break;
+    case RIP2IFSTATRCVBADPACKETS:
+      *var_len = sizeof (long);
+      return (u_char *) &ri->recv_badpackets;
+
+    case RIP2IFSTATRCVBADROUTES:
+      *var_len = sizeof (long);
+      return (u_char *) &ri->recv_badroutes;
+
+    case RIP2IFSTATSENTUPDATES:
+      *var_len = sizeof (long);
+      return (u_char *) &ri->sent_updates;
+
+    case RIP2IFSTATSTATUS:
+      *var_len = sizeof (long);
+      v->type = ASN_INTEGER;
+      return (u_char *) &valid;
+
+    default:
+      return NULL;
+
+    }
+  return NULL;
+}
+
+static long
+rip2IfConfSend (struct rip_interface *ri)
+{
+#define doNotSend       1
+#define ripVersion1     2
+#define rip1Compatible  3
+#define ripVersion2     4
+#define ripV1Demand     5
+#define ripV2Demand     6
+
+  if (! ri->running)
+    return doNotSend;
+    
+  if (ri->ri_send & RIPv2)
+    return ripVersion2;
+  else if (ri->ri_send & RIPv1)
+    return ripVersion1;
+  else if (rip)
+    {
+      if (rip->version == RIPv2)
+	return ripVersion2;
+      else if (rip->version == RIPv1)
+	return ripVersion1;
+    }
+  return doNotSend;
+}
+
+static long
+rip2IfConfReceive (struct rip_interface *ri)
+{
+#define rip1            1
+#define rip2            2
+#define rip1OrRip2      3
+#define doNotReceive    4
+
+  if (! ri->running)
+    return doNotReceive;
+
+  if (ri->ri_receive == RI_RIP_VERSION_1_AND_2)
+    return rip1OrRip2;
+  else if (ri->ri_receive & RIPv2)
+    return ripVersion2;
+  else if (ri->ri_receive & RIPv1)
+    return ripVersion1;
+  else
+    return doNotReceive;
+}
+
+static u_char *
+rip2IfConfAddress (struct variable *v, oid name[], size_t *length,
+	           int exact, size_t *val_len, WriteMethod **write_method)
+{
+  static struct in_addr addr;
+  static long valid = SNMP_INVALID;
+  static long domain = 0;
+  static long config = 0;
+  static u_int auth = 0;
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  memset (&addr, 0, sizeof (struct in_addr));
+  
+  /* Lookup interface. */
+  ifp = rip2IfLookup (v, name, length, &addr, exact);
+  if (! ifp)
+    return NULL;
+
+  /* Fetch rip_interface information. */
+  ri = ifp->info;
+
+  switch (v->magic)
+    {
+    case RIP2IFCONFADDRESS:
+      *val_len = sizeof (struct in_addr);
+      return (u_char *) &addr;
+
+    case RIP2IFCONFDOMAIN:
+      *val_len = 2;
+      return (u_char *) &domain;
+
+    case RIP2IFCONFAUTHTYPE:
+      auth = ri->auth_type;
+      *val_len = sizeof (long);
+      v->type = ASN_INTEGER;
+      return (u_char *)&auth;
+
+    case RIP2IFCONFAUTHKEY:
+      *val_len = 0;
+      return (u_char *) &domain;
+    case RIP2IFCONFSEND:
+      config = rip2IfConfSend (ri);
+      *val_len = sizeof (long);
+      v->type = ASN_INTEGER;
+      return (u_char *) &config;
+    case RIP2IFCONFRECEIVE:
+      config = rip2IfConfReceive (ri);
+      *val_len = sizeof (long);
+      v->type = ASN_INTEGER;
+      return (u_char *) &config;
+
+    case RIP2IFCONFDEFAULTMETRIC:
+      *val_len = sizeof (long);
+      v->type = ASN_INTEGER;
+      return (u_char *) &ifp->metric;
+    case RIP2IFCONFSTATUS:
+      *val_len = sizeof (long);
+      v->type = ASN_INTEGER;
+      return (u_char *) &valid;
+    case RIP2IFCONFSRCADDRESS:
+      *val_len = sizeof (struct in_addr);
+      return (u_char *) &addr;
+
+    default:
+      return NULL;
+
+    }
+  return NULL;
+}
+
+static u_char *
+rip2PeerTable (struct variable *v, oid name[], size_t *length,
+	       int exact, size_t *val_len, WriteMethod **write_method)
+{
+  static struct in_addr addr;
+  static int version;
+  /* static time_t uptime; */
+
+  struct rip_peer *peer;
+
+  memset (&addr, 0, sizeof (struct in_addr));
+  
+  /* Lookup interface. */
+  peer = rip2PeerLookup (v, name, length, &addr, exact);
+  if (! peer)
+    return NULL;
+
+  switch (v->magic)
+    {
+    case RIP2PEERADDRESS:
+      *val_len = sizeof (struct in_addr);
+      return (u_char *) &peer->addr;
+
+    case RIP2PEERDOMAIN:
+      *val_len = sizeof (int);
+      return (u_char *) &peer->domain;
+
+    case RIP2PEERLASTUPDATE:
+#if 0 
+      /* We don't know the SNMP agent startup time. We have two choices here:
+       * - assume ripd startup time equals SNMP agent startup time
+       * - don't support this variable, at all
+       * Currently, we do the latter...
+       */
+      *val_len = sizeof (time_t);
+      uptime = peer->uptime; /* now - snmp_agent_startup - peer->uptime */
+      return (u_char *) &uptime;
+#else
+      return (u_char *) NULL;
+#endif
+
+    case RIP2PEERVERSION:
+      *val_len = sizeof (int);
+      version = peer->version;
+      return (u_char *) &version;
+
+    case RIP2PEERRCVBADPACKETS:
+      *val_len = sizeof (int);
+      return (u_char *) &peer->recv_badpackets;
+
+    case RIP2PEERRCVBADROUTES:
+      *val_len = sizeof (int);
+      return (u_char *) &peer->recv_badroutes;
+
+    default:
+      return NULL;
+
+    }
+  return NULL;
+}
+
+/* Register RIPv2-MIB. */
+void
+rip_snmp_init ()
+{
+  rip_ifaddr_table = route_table_init ();
+
+  smux_init (ripd_oid, sizeof (ripd_oid) / sizeof (oid));
+  REGISTER_MIB("mibII/rip", rip_variables, variable, rip_oid);
+  smux_start ();
+}
+#endif /* HAVE_SNMP */
diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c
new file mode 100644
index 0000000..b6caf3b
--- /dev/null
+++ b/ripd/rip_zebra.c
@@ -0,0 +1,691 @@
+/* RIPd and zebra interface.
+ * Copyright (C) 1997, 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>
+
+#include "command.h"
+#include "prefix.h"
+#include "stream.h"
+#include "routemap.h"
+#include "zclient.h"
+#include "log.h"
+#include "ripd/ripd.h"
+#include "ripd/rip_debug.h"
+
+/* All information about zebra. */
+struct zclient *zclient = NULL;
+
+/* Callback prototypes for zebra client service. */
+int rip_interface_add (int, struct zclient *, zebra_size_t);
+int rip_interface_delete (int, struct zclient *, zebra_size_t);
+int rip_interface_address_add (int, struct zclient *, zebra_size_t);
+int rip_interface_address_delete (int, struct zclient *, zebra_size_t);
+int rip_interface_up (int, struct zclient *, zebra_size_t);
+int rip_interface_down (int, struct zclient *, zebra_size_t);
+
+/* RIPd to zebra command interface. */
+void
+rip_zebra_ipv4_add (struct prefix_ipv4 *p, struct in_addr *nexthop, 
+		    u_int32_t metric, u_char distance)
+{
+  struct zapi_ipv4 api;
+
+  if (zclient->redist[ZEBRA_ROUTE_RIP])
+    {
+      api.type = ZEBRA_ROUTE_RIP;
+      api.flags = 0;
+      api.message = 0;
+      SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+      api.nexthop_num = 1;
+      api.nexthop = &nexthop;
+      api.ifindex_num = 0;
+      SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
+      api.metric = metric;
+
+      if (distance && distance != ZEBRA_RIP_DISTANCE_DEFAULT)
+	{
+	  SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE);
+	  api.distance = distance;
+	}
+
+      zapi_ipv4_add (zclient, p, &api);
+
+      rip_global_route_changes++;
+    }
+}
+
+void
+rip_zebra_ipv4_delete (struct prefix_ipv4 *p, struct in_addr *nexthop, 
+		       u_int32_t metric)
+{
+  struct zapi_ipv4 api;
+
+  if (zclient->redist[ZEBRA_ROUTE_RIP])
+    {
+      api.type = ZEBRA_ROUTE_RIP;
+      api.flags = 0;
+      api.message = 0;
+      SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
+      api.nexthop_num = 1;
+      api.nexthop = &nexthop;
+      api.ifindex_num = 0;
+      SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
+      api.metric = metric;
+
+      zapi_ipv4_delete (zclient, p, &api);
+
+      rip_global_route_changes++;
+    }
+}
+
+/* Zebra route add and delete treatment. */
+int
+rip_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)
+{
+  struct stream *s;
+  struct zapi_ipv4 api;
+  unsigned long ifindex;
+  struct in_addr nexthop;
+  struct prefix_ipv4 p;
+  
+  s = zclient->ibuf;
+  ifindex = 0;
+  nexthop.s_addr = 0;
+
+  /* Type, flags, message. */
+  api.type = stream_getc (s);
+  api.flags = stream_getc (s);
+  api.message = stream_getc (s);
+
+  /* IPv4 prefix. */
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefixlen = stream_getc (s);
+  stream_get (&p.prefix, s, PSIZE (p.prefixlen));
+
+  /* Nexthop, ifindex, distance, metric. */
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
+    {
+      api.nexthop_num = stream_getc (s);
+      nexthop.s_addr = stream_get_ipv4 (s);
+    }
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
+    {
+      api.ifindex_num = stream_getc (s);
+      ifindex = stream_getl (s);
+    }
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
+    api.distance = stream_getc (s);
+  if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
+    api.metric = stream_getl (s);
+
+  /* Then fetch IPv4 prefixes. */
+  if (command == ZEBRA_IPV4_ROUTE_ADD)
+    rip_redistribute_add (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex, &nexthop);
+  else 
+    rip_redistribute_delete (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex);
+
+  return 0;
+}
+
+void
+rip_zclient_reset ()
+{
+  zclient_reset (zclient);
+}
+
+/* RIP route-map set for redistribution */
+void
+rip_routemap_set (int type, char *name)
+{
+  if (rip->route_map[type].name)
+    free(rip->route_map[type].name);
+
+  rip->route_map[type].name = strdup (name);
+  rip->route_map[type].map = route_map_lookup_by_name (name);
+}
+
+void
+rip_redistribute_metric_set (int type, int metric)
+{
+  rip->route_map[type].metric_config = 1;
+  rip->route_map[type].metric = metric;
+}
+
+int
+rip_metric_unset (int type,int metric)
+{
+#define DONT_CARE_METRIC_RIP 17  
+  if (metric != DONT_CARE_METRIC_RIP &&
+      rip->route_map[type].metric != metric)
+    return 1;
+  rip->route_map[type].metric_config = 0;
+  rip->route_map[type].metric = 0;
+  return 0;
+}
+
+/* RIP route-map unset for redistribution */
+int
+rip_routemap_unset (int type,char *name)
+{
+  if (! rip->route_map[type].name ||
+      (name != NULL && strcmp(rip->route_map[type].name,name)))
+    return 1;
+
+  free (rip->route_map[type].name);
+  rip->route_map[type].name = NULL;
+  rip->route_map[type].map = NULL;
+
+  return 0;
+}
+
+/* Redistribution types */
+static struct {
+  int type;
+  int str_min_len;
+  char *str;
+} redist_type[] = {
+  {ZEBRA_ROUTE_KERNEL,  1, "kernel"},
+  {ZEBRA_ROUTE_CONNECT, 1, "connected"},
+  {ZEBRA_ROUTE_STATIC,  1, "static"},
+  {ZEBRA_ROUTE_OSPF,    1, "ospf"},
+  {ZEBRA_ROUTE_BGP,     1, "bgp"},
+  {0, 0, NULL}
+};
+
+DEFUN (router_zebra,
+       router_zebra_cmd,
+       "router zebra",
+       "Enable a routing process\n"
+       "Make connection to zebra daemon\n")
+{
+  vty->node = ZEBRA_NODE;
+  zclient->enable = 1;
+  zclient_start (zclient);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_router_zebra,
+       no_router_zebra_cmd,
+       "no router zebra",
+       NO_STR
+       "Enable a routing process\n"
+       "Make connection to zebra daemon\n")
+{
+  zclient->enable = 0;
+  zclient_stop (zclient);
+  return CMD_SUCCESS;
+}
+
+int
+rip_redistribute_set (int type)
+{
+  if (zclient->redist[type])
+    return CMD_SUCCESS;
+
+  zclient->redist[type] = 1;
+
+  if (zclient->sock > 0)
+    zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient->sock, type);
+
+  return CMD_SUCCESS;
+}
+
+int
+rip_redistribute_unset (int type)
+{
+  if (! zclient->redist[type])
+    return CMD_SUCCESS;
+
+  zclient->redist[type] = 0;
+
+  if (zclient->sock > 0)
+    zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient->sock, type);
+
+  /* Remove the routes from RIP table. */
+  rip_redistribute_withdraw (type);
+
+  return CMD_SUCCESS;
+}
+
+int
+rip_redistribute_check (int type)
+{
+  return (zclient->redist[type]);
+}
+
+void
+rip_redistribute_clean ()
+{
+  int i;
+
+  for (i = 0; redist_type[i].str; i++)
+    {
+      if (zclient->redist[redist_type[i].type])
+	{
+	  if (zclient->sock > 0)
+	    zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE,
+				     zclient->sock, redist_type[i].type);
+
+	  zclient->redist[redist_type[i].type] = 0;
+
+	  /* Remove the routes from RIP table. */
+	  rip_redistribute_withdraw (redist_type[i].type);
+	}
+    }
+}
+
+DEFUN (rip_redistribute_rip,
+       rip_redistribute_rip_cmd,
+       "redistribute rip",
+       "Redistribute information from another routing protocol\n"
+       "Routing Information Protocol (RIP)\n")
+{
+  zclient->redist[ZEBRA_ROUTE_RIP] = 1;
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_redistribute_rip,
+       no_rip_redistribute_rip_cmd,
+       "no redistribute rip",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Routing Information Protocol (RIP)\n")
+{
+  zclient->redist[ZEBRA_ROUTE_RIP] = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (rip_redistribute_type,
+       rip_redistribute_type_cmd,
+       "redistribute (kernel|connected|static|ospf|bgp)",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n")
+{
+  int i;
+
+  for(i = 0; redist_type[i].str; i++) 
+    {
+      if (strncmp (redist_type[i].str, argv[0], 
+		   redist_type[i].str_min_len) == 0) 
+	{
+	  zclient_redistribute_set (zclient, redist_type[i].type);
+	  return CMD_SUCCESS;
+	}
+    }
+
+  vty_out(vty, "Invalid type %s%s", argv[0],
+	  VTY_NEWLINE);
+
+  return CMD_WARNING;
+}
+
+DEFUN (no_rip_redistribute_type,
+       no_rip_redistribute_type_cmd,
+       "no redistribute (kernel|connected|static|ospf|bgp)",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n")
+{
+  int i;
+
+  for (i = 0; redist_type[i].str; i++) 
+    {
+      if (strncmp(redist_type[i].str, argv[0], 
+		  redist_type[i].str_min_len) == 0) 
+	{
+	  rip_metric_unset (redist_type[i].type, DONT_CARE_METRIC_RIP);
+	  rip_routemap_unset (redist_type[i].type,NULL);
+	  rip_redistribute_unset (redist_type[i].type);
+	  return CMD_SUCCESS;
+        }
+    }
+
+  vty_out(vty, "Invalid type %s%s", argv[0],
+	  VTY_NEWLINE);
+
+  return CMD_WARNING;
+}
+
+DEFUN (rip_redistribute_type_routemap,
+       rip_redistribute_type_routemap_cmd,
+       "redistribute (kernel|connected|static|ospf|bgp) route-map WORD",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int i;
+
+  for (i = 0; redist_type[i].str; i++) {
+    if (strncmp(redist_type[i].str, argv[0],
+		redist_type[i].str_min_len) == 0) 
+      {
+	rip_routemap_set (redist_type[i].type, argv[1]);
+	zclient_redistribute_set (zclient, redist_type[i].type);
+	return CMD_SUCCESS;
+      }
+  }
+
+  vty_out(vty, "Invalid type %s%s", argv[0],
+	  VTY_NEWLINE);
+
+  return CMD_WARNING;
+}
+
+DEFUN (no_rip_redistribute_type_routemap,
+       no_rip_redistribute_type_routemap_cmd,
+       "no redistribute (kernel|connected|static|ospf|bgp) route-map WORD",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int i;
+
+  for (i = 0; redist_type[i].str; i++) 
+    {
+      if (strncmp(redist_type[i].str, argv[0], 
+		  redist_type[i].str_min_len) == 0) 
+	{
+	  if (rip_routemap_unset (redist_type[i].type,argv[1]))
+	    return CMD_WARNING;
+	  rip_redistribute_unset (redist_type[i].type);
+	  return CMD_SUCCESS;
+        }
+    }
+
+  vty_out(vty, "Invalid type %s%s", argv[0],
+	  VTY_NEWLINE);
+
+  return CMD_WARNING;
+}
+
+DEFUN (rip_redistribute_type_metric,
+       rip_redistribute_type_metric_cmd,
+       "redistribute (kernel|connected|static|ospf|bgp) metric <0-16>",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric\n"
+       "Metric value\n")
+{
+  int i;
+  int metric;
+
+  metric = atoi (argv[1]);
+
+  for (i = 0; redist_type[i].str; i++) {
+    if (strncmp(redist_type[i].str, argv[0],
+		redist_type[i].str_min_len) == 0) 
+      {
+	rip_redistribute_metric_set (redist_type[i].type, metric);
+	zclient_redistribute_set (zclient, redist_type[i].type);
+	return CMD_SUCCESS;
+      }
+  }
+
+  vty_out(vty, "Invalid type %s%s", argv[0],
+	  VTY_NEWLINE);
+
+  return CMD_WARNING;
+}
+
+DEFUN (no_rip_redistribute_type_metric,
+       no_rip_redistribute_type_metric_cmd,
+       "no redistribute (kernel|connected|static|ospf|bgp) metric <0-16>",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric\n"
+       "Metric value\n")
+{
+  int i;
+
+  for (i = 0; redist_type[i].str; i++) 
+    {
+      if (strncmp(redist_type[i].str, argv[0], 
+		  redist_type[i].str_min_len) == 0) 
+	{
+	  if (rip_metric_unset (redist_type[i].type, atoi(argv[1])))
+	    return CMD_WARNING;
+	  rip_redistribute_unset (redist_type[i].type);
+	  return CMD_SUCCESS;
+        }
+    }
+
+  vty_out(vty, "Invalid type %s%s", argv[0],
+	  VTY_NEWLINE);
+
+  return CMD_WARNING;
+}
+
+DEFUN (no_rip_redistribute_type_metric_routemap,
+       no_rip_redistribute_type_metric_routemap_cmd,
+       "no redistribute (kernel|connected|static|ospf|bgp) metric <0-16> route-map WORD",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPF)\n"
+       "Border Gateway Protocol (BGP)\n"
+       "Metric\n"
+       "Metric value\n"
+       "Route map reference\n"
+       "Pointer to route-map entries\n")
+{
+  int i;
+
+  for (i = 0; redist_type[i].str; i++) 
+    {
+      if (strncmp(redist_type[i].str, argv[0], 
+		  redist_type[i].str_min_len) == 0) 
+	{
+	  if (rip_metric_unset (redist_type[i].type, atoi(argv[1])))
+	    return CMD_WARNING;
+	  if (rip_routemap_unset (redist_type[i].type, argv[2]))
+	    {
+	      rip_redistribute_metric_set(redist_type[i].type, atoi(argv[1]));   
+	      return CMD_WARNING;
+	    }
+	  rip_redistribute_unset (redist_type[i].type);
+	  return CMD_SUCCESS;
+        }
+    }
+
+  vty_out(vty, "Invalid type %s%s", argv[0],
+	  VTY_NEWLINE);
+
+  return CMD_WARNING;
+}
+
+/* Default information originate. */
+
+DEFUN (rip_default_information_originate,
+       rip_default_information_originate_cmd,
+       "default-information originate",
+       "Control distribution of default route\n"
+       "Distribute a default route\n")
+{
+  struct prefix_ipv4 p;
+
+  if (! rip->default_information)
+    {
+      memset (&p, 0, sizeof (struct prefix_ipv4));
+      p.family = AF_INET;
+
+      rip->default_information = 1;
+  
+      rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL);
+    }
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_default_information_originate,
+       no_rip_default_information_originate_cmd,
+       "no default-information originate",
+       NO_STR
+       "Control distribution of default route\n"
+       "Distribute a default route\n")
+{
+  struct prefix_ipv4 p;
+
+  if (rip->default_information)
+    {
+      memset (&p, 0, sizeof (struct prefix_ipv4));
+      p.family = AF_INET;
+
+      rip->default_information = 0;
+  
+      rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* RIP configuration write function. */
+int
+config_write_zebra (struct vty *vty)
+{
+  if (! zclient->enable)
+    {
+      vty_out (vty, "no router zebra%s", VTY_NEWLINE);
+      return 1;
+    }
+  else if (! zclient->redist[ZEBRA_ROUTE_RIP])
+    {
+      vty_out (vty, "router zebra%s", VTY_NEWLINE);
+      vty_out (vty, " no redistribute rip%s", VTY_NEWLINE);
+      return 1;
+    }
+  return 0;
+}
+
+int
+config_write_rip_redistribute (struct vty *vty, int config_mode)
+{
+  int i;
+  char *str[] = { "system", "kernel", "connected", "static", "rip",
+		  "ripng", "ospf", "ospf6", "bgp"};
+
+  for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+    if (i != zclient->redist_default && zclient->redist[i])
+      {
+	if (config_mode)
+	  {
+	    if (rip->route_map[i].metric_config)
+	      {
+		if (rip->route_map[i].name)
+		  vty_out (vty, " redistribute %s metric %d route-map %s%s",
+			   str[i], rip->route_map[i].metric,
+			   rip->route_map[i].name,
+			   VTY_NEWLINE);
+		else
+		  vty_out (vty, " redistribute %s metric %d%s",
+			   str[i], rip->route_map[i].metric,
+			   VTY_NEWLINE);
+	      }
+	    else
+	      {
+		if (rip->route_map[i].name)
+		  vty_out (vty, " redistribute %s route-map %s%s",
+			   str[i], rip->route_map[i].name,
+			   VTY_NEWLINE);
+		else
+		  vty_out (vty, " redistribute %s%s", str[i],
+			   VTY_NEWLINE);
+	      }
+	  }
+	else
+	  vty_out (vty, " %s", str[i]);
+      }
+  return 0;
+}
+
+/* Zebra node structure. */
+struct cmd_node zebra_node =
+{
+  ZEBRA_NODE,
+  "%s(config-router)# ",
+};
+
+void
+rip_zclient_init ()
+{
+  /* Set default value to the zebra client structure. */
+  zclient = zclient_new ();
+  zclient_init (zclient, ZEBRA_ROUTE_RIP);
+  zclient->interface_add = rip_interface_add;
+  zclient->interface_delete = rip_interface_delete;
+  zclient->interface_address_add = rip_interface_address_add;
+  zclient->interface_address_delete = rip_interface_address_delete;
+  zclient->ipv4_route_add = rip_zebra_read_ipv4;
+  zclient->ipv4_route_delete = rip_zebra_read_ipv4;
+  zclient->interface_up = rip_interface_up;
+  zclient->interface_down = rip_interface_down;
+  
+  /* Install zebra node. */
+  install_node (&zebra_node, config_write_zebra);
+
+  /* Install command elements to zebra node. */ 
+  install_element (CONFIG_NODE, &router_zebra_cmd);
+  install_element (CONFIG_NODE, &no_router_zebra_cmd);
+  install_default (ZEBRA_NODE);
+  install_element (ZEBRA_NODE, &rip_redistribute_rip_cmd);
+  install_element (ZEBRA_NODE, &no_rip_redistribute_rip_cmd);
+
+  /* Install command elements to rip node. */
+  install_element (RIP_NODE, &rip_redistribute_type_cmd);
+  install_element (RIP_NODE, &rip_redistribute_type_routemap_cmd);
+  install_element (RIP_NODE, &rip_redistribute_type_metric_cmd);
+  install_element (RIP_NODE, &no_rip_redistribute_type_cmd);
+  install_element (RIP_NODE, &no_rip_redistribute_type_routemap_cmd);
+  install_element (RIP_NODE, &no_rip_redistribute_type_metric_cmd);
+  install_element (RIP_NODE, &no_rip_redistribute_type_metric_routemap_cmd);
+  install_element (RIP_NODE, &rip_default_information_originate_cmd);
+  install_element (RIP_NODE, &no_rip_default_information_originate_cmd);
+}
diff --git a/ripd/ripd.c b/ripd/ripd.c
new file mode 100644
index 0000000..c017fe5
--- /dev/null
+++ b/ripd/ripd.c
@@ -0,0 +1,3536 @@
+/* RIP version 1 and 2.
+ * Copyright (C) 1997, 98, 99 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>
+
+#include "if.h"
+#include "command.h"
+#include "prefix.h"
+#include "table.h"
+#include "thread.h"
+#include "memory.h"
+#include "log.h"
+#include "stream.h"
+#include "filter.h"
+#include "sockunion.h"
+#include "routemap.h"
+#include "plist.h"
+#include "distribute.h"
+#include "md5-gnu.h"
+#include "keychain.h"
+
+#include "ripd/ripd.h"
+#include "ripd/rip_debug.h"
+
+/* RIP Structure. */
+struct rip *rip = NULL;
+
+/* RIP neighbor address table. */
+struct route_table *rip_neighbor_table;
+
+/* RIP route changes. */
+long rip_global_route_changes = 0;
+
+/* RIP queries. */
+long rip_global_queries = 0;
+
+/* Prototypes. */
+void rip_event (enum rip_event, int);
+
+void rip_output_process (struct interface *, struct sockaddr_in *, 
+			 int, u_char);
+
+/* RIP output routes type. */
+enum
+{
+  rip_all_route,
+  rip_changed_route
+};
+
+/* RIP command strings. */
+struct message rip_msg[] = 
+{
+  {RIP_REQUEST,    "REQUEST"},
+  {RIP_RESPONSE,   "RESPONSE"},
+  {RIP_TRACEON,    "TRACEON"},
+  {RIP_TRACEOFF,   "TRACEOFF"},
+  {RIP_POLL,       "POLL"},
+  {RIP_POLL_ENTRY, "POLL ENTRY"},
+  {0,              NULL}
+};
+
+/* Each route type's strings and default preference. */
+struct
+{  
+  int key;
+  char *str;
+  char *str_long;
+} route_info[] =
+{
+  { ZEBRA_ROUTE_SYSTEM,  "X", "system"},
+  { ZEBRA_ROUTE_KERNEL,  "K", "kernel"},
+  { ZEBRA_ROUTE_CONNECT, "C", "connected"},
+  { ZEBRA_ROUTE_STATIC,  "S", "static"},
+  { ZEBRA_ROUTE_RIP,     "R", "rip"},
+  { ZEBRA_ROUTE_RIPNG,   "R", "ripng"},
+  { ZEBRA_ROUTE_OSPF,    "O", "ospf"},
+  { ZEBRA_ROUTE_OSPF6,   "O", "ospf6"},
+  { ZEBRA_ROUTE_BGP,     "B", "bgp"}
+};
+
+/* Utility function to set boradcast option to the socket. */
+int
+sockopt_broadcast (int sock)
+{
+  int ret;
+  int on = 1;
+
+  ret = setsockopt (sock, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof on);
+  if (ret < 0)
+    {
+      zlog_warn ("can't set sockopt SO_BROADCAST to socket %d", sock);
+      return -1;
+    }
+  return 0;
+}
+
+int
+rip_route_rte (struct rip_info *rinfo)
+{
+  return (rinfo->type == ZEBRA_ROUTE_RIP && rinfo->sub_type == RIP_ROUTE_RTE);
+}
+
+struct rip_info *
+rip_info_new ()
+{
+  struct rip_info *new;
+
+  new = XMALLOC (MTYPE_RIP_INFO, sizeof (struct rip_info));
+  memset (new, 0, sizeof (struct rip_info));
+  return new;
+}
+
+void
+rip_info_free (struct rip_info *rinfo)
+{
+  XFREE (MTYPE_RIP_INFO, rinfo);
+}
+
+/* RIP route garbage collect timer. */
+int
+rip_garbage_collect (struct thread *t)
+{
+  struct rip_info *rinfo;
+  struct route_node *rp;
+
+  rinfo = THREAD_ARG (t);
+  rinfo->t_garbage_collect = NULL;
+
+  /* Off timeout timer. */
+  RIP_TIMER_OFF (rinfo->t_timeout);
+  
+  /* Get route_node pointer. */
+  rp = rinfo->rp;
+
+  /* Unlock route_node. */
+  rp->info = NULL;
+  route_unlock_node (rp);
+
+  /* Free RIP routing information. */
+  rip_info_free (rinfo);
+
+  return 0;
+}
+
+/* Timeout RIP routes. */
+int
+rip_timeout (struct thread *t)
+{
+  struct rip_info *rinfo;
+  struct route_node *rn;
+
+  rinfo = THREAD_ARG (t);
+  rinfo->t_timeout = NULL;
+
+  rn = rinfo->rp;
+
+  /* - The garbage-collection timer is set for 120 seconds. */
+  RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect, 
+		rip->garbage_time);
+
+  rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rn->p, &rinfo->nexthop,
+			 rinfo->metric);
+  /* - The metric for the route is set to 16 (infinity).  This causes
+     the route to be removed from service. */
+  rinfo->metric = RIP_METRIC_INFINITY;
+  rinfo->flags &= ~RIP_RTF_FIB;
+
+  /* - The route change flag is to indicate that this entry has been
+     changed. */
+  rinfo->flags |= RIP_RTF_CHANGED;
+
+  /* - The output process is signalled to trigger a response. */
+  rip_event (RIP_TRIGGERED_UPDATE, 0);
+
+  return 0;
+}
+
+void
+rip_timeout_update (struct rip_info *rinfo)
+{
+  if (rinfo->metric != RIP_METRIC_INFINITY)
+    {
+      RIP_TIMER_OFF (rinfo->t_timeout);
+      RIP_TIMER_ON (rinfo->t_timeout, rip_timeout, rip->timeout_time);
+    }
+}
+
+int
+rip_incoming_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
+{
+  struct distribute *dist;
+  struct access_list *alist;
+  struct prefix_list *plist;
+
+  /* Input distribute-list filtering. */
+  if (ri->list[RIP_FILTER_IN])
+    {
+      if (access_list_apply (ri->list[RIP_FILTER_IN], 
+			     (struct prefix *) p) == FILTER_DENY)
+	{
+	  if (IS_RIP_DEBUG_PACKET)
+	    zlog_info ("%s/%d filtered by distribute in",
+		       inet_ntoa (p->prefix), p->prefixlen);
+	  return -1;
+	}
+    }
+  if (ri->prefix[RIP_FILTER_IN])
+    {
+      if (prefix_list_apply (ri->prefix[RIP_FILTER_IN], 
+			     (struct prefix *) p) == PREFIX_DENY)
+	{
+	  if (IS_RIP_DEBUG_PACKET)
+	    zlog_info ("%s/%d filtered by prefix-list in",
+		       inet_ntoa (p->prefix), p->prefixlen);
+	  return -1;
+	}
+    }
+
+  /* All interface filter check. */
+  dist = distribute_lookup (NULL);
+  if (dist)
+    {
+      if (dist->list[DISTRIBUTE_IN])
+	{
+	  alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
+	    
+	  if (alist)
+	    {
+	      if (access_list_apply (alist,
+				     (struct prefix *) p) == FILTER_DENY)
+		{
+		  if (IS_RIP_DEBUG_PACKET)
+		    zlog_info ("%s/%d filtered by distribute in",
+			       inet_ntoa (p->prefix), p->prefixlen);
+		  return -1;
+		}
+	    }
+	}
+      if (dist->prefix[DISTRIBUTE_IN])
+	{
+	  plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
+	  
+	  if (plist)
+	    {
+	      if (prefix_list_apply (plist,
+				     (struct prefix *) p) == PREFIX_DENY)
+		{
+		  if (IS_RIP_DEBUG_PACKET)
+		    zlog_info ("%s/%d filtered by prefix-list in",
+			       inet_ntoa (p->prefix), p->prefixlen);
+		  return -1;
+		}
+	    }
+	}
+    }
+  return 0;
+}
+
+int
+rip_outgoing_filter (struct prefix_ipv4 *p, struct rip_interface *ri)
+{
+  struct distribute *dist;
+  struct access_list *alist;
+  struct prefix_list *plist;
+
+  if (ri->list[RIP_FILTER_OUT])
+    {
+      if (access_list_apply (ri->list[RIP_FILTER_OUT],
+			     (struct prefix *) p) == FILTER_DENY)
+	{
+	  if (IS_RIP_DEBUG_PACKET)
+	    zlog_info ("%s/%d is filtered by distribute out",
+		       inet_ntoa (p->prefix), p->prefixlen);
+	  return -1;
+	}
+    }
+  if (ri->prefix[RIP_FILTER_OUT])
+    {
+      if (prefix_list_apply (ri->prefix[RIP_FILTER_OUT],
+			     (struct prefix *) p) == PREFIX_DENY)
+	{
+	  if (IS_RIP_DEBUG_PACKET)
+	    zlog_info ("%s/%d is filtered by prefix-list out",
+		       inet_ntoa (p->prefix), p->prefixlen);
+	  return -1;
+	}
+    }
+
+  /* All interface filter check. */
+  dist = distribute_lookup (NULL);
+  if (dist)
+    {
+      if (dist->list[DISTRIBUTE_OUT])
+	{
+	  alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
+	    
+	  if (alist)
+	    {
+	      if (access_list_apply (alist,
+				     (struct prefix *) p) == FILTER_DENY)
+		{
+		  if (IS_RIP_DEBUG_PACKET)
+		    zlog_info ("%s/%d filtered by distribute out",
+			       inet_ntoa (p->prefix), p->prefixlen);
+		  return -1;
+		}
+	    }
+	}
+      if (dist->prefix[DISTRIBUTE_OUT])
+	{
+	  plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
+	  
+	  if (plist)
+	    {
+	      if (prefix_list_apply (plist,
+				     (struct prefix *) p) == PREFIX_DENY)
+		{
+		  if (IS_RIP_DEBUG_PACKET)
+		    zlog_info ("%s/%d filtered by prefix-list out",
+			       inet_ntoa (p->prefix), p->prefixlen);
+		  return -1;
+		}
+	    }
+	}
+    }
+  return 0;
+}
+
+/* Check nexthop address validity. */
+static int
+rip_nexthop_check (struct in_addr *addr)
+{
+  listnode node;
+  listnode cnode;
+  struct interface *ifp;
+  struct connected *ifc;
+  struct prefix *p;
+
+  /* If nexthop address matches local configured address then it is
+     invalid nexthop. */
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+
+      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
+	{	    
+	  ifc = getdata (cnode);
+	  p = ifc->address;
+
+	  if (p->family == AF_INET
+	      && IPV4_ADDR_SAME (&p->u.prefix4, addr))
+	    return -1;
+	}
+    }
+  return 0;
+}
+
+/* RIP add route to routing table. */
+void
+rip_rte_process (struct rte *rte, struct sockaddr_in *from,
+		 struct interface *ifp)
+
+{
+  int ret;
+  struct prefix_ipv4 p;
+  struct route_node *rp;
+  struct rip_info *rinfo;
+  struct rip_interface *ri;
+  struct in_addr *nexthop;
+  u_char oldmetric;
+  int same = 0;
+
+  /* Make prefix structure. */
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefix = rte->prefix;
+  p.prefixlen = ip_masklen (rte->mask);
+
+  /* Make sure mask is applied. */
+  apply_mask_ipv4 (&p);
+
+  /* Apply input filters. */
+  ri = ifp->info;
+
+  ret = rip_incoming_filter (&p, ri);
+  if (ret < 0)
+    return;
+
+  /* Once the entry has been validated, update the metric by
+     adding the cost of the network on wich the message
+     arrived. If the result is greater than infinity, use infinity
+     (RFC2453 Sec. 3.9.2) */
+  /* Zebra ripd can handle offset-list in. */
+  ret = rip_offset_list_apply_in (&p, ifp, &rte->metric);
+
+  /* If offset-list does not modify the metric use interface's
+     metric. */
+  if (! ret)
+    rte->metric += ifp->metric;
+
+  if (rte->metric > RIP_METRIC_INFINITY)
+    rte->metric = RIP_METRIC_INFINITY;
+
+  /* Set nexthop pointer. */
+  if (rte->nexthop.s_addr == 0)
+    nexthop = &from->sin_addr;
+  else
+    nexthop = &rte->nexthop;
+
+  /* Check nexthop address. */
+  if (rip_nexthop_check (nexthop) < 0)
+    {
+      if (IS_RIP_DEBUG_PACKET)
+	zlog_info ("Nexthop address %s is invalid", inet_ntoa (*nexthop));
+      return;
+    }
+
+  /* Get index for the prefix. */
+  rp = route_node_get (rip->table, (struct prefix *) &p);
+
+  /* Check to see whether there is already RIP route on the table. */
+  rinfo = rp->info;
+
+  if (rinfo)
+    {
+      /* Redistributed route check. */
+      if (rinfo->type != ZEBRA_ROUTE_RIP
+	  && rinfo->metric != RIP_METRIC_INFINITY)
+	return;
+
+      /* Local static route. */
+      if (rinfo->type == ZEBRA_ROUTE_RIP
+	  && rinfo->sub_type == RIP_ROUTE_STATIC
+	  && rinfo->metric != RIP_METRIC_INFINITY)
+	return;
+    }
+  
+  if (! rinfo)
+    {
+      /* Now, check to see whether there is already an explicit route
+	 for the destination prefix.  If there is no such route, add
+	 this route to the routing table, unless the metric is
+	 infinity (there is no point in adding a route which
+	 unusable). */
+      if (rte->metric != RIP_METRIC_INFINITY)
+	{
+	  rinfo = rip_info_new ();
+	  
+	  /* - Setting the destination prefix and length to those in
+	     the RTE. */
+	  rinfo->rp = rp;
+
+	  /* - Setting the metric to the newly calculated metric (as
+	     described above). */
+	  rinfo->metric = rte->metric;
+	  rinfo->tag = ntohs (rte->tag);
+
+	  /* - Set the next hop address to be the address of the router
+	     from which the datagram came or the next hop address
+	     specified by a next hop RTE. */
+	  IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
+	  IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr);
+	  rinfo->ifindex = ifp->ifindex;
+
+	  /* - Initialize the timeout for the route.  If the
+	     garbage-collection timer is running for this route, stop it
+	     (see section 2.3 for a discussion of the timers). */
+	  rip_timeout_update (rinfo);
+
+	  /* - Set the route change flag. */
+	  rinfo->flags |= RIP_RTF_CHANGED;
+
+	  /* - Signal the output process to trigger an update (see section
+	     2.5). */
+	  rip_event (RIP_TRIGGERED_UPDATE, 0);
+
+	  /* Finally, route goes into the kernel. */
+	  rinfo->type = ZEBRA_ROUTE_RIP;
+	  rinfo->sub_type = RIP_ROUTE_RTE;
+
+	  /* Set distance value. */
+	  rinfo->distance = rip_distance_apply (rinfo);
+
+	  rp->info = rinfo;
+	  rip_zebra_ipv4_add (&p, &rinfo->nexthop, rinfo->metric,
+			      rinfo->distance);
+	  rinfo->flags |= RIP_RTF_FIB;
+	}
+    }
+  else
+    {
+      /* Route is there but we are not sure the route is RIP or not. */
+      rinfo = rp->info;
+	  
+      /* If there is an existing route, compare the next hop address
+	 to the address of the router from which the datagram came.
+	 If this datagram is from the same router as the existing
+	 route, reinitialize the timeout.  */
+      same = IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr);
+
+      if (same)
+	rip_timeout_update (rinfo);
+
+      /* Next, compare the metrics.  If the datagram is from the same
+	 router as the existing route, and the new metric is different
+	 than the old one; or, if the new metric is lower than the old
+	 one; do the following actions: */
+      if ((same && rinfo->metric != rte->metric) ||
+	  rte->metric < rinfo->metric)
+	{
+	  /* - Adopt the route from the datagram.  That is, put the
+	     new metric in, and adjust the next hop address (if
+	     necessary). */
+	  oldmetric = rinfo->metric;
+	  rinfo->metric = rte->metric;
+	  rinfo->tag = ntohs (rte->tag);
+	  IPV4_ADDR_COPY (&rinfo->from, &from->sin_addr);
+	  rinfo->ifindex = ifp->ifindex;
+	  rinfo->distance = rip_distance_apply (rinfo);
+
+	  /* Should a new route to this network be established
+	     while the garbage-collection timer is running, the
+	     new route will replace the one that is about to be
+	     deleted.  In this case the garbage-collection timer
+	     must be cleared. */
+
+	  if (oldmetric == RIP_METRIC_INFINITY &&
+	      rinfo->metric < RIP_METRIC_INFINITY)
+	    {
+	      rinfo->type = ZEBRA_ROUTE_RIP;
+	      rinfo->sub_type = RIP_ROUTE_RTE;
+
+	      RIP_TIMER_OFF (rinfo->t_garbage_collect);
+
+	      if (! IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))
+		IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
+
+	      rip_zebra_ipv4_add (&p, nexthop, rinfo->metric,
+				  rinfo->distance);
+	      rinfo->flags |= RIP_RTF_FIB;
+	    }
+
+	  /* Update nexthop and/or metric value.  */
+	  if (oldmetric != RIP_METRIC_INFINITY)
+	    {
+	      rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric);
+	      rip_zebra_ipv4_add (&p, nexthop, rinfo->metric,
+				  rinfo->distance);
+	      rinfo->flags |= RIP_RTF_FIB;
+
+	      if (! IPV4_ADDR_SAME (&rinfo->nexthop, nexthop))
+		IPV4_ADDR_COPY (&rinfo->nexthop, nexthop);
+	    }
+
+	  /* - Set the route change flag and signal the output process
+	     to trigger an update. */
+	  rinfo->flags |= RIP_RTF_CHANGED;
+	  rip_event (RIP_TRIGGERED_UPDATE, 0);
+
+	  /* - If the new metric is infinity, start the deletion
+	     process (described above); */
+	  if (rinfo->metric == RIP_METRIC_INFINITY)
+	    {
+	      /* If the new metric is infinity, the deletion process
+		 begins for the route, which is no longer used for
+		 routing packets.  Note that the deletion process is
+		 started only when the metric is first set to
+		 infinity.  If the metric was already infinity, then a
+		 new deletion process is not started. */
+	      if (oldmetric != RIP_METRIC_INFINITY)
+		{
+		  /* - The garbage-collection timer is set for 120 seconds. */
+		  RIP_TIMER_ON (rinfo->t_garbage_collect, 
+				rip_garbage_collect, rip->garbage_time);
+		  RIP_TIMER_OFF (rinfo->t_timeout);
+
+		  /* - The metric for the route is set to 16
+		     (infinity).  This causes the route to be removed
+		     from service.*/
+		  rip_zebra_ipv4_delete (&p, &rinfo->nexthop, oldmetric);
+		  rinfo->flags &= ~RIP_RTF_FIB;
+
+		  /* - The route change flag is to indicate that this
+		     entry has been changed. */
+		  /* - The output process is signalled to trigger a
+                     response. */
+		  ;  /* Above processes are already done previously. */
+		}
+	    }
+	  else
+	    {
+	      /* otherwise, re-initialize the timeout. */
+	      rip_timeout_update (rinfo);
+	    }
+	}
+      /* Unlock tempolary lock of the route. */
+      route_unlock_node (rp);
+    }
+}
+
+/* Dump RIP packet */
+void
+rip_packet_dump (struct rip_packet *packet, int size, char *sndrcv)
+{
+  caddr_t lim;
+  struct rte *rte;
+  char *command_str;
+  char pbuf[BUFSIZ], nbuf[BUFSIZ];
+  u_char netmask = 0;
+  u_char *p;
+
+  /* Set command string. */
+  if (packet->command > 0 && packet->command < RIP_COMMAND_MAX)
+    command_str = lookup (rip_msg, packet->command);
+  else
+    command_str = "unknown";
+
+  /* Dump packet header. */
+  zlog_info ("%s %s version %d packet size %d",
+	     sndrcv, command_str, packet->version, size);
+
+  /* Dump each routing table entry. */
+  rte = packet->rte;
+  
+  for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
+    {
+      if (packet->version == RIPv2)
+	{
+	  netmask = ip_masklen (rte->mask);
+
+	  if (ntohs (rte->family) == 0xffff)
+            {
+	      if (ntohs (rte->tag) == RIP_AUTH_SIMPLE_PASSWORD)
+		{
+		  p = (u_char *)&rte->prefix;
+
+		  zlog_info ("  family 0x%X type %d auth string: %s",
+			     ntohs (rte->family), ntohs (rte->tag), p);
+		}
+	      else if (ntohs (rte->tag) == RIP_AUTH_MD5)
+		{
+		  struct rip_md5_info *md5;
+
+		  md5 = (struct rip_md5_info *) &packet->rte;
+
+		  zlog_info ("  family 0x%X type %d (MD5 authentication)",
+			     ntohs (md5->family), ntohs (md5->type));
+		  zlog_info ("    RIP-2 packet len %d Key ID %d"
+			     " Auth Data len %d", ntohs (md5->packet_len),
+			     md5->keyid, md5->auth_len);
+		  zlog_info ("    Sequence Number %ld", (u_long)ntohl (md5->sequence));
+		}
+	      else if (ntohs (rte->tag) == RIP_AUTH_DATA)
+		{
+		  p = (u_char *)&rte->prefix;
+
+		  zlog_info ("  family 0x%X type %d (MD5 data)",
+			     ntohs (rte->family), ntohs (rte->tag));
+		  zlog_info ("    MD5: %02X%02X%02X%02X%02X%02X%02X%02X"
+			     "%02X%02X%02X%02X%02X%02X%02X",
+			     p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7],
+			     p[9],p[10],p[11],p[12],p[13],p[14],p[15]);
+		}
+	      else
+		{
+		  zlog_info ("  family 0x%X type %d (Unknown auth type)",
+			     ntohs (rte->family), ntohs (rte->tag));
+		}
+            }
+	  else
+	    zlog_info ("  %s/%d -> %s family %d tag %d metric %ld",
+		       inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),netmask,
+		       inet_ntop (AF_INET, &rte->nexthop, nbuf, BUFSIZ),
+		       ntohs (rte->family), ntohs (rte->tag), 
+		       (u_long)ntohl (rte->metric));
+	}
+      else
+	{
+	  zlog_info ("  %s family %d tag %d metric %ld", 
+		     inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ),
+		     ntohs (rte->family), ntohs (rte->tag),
+		     (u_long)ntohl (rte->metric));
+	}
+    }
+}
+
+/* Check if the destination address is valid (unicast; not net 0
+   or 127) (RFC2453 Section 3.9.2 - Page 26).  But we don't
+   check net 0 because we accept default route. */
+int
+rip_destination_check (struct in_addr addr)
+{
+  u_int32_t destination;
+
+  /* Convert to host byte order. */
+  destination = ntohl (addr.s_addr);
+
+  if (IPV4_NET127 (destination))
+    return 0;
+
+  /* Net 0 may match to the default route. */
+  if (IPV4_NET0 (destination) && destination != 0)
+    return 0;
+
+  /* Unicast address must belong to class A, B, C. */
+  if (IN_CLASSA (destination))
+    return 1;
+  if (IN_CLASSB (destination))
+    return 1;
+  if (IN_CLASSC (destination))
+    return 1;
+
+  return 0;
+}
+
+/* RIP version 2 authentication. */
+int
+rip_auth_simple_password (struct rte *rte, struct sockaddr_in *from,
+			  struct interface *ifp)
+{
+  struct rip_interface *ri;
+  char *auth_str;
+
+  if (IS_RIP_DEBUG_EVENT)
+    zlog_info ("RIPv2 simple password authentication from %s",
+	       inet_ntoa (from->sin_addr));
+
+  ri = ifp->info;
+
+  if (ri->auth_type != RIP_AUTH_SIMPLE_PASSWORD
+      || ntohs (rte->tag) != RIP_AUTH_SIMPLE_PASSWORD)
+    return 0;
+
+  /* Simple password authentication. */
+  if (ri->auth_str)
+    {
+      auth_str = (char *) &rte->prefix;
+	  
+      if (strncmp (auth_str, ri->auth_str, 16) == 0)
+	return 1;
+    }
+  if (ri->key_chain)
+    {
+      struct keychain *keychain;
+      struct key *key;
+
+      keychain = keychain_lookup (ri->key_chain);
+      if (keychain == NULL)
+	return 0;
+
+      key = key_match_for_accept (keychain, (char *) &rte->prefix);
+      if (key)
+	return 1;
+    }
+  return 0;
+}
+
+/* RIP version 2 authentication with MD5. */
+int
+rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from,
+	      struct interface *ifp)
+{
+  struct rip_interface *ri;
+  struct rip_md5_info *md5;
+  struct rip_md5_data *md5data;
+  struct keychain *keychain;
+  struct key *key;
+  struct md5_ctx ctx;
+  u_char pdigest[RIP_AUTH_MD5_SIZE];
+  u_char digest[RIP_AUTH_MD5_SIZE];
+  u_int16_t packet_len;
+  char *auth_str = NULL;
+  
+  if (IS_RIP_DEBUG_EVENT)
+    zlog_info ("RIPv2 MD5 authentication from %s", inet_ntoa (from->sin_addr));
+
+  ri = ifp->info;
+  md5 = (struct rip_md5_info *) &packet->rte;
+
+  /* Check auth type. */
+  if (ri->auth_type != RIP_AUTH_MD5 || ntohs (md5->type) != RIP_AUTH_MD5)
+    return 0;
+
+  if (md5->auth_len != RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE)
+    return 0;
+
+  if (ri->key_chain)
+    {
+      keychain = keychain_lookup (ri->key_chain);
+      if (keychain == NULL)
+	return 0;
+
+      key = key_lookup_for_accept (keychain, md5->keyid);
+      if (key == NULL)
+	return 0;
+
+      auth_str = key->string;
+    }
+
+  if (ri->auth_str)
+    auth_str = ri->auth_str;
+
+  if (! auth_str)
+    return 0;
+
+  /* MD5 digest authentication. */
+  packet_len = ntohs (md5->packet_len);
+  md5data = (struct rip_md5_data *)(((u_char *) packet) + packet_len);
+
+  /* Save digest to pdigest. */
+  memcpy (pdigest, md5data->digest, RIP_AUTH_MD5_SIZE);
+
+  /* Overwrite digest by my secret. */
+  memset (md5data->digest, 0, RIP_AUTH_MD5_SIZE);
+  strncpy (md5data->digest, auth_str, RIP_AUTH_MD5_SIZE);
+
+  md5_init_ctx (&ctx);
+  md5_process_bytes (packet, packet_len + md5->auth_len, &ctx);
+  md5_finish_ctx (&ctx, digest);
+
+  if (memcmp (pdigest, digest, RIP_AUTH_MD5_SIZE) == 0)
+    return packet_len;
+  else
+    return 0;
+}
+
+void
+rip_auth_md5_set (struct stream *s, struct interface *ifp)
+{
+  struct rip_interface *ri;
+  struct keychain *keychain = NULL;
+  struct key *key = NULL;
+  unsigned long len;
+  struct md5_ctx ctx;
+  unsigned char secret[RIP_AUTH_MD5_SIZE];
+  unsigned char digest[RIP_AUTH_MD5_SIZE];
+  char *auth_str = NULL;
+
+  ri = ifp->info;
+
+  /* Make it sure this interface is configured as MD5
+     authentication. */
+  if (ri->auth_type != RIP_AUTH_MD5)
+    return;
+
+  /* Lookup key chain. */
+  if (ri->key_chain)
+    {
+      keychain = keychain_lookup (ri->key_chain);
+      if (keychain == NULL)
+	return;
+
+      /* Lookup key. */
+      key = key_lookup_for_send (keychain);
+      if (key == NULL)
+	return;
+
+      auth_str = key->string;
+    }
+
+  if (ri->auth_str)
+    auth_str = ri->auth_str;
+
+  if (! auth_str)
+    return;
+
+  /* Get packet length. */
+  len = s->putp;
+
+  /* Check packet length. */
+  if (len < (RIP_HEADER_SIZE + RIP_RTE_SIZE))
+    {
+      zlog_err ("rip_auth_md5_set(): packet length %ld is less than minimum length.", len);
+      return;
+    }
+
+  /* Move RTE. */
+  memmove (s->data + RIP_HEADER_SIZE + RIP_RTE_SIZE,
+	   s->data + RIP_HEADER_SIZE,
+	   len - RIP_HEADER_SIZE);
+  
+  /* Set pointer to authentication header. */
+  stream_set_putp (s, RIP_HEADER_SIZE);
+  len += RIP_RTE_SIZE;
+
+  /* MD5 authentication. */
+  stream_putw (s, 0xffff);
+  stream_putw (s, RIP_AUTH_MD5);
+
+  /* RIP-2 Packet length.  Actual value is filled in
+     rip_auth_md5_set(). */
+  stream_putw (s, len);
+
+  /* Key ID. */
+  if (key)
+    stream_putc (s, key->index % 256);
+  else
+    stream_putc (s, 1);
+
+  /* Auth Data Len.  Set 16 for MD5 authentication
+     data. */
+  stream_putc (s, RIP_AUTH_MD5_SIZE + RIP_HEADER_SIZE);
+
+  /* Sequence Number (non-decreasing). */
+  /* RFC2080: The value used in the sequence number is
+     arbitrary, but two suggestions are the time of the
+     message's creation or a simple message counter. */
+  stream_putl (s, time (NULL));
+	      
+  /* Reserved field must be zero. */
+  stream_putl (s, 0);
+  stream_putl (s, 0);
+
+  /* Set pointer to authentication data. */
+  stream_set_putp (s, len);
+
+  /* Set authentication data. */
+  stream_putw (s, 0xffff);
+  stream_putw (s, 0x01);
+
+  /* Generate a digest for the RIP packet. */
+  memset (secret, 0, RIP_AUTH_MD5_SIZE);
+  strncpy (secret, auth_str, RIP_AUTH_MD5_SIZE);
+  md5_init_ctx (&ctx);
+  md5_process_bytes (s->data, s->endp, &ctx);
+  md5_process_bytes (secret, RIP_AUTH_MD5_SIZE, &ctx);
+  md5_finish_ctx (&ctx, digest);
+
+  /* Copy the digest to the packet. */
+  stream_write (s, digest, RIP_AUTH_MD5_SIZE);
+}
+
+/* RIP routing information. */
+void
+rip_response_process (struct rip_packet *packet, int size, 
+		      struct sockaddr_in *from, struct interface *ifp)
+{
+  caddr_t lim;
+  struct rte *rte;
+      
+  /* The Response must be ignored if it is not from the RIP
+     port. (RFC2453 - Sec. 3.9.2)*/
+  if (ntohs (from->sin_port) != RIP_PORT_DEFAULT) 
+    {
+      zlog_info ("response doesn't come from RIP port: %d",
+		 from->sin_port);
+      rip_peer_bad_packet (from);
+      return;
+    }
+
+  /* The datagram's IPv4 source address should be checked to see
+     whether the datagram is from a valid neighbor; the source of the
+     datagram must be on a directly connected network  */
+  if (! if_valid_neighbor (from->sin_addr)) 
+    {
+      zlog_info ("This datagram doesn't came from a valid neighbor: %s",
+		 inet_ntoa (from->sin_addr));
+      rip_peer_bad_packet (from);
+      return;
+    }
+
+  /* It is also worth checking to see whether the response is from one
+     of the router's own addresses. */
+
+  ; /* Alredy done in rip_read () */
+
+  /* Update RIP peer. */
+  rip_peer_update (from, packet->version);
+
+  /* Set RTE pointer. */
+  rte = packet->rte;
+
+  for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
+    {
+      /* RIPv2 authentication check. */
+      /* If the Address Family Identifier of the first (and only the
+	 first) entry in the message is 0xFFFF, then the remainder of
+	 the entry contains the authentication. */
+      /* If the packet gets here it means authentication enabled */
+      /* Check is done in rip_read(). So, just skipping it */
+      if (packet->version == RIPv2 &&
+	  rte == packet->rte &&
+	  rte->family == 0xffff)
+	continue;
+
+      if (ntohs (rte->family) != AF_INET)
+	{
+	  /* Address family check.  RIP only supports AF_INET. */
+	  zlog_info ("Unsupported family %d from %s.",
+		     ntohs (rte->family), inet_ntoa (from->sin_addr));
+	  continue;
+	}
+
+      /* - is the destination address valid (e.g., unicast; not net 0
+         or 127) */
+      if (! rip_destination_check (rte->prefix))
+        {
+	  zlog_info ("Network is net 0 or net 127 or it is not unicast network");
+	  rip_peer_bad_route (from);
+	  continue;
+	} 
+
+      /* Convert metric value to host byte order. */
+      rte->metric = ntohl (rte->metric);
+
+      /* - is the metric valid (i.e., between 1 and 16, inclusive) */
+      if (! (rte->metric >= 1 && rte->metric <= 16))
+	{
+	  zlog_info ("Route's metric is not in the 1-16 range.");
+	  rip_peer_bad_route (from);
+	  continue;
+	}
+
+      /* RIPv1 does not have nexthop value. */
+      if (packet->version == RIPv1 && rte->nexthop.s_addr != 0)
+	{
+	  zlog_info ("RIPv1 packet with nexthop value %s",
+		     inet_ntoa (rte->nexthop));
+	  rip_peer_bad_route (from);
+	  continue;
+	}
+
+      /* That is, if the provided information is ignored, a possibly
+	 sub-optimal, but absolutely valid, route may be taken.  If
+	 the received Next Hop is not directly reachable, it should be
+	 treated as 0.0.0.0. */
+      if (packet->version == RIPv2 && rte->nexthop.s_addr != 0)
+	{
+	  u_int32_t addrval;
+
+	  /* Multicast address check. */
+	  addrval = ntohl (rte->nexthop.s_addr);
+	  if (IN_CLASSD (addrval))
+	    {
+	      zlog_info ("Nexthop %s is multicast address, skip this rte",
+			 inet_ntoa (rte->nexthop));
+	      continue;
+	    }
+
+	  if (! if_lookup_address (rte->nexthop))
+	    {
+	      struct route_node *rn;
+	      struct rip_info *rinfo;
+
+	      rn = route_node_match_ipv4 (rip->table, &rte->nexthop);
+
+	      if (rn)
+		{
+		  rinfo = rn->info;
+
+		  if (rinfo->type == ZEBRA_ROUTE_RIP
+		      && rinfo->sub_type == RIP_ROUTE_RTE)
+		    {
+		      if (IS_RIP_DEBUG_EVENT)
+			zlog_info ("Next hop %s is on RIP network.  Set nexthop to the packet's originator", inet_ntoa (rte->nexthop));
+		      rte->nexthop = rinfo->from;
+		    }
+		  else
+		    {
+		      if (IS_RIP_DEBUG_EVENT)
+			zlog_info ("Next hop %s is not directly reachable. Treat it as 0.0.0.0", inet_ntoa (rte->nexthop));
+		      rte->nexthop.s_addr = 0;
+		    }
+
+		  route_unlock_node (rn);
+		}
+	      else
+		{
+		  if (IS_RIP_DEBUG_EVENT)
+		    zlog_info ("Next hop %s is not directly reachable. Treat it as 0.0.0.0", inet_ntoa (rte->nexthop));
+		  rte->nexthop.s_addr = 0;
+		}
+
+	    }
+	}
+
+     /* For RIPv1, there won't be a valid netmask.  
+
+	This is a best guess at the masks.  If everyone was using old
+	Ciscos before the 'ip subnet zero' option, it would be almost
+	right too :-)
+      
+	Cisco summarize ripv1 advertisments to the classful boundary
+	(/16 for class B's) except when the RIP packet does to inside
+	the classful network in question.  */
+
+      if ((packet->version == RIPv1 && rte->prefix.s_addr != 0) 
+	  || (packet->version == RIPv2 
+	      && (rte->prefix.s_addr != 0 && rte->mask.s_addr == 0)))
+	{
+	  u_int32_t destination;
+
+	  destination = ntohl (rte->prefix.s_addr);
+
+	  if (destination & 0xff) 
+	    {
+	      masklen2ip (32, &rte->mask);
+	    }
+	  else if ((destination & 0xff00) || IN_CLASSC (destination)) 
+	    {
+	      masklen2ip (24, &rte->mask);
+	    }
+	  else if ((destination & 0xff0000) || IN_CLASSB (destination)) 
+	    {
+	      masklen2ip (16, &rte->mask);
+	    }
+	  else 
+	    {
+	      masklen2ip (8, &rte->mask);
+	    }
+	}
+
+      /* In case of RIPv2, if prefix in RTE is not netmask applied one
+         ignore the entry.  */
+      if ((packet->version == RIPv2) 
+	  && (rte->mask.s_addr != 0) 
+	  && ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr))
+	{
+	  zlog_warn ("RIPv2 address %s is not mask /%d applied one",
+		     inet_ntoa (rte->prefix), ip_masklen (rte->mask));
+	  rip_peer_bad_route (from);
+	  continue;
+	}
+
+      /* Default route's netmask is ignored. */
+      if (packet->version == RIPv2
+	  && (rte->prefix.s_addr == 0)
+	  && (rte->mask.s_addr != 0))
+	{
+	  if (IS_RIP_DEBUG_EVENT)
+	    zlog_info ("Default route with non-zero netmask.  Set zero to netmask");
+	  rte->mask.s_addr = 0;
+	}
+	  
+      /* Routing table updates. */
+      rip_rte_process (rte, from, ifp);
+    }
+}
+
+/* RIP packet send to destination address. */
+int
+rip_send_packet (caddr_t buf, int size, struct sockaddr_in *to, 
+		 struct interface *ifp)
+{
+  int ret;
+  struct sockaddr_in sin;
+  int sock;
+
+  /* Make destination address. */
+  memset (&sin, 0, sizeof (struct sockaddr_in));
+  sin.sin_family = AF_INET;
+#ifdef HAVE_SIN_LEN
+  sin.sin_len = sizeof (struct sockaddr_in);
+#endif /* HAVE_SIN_LEN */
+
+  /* When destination is specified, use it's port and address. */
+  if (to)
+    {
+      sock = rip->sock;
+
+      sin.sin_port = to->sin_port;
+      sin.sin_addr = to->sin_addr;
+    }
+  else
+    {
+      sock = socket (AF_INET, SOCK_DGRAM, 0);
+      
+      sockopt_broadcast (sock);
+      sockopt_reuseaddr (sock);
+      sockopt_reuseport (sock);
+
+      sin.sin_port = htons (RIP_PORT_DEFAULT);
+      sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP);
+
+      /* Set multicast interface. */
+      rip_interface_multicast_set (sock, ifp);
+    }
+
+  ret = sendto (sock, buf, size, 0, (struct sockaddr *)&sin,
+		sizeof (struct sockaddr_in));
+
+  if (IS_RIP_DEBUG_EVENT)
+      zlog_info ("SEND to socket %d port %d addr %s",
+                 sock, ntohs (sin.sin_port), inet_ntoa(sin.sin_addr));
+
+  if (ret < 0)
+    zlog_warn ("can't send packet : %s", strerror (errno));
+
+  if (! to)
+    close (sock);
+
+  return ret;
+}
+
+/* Add redistributed route to RIP table. */
+void
+rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, 
+		      unsigned int ifindex, struct in_addr *nexthop)
+{
+  int ret;
+  struct route_node *rp;
+  struct rip_info *rinfo;
+
+  /* Redistribute route  */
+  ret = rip_destination_check (p->prefix);
+  if (! ret)
+    return;
+
+  rp = route_node_get (rip->table, (struct prefix *) p);
+
+  rinfo = rp->info;
+
+  if (rinfo)
+    {
+      if (rinfo->type == ZEBRA_ROUTE_CONNECT 
+	  && rinfo->sub_type == RIP_ROUTE_INTERFACE
+	  && rinfo->metric != RIP_METRIC_INFINITY)
+	{
+	  route_unlock_node (rp);
+	  return;
+	}
+
+      /* Manually configured RIP route check. */
+      if (rinfo->type == ZEBRA_ROUTE_RIP 
+	  && rinfo->sub_type == RIP_ROUTE_STATIC)
+	{
+	  if (type != ZEBRA_ROUTE_RIP || sub_type != RIP_ROUTE_STATIC)
+	    {
+	      route_unlock_node (rp);
+	      return;
+	    }
+	}
+
+      RIP_TIMER_OFF (rinfo->t_timeout);
+      RIP_TIMER_OFF (rinfo->t_garbage_collect);
+
+      if (rip_route_rte (rinfo))
+	rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p, &rinfo->nexthop,
+			       rinfo->metric);
+      rp->info = NULL;
+      rip_info_free (rinfo);
+      
+      route_unlock_node (rp);      
+    }
+
+  rinfo = rip_info_new ();
+    
+  rinfo->type = type;
+  rinfo->sub_type = sub_type;
+  rinfo->ifindex = ifindex;
+  rinfo->metric = 1;
+  rinfo->rp = rp;
+
+  if (nexthop)
+    rinfo->nexthop = *nexthop;
+
+  rinfo->flags |= RIP_RTF_FIB;
+  rp->info = rinfo;
+
+  rinfo->flags |= RIP_RTF_CHANGED;
+
+  rip_event (RIP_TRIGGERED_UPDATE, 0);
+}
+
+/* Delete redistributed route from RIP table. */
+void
+rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p, 
+			   unsigned int ifindex)
+{
+  int ret;
+  struct route_node *rp;
+  struct rip_info *rinfo;
+
+  ret = rip_destination_check (p->prefix);
+  if (! ret)
+    return;
+
+  rp = route_node_lookup (rip->table, (struct prefix *) p);
+  if (rp)
+    {
+      rinfo = rp->info;
+
+      if (rinfo != NULL
+	  && rinfo->type == type 
+	  && rinfo->sub_type == sub_type 
+	  && rinfo->ifindex == ifindex)
+	{
+	  /* Perform poisoned reverse. */
+	  rinfo->metric = RIP_METRIC_INFINITY;
+	  RIP_TIMER_ON (rinfo->t_garbage_collect, 
+			rip_garbage_collect, rip->garbage_time);
+	  RIP_TIMER_OFF (rinfo->t_timeout);
+	  rinfo->flags |= RIP_RTF_CHANGED;
+
+	  rip_event (RIP_TRIGGERED_UPDATE, 0);
+	}
+    }
+}
+
+/* Response to request called from rip_read ().*/
+void
+rip_request_process (struct rip_packet *packet, int size, 
+		     struct sockaddr_in *from, struct interface *ifp)
+{
+  caddr_t lim;
+  struct rte *rte;
+  struct prefix_ipv4 p;
+  struct route_node *rp;
+  struct rip_info *rinfo;
+  struct rip_interface *ri;
+
+  ri = ifp->info;
+
+  /* When passive interface is specified, suppress responses */
+  if (ri->passive)
+    return;
+
+  /* RIP peer update. */
+  rip_peer_update (from, packet->version);
+
+  lim = ((caddr_t) packet) + size;
+  rte = packet->rte;
+
+  /* The Request is processed entry by entry.  If there are no
+     entries, no response is given. */
+  if (lim == (caddr_t) rte)
+    return;
+
+  /* There is one special case.  If there is exactly one entry in the
+     request, and it has an address family identifier of zero and a
+     metric of infinity (i.e., 16), then this is a request to send the
+     entire routing table. */
+  if (lim == ((caddr_t) (rte + 1)) &&
+      ntohs (rte->family) == 0 &&
+      ntohl (rte->metric) == RIP_METRIC_INFINITY)
+    {	
+      /* All route with split horizon */
+      rip_output_process (ifp, from, rip_all_route, packet->version);
+    }
+  else
+    {
+      /* Examine the list of RTEs in the Request one by one.  For each
+	 entry, look up the destination in the router's routing
+	 database and, if there is a route, put that route's metric in
+	 the metric field of the RTE.  If there is no explicit route
+	 to the specified destination, put infinity in the metric
+	 field.  Once all the entries have been filled in, change the
+	 command from Request to Response and send the datagram back
+	 to the requestor. */
+      p.family = AF_INET;
+
+      for (; ((caddr_t) rte) < lim; rte++)
+	{
+	  p.prefix = rte->prefix;
+	  p.prefixlen = ip_masklen (rte->mask);
+	  apply_mask_ipv4 (&p);
+	  
+	  rp = route_node_lookup (rip->table, (struct prefix *) &p);
+	  if (rp)
+	    {
+	      rinfo = rp->info;
+	      rte->metric = htonl (rinfo->metric);
+	      route_unlock_node (rp);
+	    }
+	  else
+	    rte->metric = htonl (RIP_METRIC_INFINITY);
+	}
+      packet->command = RIP_RESPONSE;
+
+      rip_send_packet ((caddr_t) packet, size, from, ifp);
+    }
+  rip_global_queries++;
+}
+
+#if RIP_RECVMSG
+/* Set IPv6 packet info to the socket. */
+static int
+setsockopt_pktinfo (int sock)
+{
+  int ret;
+  int val = 1;
+    
+  ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val));
+  if (ret < 0)
+    zlog_warn ("Can't setsockopt IP_PKTINFO : %s", strerror (errno));
+  return ret;
+}
+
+/* Read RIP packet by recvmsg function. */
+int
+rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from,
+	     int *ifindex)
+{
+  int ret;
+  struct msghdr msg;
+  struct iovec iov;
+  struct cmsghdr *ptr;
+  char adata[1024];
+
+  msg.msg_name = (void *) from;
+  msg.msg_namelen = sizeof (struct sockaddr_in);
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = (void *) adata;
+  msg.msg_controllen = sizeof adata;
+  iov.iov_base = buf;
+  iov.iov_len = size;
+
+  ret = recvmsg (sock, &msg, 0);
+  if (ret < 0)
+    return ret;
+
+  for (ptr = CMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr))
+    if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO) 
+      {
+	struct in_pktinfo *pktinfo;
+	int i;
+
+	pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr);
+	i = pktinfo->ipi_ifindex;
+      }
+  return ret;
+}
+
+/* RIP packet read function. */
+int
+rip_read_new (struct thread *t)
+{
+  int ret;
+  int sock;
+  char buf[RIP_PACKET_MAXSIZ];
+  struct sockaddr_in from;
+  unsigned int ifindex;
+  
+  /* Fetch socket then register myself. */
+  sock = THREAD_FD (t);
+  rip_event (RIP_READ, sock);
+
+  /* Read RIP packet. */
+  ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex);
+  if (ret < 0)
+    {
+      zlog_warn ("Can't read RIP packet: %s", strerror (errno));
+      return ret;
+    }
+
+  return ret;
+}
+#endif /* RIP_RECVMSG */
+
+/* First entry point of RIP packet. */
+int
+rip_read (struct thread *t)
+{
+  int sock;
+  int ret;
+  int rtenum;
+  union rip_buf rip_buf;
+  struct rip_packet *packet;
+  struct sockaddr_in from;
+  int fromlen, len;
+  struct interface *ifp;
+  struct rip_interface *ri;
+
+  /* Fetch socket then register myself. */
+  sock = THREAD_FD (t);
+  rip->t_read = NULL;
+
+  /* Add myself to tne next event */
+  rip_event (RIP_READ, sock);
+
+  /* RIPd manages only IPv4. */
+  memset (&from, 0, sizeof (struct sockaddr_in));
+  fromlen = sizeof (struct sockaddr_in);
+
+  len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0, 
+		  (struct sockaddr *) &from, &fromlen);
+  if (len < 0) 
+    {
+      zlog_info ("recvfrom failed: %s", strerror (errno));
+      return len;
+    }
+
+  /* Check is this packet comming from myself? */
+  if (if_check_address (from.sin_addr)) 
+    {
+      if (IS_RIP_DEBUG_PACKET)
+	zlog_warn ("ignore packet comes from myself");
+      return -1;
+    }
+
+  /* Which interface is this packet comes from. */
+  ifp = if_lookup_address (from.sin_addr);
+
+  /* RIP packet received */
+  if (IS_RIP_DEBUG_EVENT)
+    zlog_info ("RECV packet from %s port %d on %s",
+	       inet_ntoa (from.sin_addr), ntohs (from.sin_port),
+	       ifp ? ifp->name : "unknown");
+
+  /* If this packet come from unknown interface, ignore it. */
+  if (ifp == NULL)
+    {
+      zlog_info ("packet comes from unknown interface");
+      return -1;
+    }
+
+  /* Packet length check. */
+  if (len < RIP_PACKET_MINSIZ)
+    {
+      zlog_warn ("packet size %d is smaller than minimum size %d",
+		 len, RIP_PACKET_MINSIZ);
+      rip_peer_bad_packet (&from);
+      return len;
+    }
+  if (len > RIP_PACKET_MAXSIZ)
+    {
+      zlog_warn ("packet size %d is larger than max size %d",
+		 len, RIP_PACKET_MAXSIZ);
+      rip_peer_bad_packet (&from);
+      return len;
+    }
+
+  /* Packet alignment check. */
+  if ((len - RIP_PACKET_MINSIZ) % 20)
+    {
+      zlog_warn ("packet size %d is wrong for RIP packet alignment", len);
+      rip_peer_bad_packet (&from);
+      return len;
+    }
+
+  /* Set RTE number. */
+  rtenum = ((len - RIP_PACKET_MINSIZ) / 20);
+
+  /* For easy to handle. */
+  packet = &rip_buf.rip_packet;
+
+  /* RIP version check. */
+  if (packet->version == 0)
+    {
+      zlog_info ("version 0 with command %d received.", packet->command);
+      rip_peer_bad_packet (&from);
+      return -1;
+    }
+
+  /* Dump RIP packet. */
+  if (IS_RIP_DEBUG_RECV)
+    rip_packet_dump (packet, len, "RECV");
+
+  /* RIP version adjust.  This code should rethink now.  RFC1058 says
+     that "Version 1 implementations are to ignore this extra data and
+     process only the fields specified in this document.". So RIPv3
+     packet should be treated as RIPv1 ignoring must be zero field. */
+  if (packet->version > RIPv2)
+    packet->version = RIPv2;
+
+  /* Is RIP running or is this RIP neighbor ?*/
+  ri = ifp->info;
+  if (! ri->running && ! rip_neighbor_lookup (&from))
+    {
+      if (IS_RIP_DEBUG_EVENT)
+	zlog_info ("RIP is not enabled on interface %s.", ifp->name);
+      rip_peer_bad_packet (&from);
+      return -1;
+    }
+
+  /* RIP Version check. */
+  if (packet->command == RIP_RESPONSE)
+    {
+      if (ri->ri_receive == RI_RIP_UNSPEC)
+	{
+	  if (packet->version != rip->version) 
+	    {
+	      if (IS_RIP_DEBUG_PACKET)
+		zlog_warn ("  packet's v%d doesn't fit to my version %d", 
+			   packet->version, rip->version);
+	      rip_peer_bad_packet (&from);
+	      return -1;
+	    }
+	}
+      else
+	{
+	  if (packet->version == RIPv1)
+	    if (! (ri->ri_receive & RIPv1))
+	      {
+		if (IS_RIP_DEBUG_PACKET)
+		  zlog_warn ("  packet's v%d doesn't fit to if version spec", 
+			     packet->version);
+		rip_peer_bad_packet (&from);
+		return -1;
+	      }
+	  if (packet->version == RIPv2)
+	    if (! (ri->ri_receive & RIPv2))
+	      {
+		if (IS_RIP_DEBUG_PACKET)
+		  zlog_warn ("  packet's v%d doesn't fit to if version spec", 
+			     packet->version);
+		rip_peer_bad_packet (&from);
+		return -1;
+	      }
+	}
+    }
+
+  /* RFC2453 5.2 If the router is not configured to authenticate RIP-2
+     messages, then RIP-1 and unauthenticated RIP-2 messages will be
+     accepted; authenticated RIP-2 messages shall be discarded.  */
+
+  if ((ri->auth_type == RIP_NO_AUTH) 
+      && rtenum 
+      && (packet->version == RIPv2) && (packet->rte->family == 0xffff))
+    {
+      if (IS_RIP_DEBUG_EVENT)
+	zlog_warn ("packet RIPv%d is dropped because authentication disabled", 
+		   packet->version);
+      rip_peer_bad_packet (&from);
+      return -1;
+    }
+
+  /* If the router is configured to authenticate RIP-2 messages, then
+     RIP-1 messages and RIP-2 messages which pass authentication
+     testing shall be accepted; unauthenticated and failed
+     authentication RIP-2 messages shall be discarded.  For maximum
+     security, RIP-1 messages should be ignored when authentication is
+     in use (see section 4.1); otherwise, the routing information from
+     authenticated messages will be propagated by RIP-1 routers in an
+     unauthenticated manner. */
+
+  if ((ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD 
+       || ri->auth_type == RIP_AUTH_MD5)
+      && rtenum)
+    {
+      /* We follow maximum security. */
+      if (packet->version == RIPv1 && packet->rte->family == 0xffff)
+	{
+	  if (IS_RIP_DEBUG_PACKET)
+	    zlog_warn ("packet RIPv%d is dropped because authentication enabled", packet->version);
+	  rip_peer_bad_packet (&from);
+	  return -1;
+	}
+
+      /* Check RIPv2 authentication. */
+      if (packet->version == RIPv2)
+	{
+	  if (packet->rte->family == 0xffff)
+	    {
+	      if (ntohs (packet->rte->tag) == RIP_AUTH_SIMPLE_PASSWORD)
+                {
+		  ret = rip_auth_simple_password (packet->rte, &from, ifp);
+		  if (! ret)
+		    {
+		      if (IS_RIP_DEBUG_EVENT)
+			zlog_warn ("RIPv2 simple password authentication failed");
+		      rip_peer_bad_packet (&from);
+		      return -1;
+		    }
+		  else
+		    {
+		      if (IS_RIP_DEBUG_EVENT)
+			zlog_info ("RIPv2 simple password authentication success");
+		    }
+                }
+	      else if (ntohs (packet->rte->tag) == RIP_AUTH_MD5)
+                {
+		  ret = rip_auth_md5 (packet, &from, ifp);
+		  if (! ret)
+		    {
+		      if (IS_RIP_DEBUG_EVENT)
+			zlog_warn ("RIPv2 MD5 authentication failed");
+		      rip_peer_bad_packet (&from);
+		      return -1;
+		    }
+		  else
+		    {
+		      if (IS_RIP_DEBUG_EVENT)
+			zlog_info ("RIPv2 MD5 authentication success");
+		    }
+		  /* Reset RIP packet length to trim MD5 data. */
+		  len = ret; 
+                }
+	      else
+		{
+		  if (IS_RIP_DEBUG_EVENT)
+		    zlog_warn ("Unknown authentication type %d",
+			       ntohs (packet->rte->tag));
+		  rip_peer_bad_packet (&from);
+		  return -1;
+		}
+	    }
+	  else
+	    {
+	      /* There is no authentication in the packet. */
+	      if (ri->auth_str || ri->key_chain)
+		{
+		  if (IS_RIP_DEBUG_EVENT)
+		    zlog_warn ("RIPv2 authentication failed: no authentication in packet");
+		  rip_peer_bad_packet (&from);
+		  return -1;
+		}
+	    }
+	}
+    }
+  
+  /* Process each command. */
+  switch (packet->command)
+    {
+    case RIP_RESPONSE:
+      rip_response_process (packet, len, &from, ifp);
+      break;
+    case RIP_REQUEST:
+    case RIP_POLL:
+      rip_request_process (packet, len, &from, ifp);
+      break;
+    case RIP_TRACEON:
+    case RIP_TRACEOFF:
+      zlog_info ("Obsolete command %s received, please sent it to routed", 
+		 lookup (rip_msg, packet->command));
+      rip_peer_bad_packet (&from);
+      break;
+    case RIP_POLL_ENTRY:
+      zlog_info ("Obsolete command %s received", 
+		 lookup (rip_msg, packet->command));
+      rip_peer_bad_packet (&from);
+      break;
+    default:
+      zlog_info ("Unknown RIP command %d received", packet->command);
+      rip_peer_bad_packet (&from);
+      break;
+    }
+
+  return len;
+}
+
+/* Make socket for RIP protocol. */
+int 
+rip_create_socket ()
+{
+  int ret;
+  int sock;
+  struct sockaddr_in addr;
+  struct servent *sp;
+
+  memset (&addr, 0, sizeof (struct sockaddr_in));
+
+  /* Set RIP port. */
+  sp = getservbyname ("router", "udp");
+  if (sp) 
+    addr.sin_port = sp->s_port;
+  else 
+    addr.sin_port = htons (RIP_PORT_DEFAULT);
+
+  /* Address shoud be any address. */
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = INADDR_ANY;
+
+  /* Make datagram socket. */
+  sock = socket (AF_INET, SOCK_DGRAM, 0);
+  if (sock < 0) 
+    {
+      perror ("socket");
+      exit (1);
+    }
+
+  sockopt_broadcast (sock);
+  sockopt_reuseaddr (sock);
+  sockopt_reuseport (sock);
+#ifdef RIP_RECVMSG
+  setsockopt_pktinfo (sock);
+#endif /* RIP_RECVMSG */
+
+  ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr));
+  if (ret < 0)
+    {
+      perror ("bind");
+      return ret;
+    }
+  
+  return sock;
+}
+
+/* Write routing table entry to the stream and return next index of
+   the routing table entry in the stream. */
+int
+rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p,
+	       u_char version, struct rip_info *rinfo, struct interface *ifp)
+{
+  struct in_addr mask;
+  struct rip_interface *ri;
+
+  /* RIP packet header. */
+  if (num == 0)
+    {
+      stream_putc (s, RIP_RESPONSE);
+      stream_putc (s, version);
+      stream_putw (s, 0);
+
+      /* In case of we need RIPv2 authentication. */
+      if (version == RIPv2 && ifp)
+	{
+	  ri = ifp->info;
+	      
+	  if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
+	    {
+	      if (ri->auth_str)
+		{
+		  stream_putw (s, 0xffff);
+		  stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD);
+
+		  memset ((s->data + s->putp), 0, 16);
+		  strncpy ((s->data + s->putp), ri->auth_str, 16);
+		  stream_set_putp (s, s->putp + 16);
+
+		  num++;
+		}
+	      if (ri->key_chain)
+		{
+		  struct keychain *keychain;
+		  struct key *key;
+
+		  keychain = keychain_lookup (ri->key_chain);
+
+		  if (keychain)
+		    {
+		      key = key_lookup_for_send (keychain);
+		      
+		      if (key)
+			{
+			  stream_putw (s, 0xffff);
+			  stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD);
+
+			  memset ((s->data + s->putp), 0, 16);
+			  strncpy ((s->data + s->putp), key->string, 16);
+			  stream_set_putp (s, s->putp + 16);
+
+			  num++;
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+  /* Write routing table entry. */
+  if (version == RIPv1)
+    {
+      stream_putw (s, AF_INET);
+      stream_putw (s, 0);
+      stream_put_ipv4 (s, p->prefix.s_addr);
+      stream_put_ipv4 (s, 0);
+      stream_put_ipv4 (s, 0);
+      stream_putl (s, rinfo->metric_out);
+    }
+  else
+    {
+      masklen2ip (p->prefixlen, &mask);
+
+      stream_putw (s, AF_INET);
+      stream_putw (s, rinfo->tag);
+      stream_put_ipv4 (s, p->prefix.s_addr);
+      stream_put_ipv4 (s, mask.s_addr);
+      stream_put_ipv4 (s, rinfo->nexthop_out.s_addr);
+      stream_putl (s, rinfo->metric_out);
+    }
+
+  return ++num;
+}
+
+/* Send update to the ifp or spcified neighbor. */
+void
+rip_output_process (struct interface *ifp, struct sockaddr_in *to,
+		    int route_type, u_char version)
+{
+  int ret;
+  struct stream *s;
+  struct route_node *rp;
+  struct rip_info *rinfo;
+  struct rip_interface *ri;
+  struct prefix_ipv4 *p;
+  struct prefix_ipv4 classfull;
+  int num;
+  int rtemax;
+
+  /* Logging output event. */
+  if (IS_RIP_DEBUG_EVENT)
+    {
+      if (to)
+	zlog_info ("update routes to neighbor %s", inet_ntoa (to->sin_addr));
+      else
+	zlog_info ("update routes on interface %s ifindex %d",
+		   ifp->name, ifp->ifindex);
+    }
+
+  /* Set output stream. */
+  s = rip->obuf;
+
+  /* Reset stream and RTE counter. */
+  stream_reset (s);
+  num = 0;
+  rtemax = (RIP_PACKET_MAXSIZ - 4) / 20;
+
+  /* Get RIP interface. */
+  ri = ifp->info;
+    
+  /* If output interface is in simple password authentication mode, we
+     need space for authentication data.  */
+  if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
+    rtemax -= 1;
+
+  /* If output interface is in MD5 authentication mode, we need space
+     for authentication header and data. */
+  if (ri->auth_type == RIP_AUTH_MD5)
+    rtemax -= 2;
+
+  /* If output interface is in simple password authentication mode
+     and string or keychain is specified we need space for auth. data */
+  if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
+    {
+      if (ri->key_chain)
+       {
+         struct keychain *keychain;
+
+         keychain = keychain_lookup (ri->key_chain);
+         if (keychain)
+           if (key_lookup_for_send (keychain))
+             rtemax -=1;
+       }
+      else
+       if (ri->auth_str)
+         rtemax -=1;
+    }
+
+  for (rp = route_top (rip->table); rp; rp = route_next (rp))
+    if ((rinfo = rp->info) != NULL)
+      {
+	/* Some inheritance stuff:                                          */
+	/* Before we process with ipv4 prefix we should mask it             */
+	/* with Classful mask if we send RIPv1 packet.That's because        */
+	/* user could set non-classful mask or we could get it by RIPv2     */
+	/* or other protocol. checked with Cisco's way of life :)           */
+	
+	if (version == RIPv1)
+	  {
+	    memcpy (&classfull, &rp->p, sizeof (struct prefix_ipv4));
+
+	    if (IS_RIP_DEBUG_PACKET)
+	      zlog_info("%s/%d before RIPv1 mask check ",
+			inet_ntoa (classfull.prefix), classfull.prefixlen);
+
+	    apply_classful_mask_ipv4 (&classfull);
+	    p = &classfull;
+
+	    if (IS_RIP_DEBUG_PACKET)
+	      zlog_info("%s/%d after RIPv1 mask check",
+			inet_ntoa (p->prefix), p->prefixlen);
+	  }
+	else 
+	  p = (struct prefix_ipv4 *) &rp->p;
+
+	/* Apply output filters. */
+	ret = rip_outgoing_filter (p, ri);
+	if (ret < 0)
+	  continue;
+
+	/* Changed route only output. */
+	if (route_type == rip_changed_route &&
+	    (! (rinfo->flags & RIP_RTF_CHANGED)))
+	  continue;
+
+	/* Split horizon. */
+	/* if (split_horizon == rip_split_horizon) */
+	if (ri->split_horizon)
+	  {
+	    /* We perform split horizon for RIP and connected route. */
+	    if ((rinfo->type == ZEBRA_ROUTE_RIP ||
+		 rinfo->type == ZEBRA_ROUTE_CONNECT) &&
+		rinfo->ifindex == ifp->ifindex)
+	      continue;
+	  }
+
+	/* Preparation for route-map. */
+	rinfo->metric_set = 0;
+	rinfo->nexthop_out.s_addr = 0;
+	rinfo->metric_out = rinfo->metric;
+	rinfo->ifindex_out = ifp->ifindex;
+
+	/* In order to avoid some local loops, if the RIP route has a
+	   nexthop via this interface, keep the nexthop, otherwise set
+	   it to 0. The nexthop should not be propagated beyond the
+	   local broadcast/multicast area in order to avoid an IGP
+	   multi-level recursive look-up.  For RIP and connected
+	   route, we don't set next hop value automatically.  For
+	   settting next hop to those routes, please use
+	   route-map.  */
+
+	if (rinfo->type != ZEBRA_ROUTE_RIP
+	    && rinfo->type != ZEBRA_ROUTE_CONNECT
+	    && rinfo->ifindex == ifp->ifindex)
+	  rinfo->nexthop_out = rinfo->nexthop;
+           
+	/* Apply route map - continue, if deny */
+	if (rip->route_map[rinfo->type].name
+	    && rinfo->sub_type != RIP_ROUTE_INTERFACE)
+	  {
+	    ret = route_map_apply (rip->route_map[rinfo->type].map,
+				   (struct prefix *)p, RMAP_RIP, rinfo);
+
+	    if (ret == RMAP_DENYMATCH) 
+	      {
+		if (IS_RIP_DEBUG_PACKET)
+		  zlog_info ("%s/%d is filtered by route-map",
+			     inet_ntoa (p->prefix), p->prefixlen);
+		continue;
+	      }
+	  }
+
+	/* When route-map does not set metric. */
+	if (! rinfo->metric_set)
+	  {
+	    /* If redistribute metric is set. */
+	    if (rip->route_map[rinfo->type].metric_config
+		&& rinfo->metric != RIP_METRIC_INFINITY)
+	      {
+		rinfo->metric_out = rip->route_map[rinfo->type].metric;
+	      }
+	    else
+	      {
+		/* If the route is not connected or localy generated
+		   one, use default-metric value*/
+		if (rinfo->type != ZEBRA_ROUTE_RIP 
+		    && rinfo->type != ZEBRA_ROUTE_CONNECT
+		    && rinfo->metric != RIP_METRIC_INFINITY)
+		  rinfo->metric_out = rip->default_metric;
+	      }
+	  }
+
+	/* Apply offset-list */
+	if (rinfo->metric != RIP_METRIC_INFINITY)
+	  rip_offset_list_apply_out (p, ifp, &rinfo->metric_out);
+
+	if (rinfo->metric_out > RIP_METRIC_INFINITY)
+	  rinfo->metric_out = RIP_METRIC_INFINITY;
+	  
+	/* Write RTE to the stream. */
+	num = rip_write_rte (num, s, p, version, rinfo, to ? NULL : ifp);
+	if (num == rtemax)
+	  {
+	    if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
+	      rip_auth_md5_set (s, ifp);
+
+	    ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s),
+				   to, ifp);
+
+	    if (ret >= 0 && IS_RIP_DEBUG_SEND)
+	      rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
+			       stream_get_endp(s), "SEND");
+	    num = 0;
+	    stream_reset (s);
+	  }
+      }
+
+  /* Flush unwritten RTE. */
+  if (num != 0)
+    {
+      if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
+	rip_auth_md5_set (s, ifp);
+
+      ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifp);
+
+      if (ret >= 0 && IS_RIP_DEBUG_SEND)
+	rip_packet_dump ((struct rip_packet *)STREAM_DATA (s),
+			 stream_get_endp (s), "SEND");
+      num = 0;
+      stream_reset (s);
+    }
+
+  /* Statistics updates. */
+  ri->sent_updates++;
+}
+
+/* Send RIP packet to the interface. */
+void
+rip_update_interface (struct interface *ifp, u_char version, int route_type)
+{
+  struct prefix_ipv4 *p;
+  struct connected *connected;
+  listnode node;
+  struct sockaddr_in to;
+
+  /* When RIP version is 2 and multicast enable interface. */
+  if (version == RIPv2 && if_is_multicast (ifp)) 
+    {
+      if (IS_RIP_DEBUG_EVENT)
+	zlog_info ("multicast announce on %s ", ifp->name);
+
+      rip_output_process (ifp, NULL, route_type, version);
+      return;
+    }
+
+  /* If we can't send multicast packet, send it with unicast. */
+  if (if_is_broadcast (ifp) || if_is_pointopoint (ifp))
+    {
+      for (node = listhead (ifp->connected); node; nextnode (node))
+	{	    
+	  connected = getdata (node);
+
+	  /* Fetch broadcast address or poin-to-point destination
+             address . */
+	  p = (struct prefix_ipv4 *) connected->destination;
+
+	  if (p->family == AF_INET)
+	    {
+	      /* Destination address and port setting. */
+	      memset (&to, 0, sizeof (struct sockaddr_in));
+	      to.sin_addr = p->prefix;
+	      to.sin_port = htons (RIP_PORT_DEFAULT);
+
+	      if (IS_RIP_DEBUG_EVENT)
+		zlog_info ("%s announce to %s on %s",
+			   if_is_pointopoint (ifp) ? "unicast" : "broadcast",
+			   inet_ntoa (to.sin_addr), ifp->name);
+
+	      rip_output_process (ifp, &to, route_type, version);
+	    }
+	}
+    }
+}
+
+/* Update send to all interface and neighbor. */
+void
+rip_update_process (int route_type)
+{
+  listnode node;
+  struct interface *ifp;
+  struct rip_interface *ri;
+  struct route_node *rp;
+  struct sockaddr_in to;
+  struct prefix_ipv4 *p;
+
+  /* Send RIP update to each interface. */
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+
+      if (if_is_loopback (ifp))
+	continue;
+
+      if (! if_is_up (ifp))
+	continue;
+
+      /* Fetch RIP interface information. */
+      ri = ifp->info;
+
+      /* When passive interface is specified, suppress announce to the
+         interface. */
+      if (ri->passive)
+	continue;
+
+      if (ri->running)
+	{
+	  if (IS_RIP_DEBUG_EVENT) 
+	    {
+	      if (ifp->name) 
+		zlog_info ("SEND UPDATE to %s ifindex %d",
+			   ifp->name, ifp->ifindex);
+	      else
+		zlog_info ("SEND UPDATE to _unknown_ ifindex %d",
+			   ifp->ifindex);
+	    }
+
+	  /* If there is no version configuration in the interface,
+             use rip's version setting. */
+	  if (ri->ri_send == RI_RIP_UNSPEC)
+	    {
+	      if (rip->version == RIPv1)
+		rip_update_interface (ifp, RIPv1, route_type);
+	      else
+		rip_update_interface (ifp, RIPv2, route_type);
+	    }
+	  /* If interface has RIP version configuration use it. */
+	  else
+	    {
+	      if (ri->ri_send & RIPv1)
+		rip_update_interface (ifp, RIPv1, route_type);
+	      if (ri->ri_send & RIPv2)
+		rip_update_interface (ifp, RIPv2, route_type);
+	    }
+	}
+    }
+
+  /* RIP send updates to each neighbor. */
+  for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
+    if (rp->info != NULL)
+      {
+	p = (struct prefix_ipv4 *) &rp->p;
+
+	ifp = if_lookup_address (p->prefix);
+	if (! ifp)
+	  {
+	    zlog_warn ("Neighbor %s doesn't exist direct connected network",
+		       inet_ntoa (p->prefix));
+	    continue;
+	  }
+
+	/* Set destination address and port */
+	memset (&to, 0, sizeof (struct sockaddr_in));
+	to.sin_addr = p->prefix;
+	to.sin_port = htons (RIP_PORT_DEFAULT);
+
+	/* RIP version is rip's configuration. */
+	rip_output_process (ifp, &to, route_type, rip->version);
+      }
+}
+
+/* RIP's periodical timer. */
+int
+rip_update (struct thread *t)
+{
+  /* Clear timer pointer. */
+  rip->t_update = NULL;
+
+  if (IS_RIP_DEBUG_EVENT)
+    zlog_info ("update timer fire!");
+
+  /* Process update output. */
+  rip_update_process (rip_all_route);
+
+  /* Triggered updates may be suppressed if a regular update is due by
+     the time the triggered update would be sent. */
+  if (rip->t_triggered_interval)
+    {
+      thread_cancel (rip->t_triggered_interval);
+      rip->t_triggered_interval = NULL;
+    }
+  rip->trigger = 0;
+
+  /* Register myself. */
+  rip_event (RIP_UPDATE_EVENT, 0);
+
+  return 0;
+}
+
+/* Walk down the RIP routing table then clear changed flag. */
+void
+rip_clear_changed_flag ()
+{
+  struct route_node *rp;
+  struct rip_info *rinfo;
+
+  for (rp = route_top (rip->table); rp; rp = route_next (rp))
+    if ((rinfo = rp->info) != NULL)
+      if (rinfo->flags & RIP_RTF_CHANGED)
+	rinfo->flags &= ~RIP_RTF_CHANGED;
+}
+
+/* Triggered update interval timer. */
+int
+rip_triggered_interval (struct thread *t)
+{
+  int rip_triggered_update (struct thread *);
+
+  rip->t_triggered_interval = NULL;
+
+  if (rip->trigger)
+    {
+      rip->trigger = 0;
+      rip_triggered_update (t);
+    }
+  return 0;
+}     
+
+/* Execute triggered update. */
+int
+rip_triggered_update (struct thread *t)
+{
+  int interval;
+
+  /* Clear thred pointer. */
+  rip->t_triggered_update = NULL;
+
+  /* Cancel interval timer. */
+  if (rip->t_triggered_interval)
+    {
+      thread_cancel (rip->t_triggered_interval);
+      rip->t_triggered_interval = NULL;
+    }
+  rip->trigger = 0;
+
+  /* Logging triggered update. */
+  if (IS_RIP_DEBUG_EVENT)
+    zlog_info ("triggered update!");
+
+  /* Split Horizon processing is done when generating triggered
+     updates as well as normal updates (see section 2.6). */
+  rip_update_process (rip_changed_route);
+
+  /* Once all of the triggered updates have been generated, the route
+     change flags should be cleared. */
+  rip_clear_changed_flag ();
+
+  /* After a triggered update is sent, a timer should be set for a
+   random interval between 1 and 5 seconds.  If other changes that
+   would trigger updates occur before the timer expires, a single
+   update is triggered when the timer expires. */
+  interval = (random () % 5) + 1;
+
+  rip->t_triggered_interval = 
+    thread_add_timer (master, rip_triggered_interval, NULL, interval);
+
+  return 0;
+}
+
+/* Withdraw redistributed route. */
+void
+rip_redistribute_withdraw (int type)
+{
+  struct route_node *rp;
+  struct rip_info *rinfo;
+
+  if (!rip)
+    return;
+
+  for (rp = route_top (rip->table); rp; rp = route_next (rp))
+    if ((rinfo = rp->info) != NULL)
+      {
+	if (rinfo->type == type
+	    && rinfo->sub_type != RIP_ROUTE_INTERFACE)
+	  {
+	    /* Perform poisoned reverse. */
+	    rinfo->metric = RIP_METRIC_INFINITY;
+	    RIP_TIMER_ON (rinfo->t_garbage_collect, 
+			  rip_garbage_collect, rip->garbage_time);
+	    RIP_TIMER_OFF (rinfo->t_timeout);
+	    rinfo->flags |= RIP_RTF_CHANGED;
+
+	    rip_event (RIP_TRIGGERED_UPDATE, 0);
+	  }
+      }
+}
+
+/* Create new RIP instance and set it to global variable. */
+int
+rip_create ()
+{
+  rip = XMALLOC (MTYPE_RIP, sizeof (struct rip));
+  memset (rip, 0, sizeof (struct rip));
+
+  /* Set initial value. */
+  rip->version = RIPv2;
+  rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
+  rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
+  rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
+  rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
+
+  /* Initialize RIP routig table. */
+  rip->table = route_table_init ();
+  rip->route = route_table_init ();
+  rip->neighbor = route_table_init ();
+
+  /* Make output stream. */
+  rip->obuf = stream_new (1500);
+
+  /* Make socket. */
+  rip->sock = rip_create_socket ();
+  if (rip->sock < 0)
+    return rip->sock;
+
+  /* Create read and timer thread. */
+  rip_event (RIP_READ, rip->sock);
+  rip_event (RIP_UPDATE_EVENT, 1);
+
+  return 0;
+}
+
+/* Sned RIP request to the destination. */
+int
+rip_request_send (struct sockaddr_in *to, struct interface *ifp,
+		  u_char version)
+{
+  struct rte *rte;
+  struct rip_packet rip_packet;
+
+  memset (&rip_packet, 0, sizeof (rip_packet));
+
+  rip_packet.command = RIP_REQUEST;
+  rip_packet.version = version;
+  rte = rip_packet.rte;
+  rte->metric = htonl (RIP_METRIC_INFINITY);
+
+  return rip_send_packet ((caddr_t) &rip_packet, sizeof (rip_packet), to, ifp);
+}
+
+int
+rip_update_jitter (unsigned long time)
+{
+  return ((rand () % (time + 1)) - (time / 2));
+}
+
+void
+rip_event (enum rip_event event, int sock)
+{
+  int jitter = 0;
+
+  switch (event)
+    {
+    case RIP_READ:
+      rip->t_read = thread_add_read (master, rip_read, NULL, sock);
+      break;
+    case RIP_UPDATE_EVENT:
+      if (rip->t_update)
+	{
+	  thread_cancel (rip->t_update);
+	  rip->t_update = NULL;
+	}
+      jitter = rip_update_jitter (rip->update_time);
+      rip->t_update = 
+	thread_add_timer (master, rip_update, NULL, 
+			  sock ? 2 : rip->update_time + jitter);
+      break;
+    case RIP_TRIGGERED_UPDATE:
+      if (rip->t_triggered_interval)
+	rip->trigger = 1;
+      else if (! rip->t_triggered_update)
+	rip->t_triggered_update = 
+	  thread_add_event (master, rip_triggered_update, NULL, 0);
+      break;
+    default:
+      break;
+    }
+}
+
+DEFUN (router_rip,
+       router_rip_cmd,
+       "router rip",
+       "Enable a routing process\n"
+       "Routing Information Protocol (RIP)\n")
+{
+  int ret;
+
+  /* If rip is not enabled before. */
+  if (! rip)
+    {
+      ret = rip_create ();
+      if (ret < 0)
+	{
+	  zlog_info ("Can't create RIP");
+	  return CMD_WARNING;
+	}
+    }
+  vty->node = RIP_NODE;
+  vty->index = rip;
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_router_rip,
+       no_router_rip_cmd,
+       "no router rip",
+       NO_STR
+       "Enable a routing process\n"
+       "Routing Information Protocol (RIP)\n")
+{
+  if (rip)
+    rip_clean ();
+  return CMD_SUCCESS;
+}
+
+DEFUN (rip_version,
+       rip_version_cmd,
+       "version <1-2>",
+       "Set routing protocol version\n"
+       "version\n")
+{
+  int version;
+
+  version = atoi (argv[0]);
+  if (version != RIPv1 && version != RIPv2)
+    {
+      vty_out (vty, "invalid rip version %d%s", version,
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  rip->version = version;
+
+  return CMD_SUCCESS;
+} 
+
+DEFUN (no_rip_version,
+       no_rip_version_cmd,
+       "no version",
+       NO_STR
+       "Set routing protocol version\n")
+{
+  /* Set RIP version to the default. */
+  rip->version = RIPv2;
+
+  return CMD_SUCCESS;
+} 
+
+ALIAS (no_rip_version,
+       no_rip_version_val_cmd,
+       "no version <1-2>",
+       NO_STR
+       "Set routing protocol version\n"
+       "version\n")
+
+DEFUN (rip_route,
+       rip_route_cmd,
+       "route A.B.C.D/M",
+       "RIP static route configuration\n"
+       "IP prefix <network>/<length>\n")
+{
+  int ret;
+  struct prefix_ipv4 p;
+  struct route_node *node;
+
+  ret = str2prefix_ipv4 (argv[0], &p);
+  if (ret < 0)
+    {
+      vty_out (vty, "Malformed address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  apply_mask_ipv4 (&p);
+
+  /* For router rip configuration. */
+  node = route_node_get (rip->route, (struct prefix *) &p);
+
+  if (node->info)
+    {
+      vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
+      route_unlock_node (node);
+      return CMD_WARNING;
+    }
+
+  node->info = "static";
+
+  rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_route,
+       no_rip_route_cmd,
+       "no route A.B.C.D/M",
+       NO_STR
+       "RIP static route configuration\n"
+       "IP prefix <network>/<length>\n")
+{
+  int ret;
+  struct prefix_ipv4 p;
+  struct route_node *node;
+
+  ret = str2prefix_ipv4 (argv[0], &p);
+  if (ret < 0)
+    {
+      vty_out (vty, "Malformed address%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  apply_mask_ipv4 (&p);
+
+  /* For router rip configuration. */
+  node = route_node_lookup (rip->route, (struct prefix *) &p);
+  if (! node)
+    {
+      vty_out (vty, "Can't find route %s.%s", argv[0],
+	       VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
+  route_unlock_node (node);
+
+  node->info = NULL;
+  route_unlock_node (node);
+
+  return CMD_SUCCESS;
+}
+
+void
+rip_update_default_metric ()
+{
+  struct route_node *np;
+  struct rip_info *rinfo;
+
+  for (np = route_top (rip->table); np; np = route_next (np))
+    if ((rinfo = np->info) != NULL)
+      if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT)
+        rinfo->metric = rip->default_metric;
+}
+
+DEFUN (rip_default_metric,
+       rip_default_metric_cmd,
+       "default-metric <1-16>",
+       "Set a metric of redistribute routes\n"
+       "Default metric\n")
+{
+  if (rip)
+    {
+      rip->default_metric = atoi (argv[0]);
+      /* rip_update_default_metric (); */
+    }
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_default_metric,
+       no_rip_default_metric_cmd,
+       "no default-metric",
+       NO_STR
+       "Set a metric of redistribute routes\n"
+       "Default metric\n")
+{
+  if (rip)
+    {
+      rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT;
+      /* rip_update_default_metric (); */
+    }
+  return CMD_SUCCESS;
+}
+
+ALIAS (no_rip_default_metric,
+       no_rip_default_metric_val_cmd,
+       "no default-metric <1-16>",
+       NO_STR
+       "Set a metric of redistribute routes\n"
+       "Default metric\n")
+
+DEFUN (rip_timers,
+       rip_timers_cmd,
+       "timers basic <5-2147483647> <5-2147483647> <5-2147483647>",
+       "Adjust routing timers\n"
+       "Basic routing protocol update timers\n"
+       "Routing table update timer value in second. Default is 30.\n"
+       "Routing information timeout timer. Default is 180.\n"
+       "Garbage collection timer. Default is 120.\n")
+{
+  unsigned long update;
+  unsigned long timeout;
+  unsigned long garbage;
+  char *endptr = NULL;
+  unsigned long RIP_TIMER_MAX = 2147483647;
+  unsigned long RIP_TIMER_MIN = 5;
+
+  update = strtoul (argv[0], &endptr, 10);
+  if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0')  
+    {
+      vty_out (vty, "update timer value error%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  
+  timeout = strtoul (argv[1], &endptr, 10);
+  if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0') 
+    {
+      vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  
+  garbage = strtoul (argv[2], &endptr, 10);
+  if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0') 
+    {
+      vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  /* Set each timer value. */
+  rip->update_time = update;
+  rip->timeout_time = timeout;
+  rip->garbage_time = garbage;
+
+  /* Reset update timer thread. */
+  rip_event (RIP_UPDATE_EVENT, 0);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_timers,
+       no_rip_timers_cmd,
+       "no timers basic",
+       NO_STR
+       "Adjust routing timers\n"
+       "Basic routing protocol update timers\n")
+{
+  /* Set each timer value to the default. */
+  rip->update_time = RIP_UPDATE_TIMER_DEFAULT;
+  rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT;
+  rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT;
+
+  /* Reset update timer thread. */
+  rip_event (RIP_UPDATE_EVENT, 0);
+
+  return CMD_SUCCESS;
+}
+
+struct route_table *rip_distance_table;
+
+struct rip_distance
+{
+  /* Distance value for the IP source prefix. */
+  u_char distance;
+
+  /* Name of the access-list to be matched. */
+  char *access_list;
+};
+
+struct rip_distance *
+rip_distance_new ()
+{
+  struct rip_distance *new;
+  new = XMALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance));
+  memset (new, 0, sizeof (struct rip_distance));
+  return new;
+}
+
+void
+rip_distance_free (struct rip_distance *rdistance)
+{
+  XFREE (MTYPE_RIP_DISTANCE, rdistance);
+}
+
+int
+rip_distance_set (struct vty *vty, char *distance_str, char *ip_str,
+		  char *access_list_str)
+{
+  int ret;
+  struct prefix_ipv4 p;
+  u_char distance;
+  struct route_node *rn;
+  struct rip_distance *rdistance;
+
+  ret = str2prefix_ipv4 (ip_str, &p);
+  if (ret == 0)
+    {
+      vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  distance = atoi (distance_str);
+
+  /* Get RIP distance node. */
+  rn = route_node_get (rip_distance_table, (struct prefix *) &p);
+  if (rn->info)
+    {
+      rdistance = rn->info;
+      route_unlock_node (rn);
+    }
+  else
+    {
+      rdistance = rip_distance_new ();
+      rn->info = rdistance;
+    }
+
+  /* Set distance value. */
+  rdistance->distance = distance;
+
+  /* Reset access-list configuration. */
+  if (rdistance->access_list)
+    {
+      free (rdistance->access_list);
+      rdistance->access_list = NULL;
+    }
+  if (access_list_str)
+    rdistance->access_list = strdup (access_list_str);
+
+  return CMD_SUCCESS;
+}
+
+int
+rip_distance_unset (struct vty *vty, char *distance_str, char *ip_str,
+		    char *access_list_str)
+{
+  int ret;
+  struct prefix_ipv4 p;
+  u_char distance;
+  struct route_node *rn;
+  struct rip_distance *rdistance;
+
+  ret = str2prefix_ipv4 (ip_str, &p);
+  if (ret == 0)
+    {
+      vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  distance = atoi (distance_str);
+
+  rn = route_node_lookup (rip_distance_table, (struct prefix *)&p);
+  if (! rn)
+    {
+      vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  rdistance = rn->info;
+
+  if (rdistance->access_list)
+    free (rdistance->access_list);
+  rip_distance_free (rdistance);
+
+  rn->info = NULL;
+  route_unlock_node (rn);
+  route_unlock_node (rn);
+
+  return CMD_SUCCESS;
+}
+
+void
+rip_distance_reset ()
+{
+  struct route_node *rn;
+  struct rip_distance *rdistance;
+
+  for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
+    if ((rdistance = rn->info) != NULL)
+      {
+	if (rdistance->access_list)
+	  free (rdistance->access_list);
+	rip_distance_free (rdistance);
+	rn->info = NULL;
+	route_unlock_node (rn);
+      }
+}
+
+/* Apply RIP information to distance method. */
+u_char
+rip_distance_apply (struct rip_info *rinfo)
+{
+  struct route_node *rn;
+  struct prefix_ipv4 p;
+  struct rip_distance *rdistance;
+  struct access_list *alist;
+
+  if (! rip)
+    return 0;
+
+  memset (&p, 0, sizeof (struct prefix_ipv4));
+  p.family = AF_INET;
+  p.prefix = rinfo->from;
+  p.prefixlen = IPV4_MAX_BITLEN;
+
+  /* Check source address. */
+  rn = route_node_match (rip_distance_table, (struct prefix *) &p);
+  if (rn)
+    {
+      rdistance = rn->info;
+      route_unlock_node (rn);
+
+      if (rdistance->access_list)
+	{
+	  alist = access_list_lookup (AFI_IP, rdistance->access_list);
+	  if (alist == NULL)
+	    return 0;
+	  if (access_list_apply (alist, &rinfo->rp->p) == FILTER_DENY)
+	    return 0;
+
+	  return rdistance->distance;
+	}
+      else
+	return rdistance->distance;
+    }
+
+  if (rip->distance)
+    return rip->distance;
+
+  return 0;
+}
+
+void
+rip_distance_show (struct vty *vty)
+{
+  struct route_node *rn;
+  struct rip_distance *rdistance;
+  int header = 1;
+  char buf[BUFSIZ];
+  
+  vty_out (vty, "  Distance: (default is %d)%s",
+	   rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT,
+	   VTY_NEWLINE);
+
+  for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
+    if ((rdistance = rn->info) != NULL)
+      {
+	if (header)
+	  {
+	    vty_out (vty, "    Address           Distance  List%s",
+		     VTY_NEWLINE);
+	    header = 0;
+	  }
+	sprintf (buf, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen);
+	vty_out (vty, "    %-20s  %4d  %s%s",
+		 buf, rdistance->distance,
+		 rdistance->access_list ? rdistance->access_list : "",
+		 VTY_NEWLINE);
+      }
+}
+
+DEFUN (rip_distance,
+       rip_distance_cmd,
+       "distance <1-255>",
+       "Administrative distance\n"
+       "Distance value\n")
+{
+  rip->distance = atoi (argv[0]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_distance,
+       no_rip_distance_cmd,
+       "no distance <1-255>",
+       NO_STR
+       "Administrative distance\n"
+       "Distance value\n")
+{
+  rip->distance = 0;
+  return CMD_SUCCESS;
+}
+
+DEFUN (rip_distance_source,
+       rip_distance_source_cmd,
+       "distance <1-255> A.B.C.D/M",
+       "Administrative distance\n"
+       "Distance value\n"
+       "IP source prefix\n")
+{
+  rip_distance_set (vty, argv[0], argv[1], NULL);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_distance_source,
+       no_rip_distance_source_cmd,
+       "no distance <1-255> A.B.C.D/M",
+       NO_STR
+       "Administrative distance\n"
+       "Distance value\n"
+       "IP source prefix\n")
+{
+  rip_distance_unset (vty, argv[0], argv[1], NULL);
+  return CMD_SUCCESS;
+}
+
+DEFUN (rip_distance_source_access_list,
+       rip_distance_source_access_list_cmd,
+       "distance <1-255> A.B.C.D/M WORD",
+       "Administrative distance\n"
+       "Distance value\n"
+       "IP source prefix\n"
+       "Access list name\n")
+{
+  rip_distance_set (vty, argv[0], argv[1], argv[2]);
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_rip_distance_source_access_list,
+       no_rip_distance_source_access_list_cmd,
+       "no distance <1-255> A.B.C.D/M WORD",
+       NO_STR
+       "Administrative distance\n"
+       "Distance value\n"
+       "IP source prefix\n"
+       "Access list name\n")
+{
+  rip_distance_unset (vty, argv[0], argv[1], argv[2]);
+  return CMD_SUCCESS;
+}
+
+/* Print out routes update time. */
+void
+rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo)
+{
+  struct timeval timer_now;
+  time_t clock;
+  struct tm *tm;
+#define TIME_BUF 25
+  char timebuf [TIME_BUF];
+  struct thread *thread;
+
+  gettimeofday (&timer_now, NULL);
+
+  if ((thread = rinfo->t_timeout) != NULL)
+    {
+      clock = thread->u.sands.tv_sec - timer_now.tv_sec;
+      tm = gmtime (&clock);
+      strftime (timebuf, TIME_BUF, "%M:%S", tm);
+      vty_out (vty, "%5s", timebuf);
+    }
+  else if ((thread = rinfo->t_garbage_collect) != NULL)
+    {
+      clock = thread->u.sands.tv_sec - timer_now.tv_sec;
+      tm = gmtime (&clock);
+      strftime (timebuf, TIME_BUF, "%M:%S", tm);
+      vty_out (vty, "%5s", timebuf);
+    }
+}
+
+char *
+rip_route_type_print (int sub_type)
+{
+  switch (sub_type)
+    {
+      case RIP_ROUTE_RTE:
+	return "n";
+      case RIP_ROUTE_STATIC:
+	return "s";
+      case RIP_ROUTE_DEFAULT:
+	return "d";
+      case RIP_ROUTE_REDISTRIBUTE:
+	return "r";
+      case RIP_ROUTE_INTERFACE:
+	return "i";
+      default:
+	return "?";
+    }
+}
+
+DEFUN (show_ip_rip,
+       show_ip_rip_cmd,
+       "show ip rip",
+       SHOW_STR
+       IP_STR
+       "Show RIP routes\n")
+{
+  struct route_node *np;
+  struct rip_info *rinfo;
+
+  if (! rip)
+    return CMD_SUCCESS;
+
+  vty_out (vty, "Codes: R - RIP, C - connected, O - OSPF, B - BGP%s"
+	   "      (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
+	   "      (i) - interface%s%s"
+	   "     Network            Next Hop         Metric From            Time%s",
+	   VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
+  
+  for (np = route_top (rip->table); np; np = route_next (np))
+    if ((rinfo = np->info) != NULL)
+      {
+	int len;
+
+	len = vty_out (vty, "%s(%s) %s/%d",
+		       /* np->lock, For debugging. */
+		       route_info[rinfo->type].str,
+		       rip_route_type_print (rinfo->sub_type),
+		       inet_ntoa (np->p.u.prefix4), np->p.prefixlen);
+	
+	len = 24 - len;
+
+	if (len > 0)
+	  vty_out (vty, "%*s", len, " ");
+
+        if (rinfo->nexthop.s_addr) 
+	  vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop),
+		   rinfo->metric);
+        else
+	  vty_out (vty, "0.0.0.0              %2d ", rinfo->metric);
+
+	/* Route which exist in kernel routing table. */
+	if ((rinfo->type == ZEBRA_ROUTE_RIP) && 
+	    (rinfo->sub_type == RIP_ROUTE_RTE))
+	  {
+	    vty_out (vty, "%-15s ", inet_ntoa (rinfo->from));
+	    rip_vty_out_uptime (vty, rinfo);
+	  }
+	else if (rinfo->metric == RIP_METRIC_INFINITY)
+	  {
+	    vty_out (vty, "self            ");
+	    rip_vty_out_uptime (vty, rinfo);
+	  }
+	else
+	  vty_out (vty, "self");
+
+	vty_out (vty, "%s", VTY_NEWLINE);
+      }
+  return CMD_SUCCESS;
+}
+
+/* Return next event time. */
+int
+rip_next_thread_timer (struct thread *thread)
+{
+  struct timeval timer_now;
+
+  gettimeofday (&timer_now, NULL);
+
+  return thread->u.sands.tv_sec - timer_now.tv_sec;
+}
+
+DEFUN (show_ip_protocols_rip,
+       show_ip_protocols_rip_cmd,
+       "show ip protocols",
+       SHOW_STR
+       IP_STR
+       "IP routing protocol process parameters and statistics\n")
+{
+  listnode node;
+  struct interface *ifp;
+  struct rip_interface *ri;
+  extern struct message ri_version_msg[];
+  char *send_version;
+  char *receive_version;
+
+  if (! rip)
+    return CMD_SUCCESS;
+
+  vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE);
+  vty_out (vty, "  Sending updates every %ld seconds with +/-50%%,",
+	   rip->update_time);
+  vty_out (vty, " next due in %d seconds%s", 
+	   rip_next_thread_timer (rip->t_update),
+	   VTY_NEWLINE);
+  vty_out (vty, "  Timeout after %ld seconds,", rip->timeout_time);
+  vty_out (vty, " garbage collect after %ld seconds%s", rip->garbage_time,
+	   VTY_NEWLINE);
+
+  /* Filtering status show. */
+  config_show_distribute (vty);
+		 
+  /* Default metric information. */
+  vty_out (vty, "  Default redistribution metric is %d%s",
+	   rip->default_metric, VTY_NEWLINE);
+
+  /* Redistribute information. */
+  vty_out (vty, "  Redistributing:");
+  config_write_rip_redistribute (vty, 0);
+  vty_out (vty, "%s", VTY_NEWLINE);
+
+  vty_out (vty, "  Default version control: send version %d,", rip->version);
+  vty_out (vty, " receive version %d %s", rip->version,
+	   VTY_NEWLINE);
+
+  vty_out (vty, "    Interface        Send  Recv   Key-chain%s", VTY_NEWLINE);
+
+  for (node = listhead (iflist); node; node = nextnode (node))
+    {
+      ifp = getdata (node);
+      ri = ifp->info;
+
+      if (ri->enable_network || ri->enable_interface)
+	{
+	  if (ri->ri_send == RI_RIP_UNSPEC)
+	    send_version = lookup (ri_version_msg, rip->version);
+	  else
+	    send_version = lookup (ri_version_msg, ri->ri_send);
+
+	  if (ri->ri_receive == RI_RIP_UNSPEC)
+	    receive_version = lookup (ri_version_msg, rip->version);
+	  else
+	    receive_version = lookup (ri_version_msg, ri->ri_receive);
+	
+	  vty_out (vty, "    %-17s%-3s   %-3s    %s%s", ifp->name,
+		   send_version,
+		   receive_version,
+		   ri->key_chain ? ri->key_chain : "",
+		   VTY_NEWLINE);
+	}
+    }
+
+  vty_out (vty, "  Routing for Networks:%s", VTY_NEWLINE);
+  config_write_rip_network (vty, 0);  
+
+  vty_out (vty, "  Routing Information Sources:%s", VTY_NEWLINE);
+  vty_out (vty, "    Gateway          BadPackets BadRoutes  Distance Last Update%s", VTY_NEWLINE);
+  rip_peer_display (vty);
+
+  rip_distance_show (vty);
+
+  return CMD_SUCCESS;
+}
+
+/* RIP configuration write function. */
+int
+config_write_rip (struct vty *vty)
+{
+  int write = 0;
+  struct route_node *rn;
+  struct rip_distance *rdistance;
+
+  if (rip)
+    {
+      /* Router RIP statement. */
+      vty_out (vty, "router rip%s", VTY_NEWLINE);
+      write++;
+  
+      /* RIP version statement.  Default is RIP version 2. */
+      if (rip->version != RIPv2)
+	vty_out (vty, " version %d%s", rip->version,
+		 VTY_NEWLINE);
+ 
+      /* RIP timer configuration. */
+      if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT 
+	  || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT 
+	  || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT)
+	vty_out (vty, " timers basic %lu %lu %lu%s",
+		 rip->update_time,
+		 rip->timeout_time,
+		 rip->garbage_time,
+		 VTY_NEWLINE);
+
+      /* Default information configuration. */
+      if (rip->default_information)
+	{
+	  if (rip->default_information_route_map)
+	    vty_out (vty, " default-information originate route-map %s%s",
+		     rip->default_information_route_map, VTY_NEWLINE);
+	  else
+	    vty_out (vty, " default-information originate%s",
+		     VTY_NEWLINE);
+	}
+
+      /* Redistribute configuration. */
+      config_write_rip_redistribute (vty, 1);
+
+      /* RIP offset-list configuration. */
+      config_write_rip_offset_list (vty);
+
+      /* RIP enabled network and interface configuration. */
+      config_write_rip_network (vty, 1);
+			
+      /* RIP default metric configuration */
+      if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT)
+        vty_out (vty, " default-metric %d%s",
+		 rip->default_metric, VTY_NEWLINE);
+
+      /* Distribute configuration. */
+      write += config_write_distribute (vty);
+
+      /* Distance configuration. */
+      if (rip->distance)
+	vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE);
+
+      /* RIP source IP prefix distance configuration. */
+      for (rn = route_top (rip_distance_table); rn; rn = route_next (rn))
+	if ((rdistance = rn->info) != NULL)
+	  vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance,
+		   inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen,
+		   rdistance->access_list ? rdistance->access_list : "",
+		   VTY_NEWLINE);
+
+      /* RIP static route configuration. */
+      for (rn = route_top (rip->route); rn; rn = route_next (rn))
+	if (rn->info)
+	  vty_out (vty, " route %s/%d%s", 
+		   inet_ntoa (rn->p.u.prefix4),
+		   rn->p.prefixlen,
+		   VTY_NEWLINE);
+
+    }
+  return write;
+}
+
+/* RIP node structure. */
+struct cmd_node rip_node =
+{
+  RIP_NODE,
+  "%s(config-router)# ",
+  1
+};
+
+/* Distribute-list update functions. */
+void
+rip_distribute_update (struct distribute *dist)
+{
+  struct interface *ifp;
+  struct rip_interface *ri;
+  struct access_list *alist;
+  struct prefix_list *plist;
+
+  if (! dist->ifname)
+    return;
+
+  ifp = if_lookup_by_name (dist->ifname);
+  if (ifp == NULL)
+    return;
+
+  ri = ifp->info;
+
+  if (dist->list[DISTRIBUTE_IN])
+    {
+      alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]);
+      if (alist)
+	ri->list[RIP_FILTER_IN] = alist;
+      else
+	ri->list[RIP_FILTER_IN] = NULL;
+    }
+  else
+    ri->list[RIP_FILTER_IN] = NULL;
+
+  if (dist->list[DISTRIBUTE_OUT])
+    {
+      alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]);
+      if (alist)
+	ri->list[RIP_FILTER_OUT] = alist;
+      else
+	ri->list[RIP_FILTER_OUT] = NULL;
+    }
+  else
+    ri->list[RIP_FILTER_OUT] = NULL;
+
+  if (dist->prefix[DISTRIBUTE_IN])
+    {
+      plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]);
+      if (plist)
+	ri->prefix[RIP_FILTER_IN] = plist;
+      else
+	ri->prefix[RIP_FILTER_IN] = NULL;
+    }
+  else
+    ri->prefix[RIP_FILTER_IN] = NULL;
+
+  if (dist->prefix[DISTRIBUTE_OUT])
+    {
+      plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]);
+      if (plist)
+	ri->prefix[RIP_FILTER_OUT] = plist;
+      else
+	ri->prefix[RIP_FILTER_OUT] = NULL;
+    }
+  else
+    ri->prefix[RIP_FILTER_OUT] = NULL;
+}
+
+void
+rip_distribute_update_interface (struct interface *ifp)
+{
+  struct distribute *dist;
+
+  dist = distribute_lookup (ifp->name);
+  if (dist)
+    rip_distribute_update (dist);
+}
+
+/* Update all interface's distribute list. */
+void
+rip_distribute_update_all ()
+{
+  struct interface *ifp;
+  listnode node;
+
+  for (node = listhead (iflist); node; nextnode (node))
+    {
+      ifp = getdata (node);
+      rip_distribute_update_interface (ifp);
+    }
+}
+
+/* Delete all added rip route. */
+void
+rip_clean ()
+{
+  int i;
+  struct route_node *rp;
+  struct rip_info *rinfo;
+
+  if (rip)
+    {
+      /* Clear RIP routes */
+      for (rp = route_top (rip->table); rp; rp = route_next (rp))
+	if ((rinfo = rp->info) != NULL)
+	  {
+	    if (rinfo->type == ZEBRA_ROUTE_RIP &&
+		rinfo->sub_type == RIP_ROUTE_RTE)
+	      rip_zebra_ipv4_delete ((struct prefix_ipv4 *)&rp->p,
+				     &rinfo->nexthop, rinfo->metric);
+	
+	    RIP_TIMER_OFF (rinfo->t_timeout);
+	    RIP_TIMER_OFF (rinfo->t_garbage_collect);
+
+	    rp->info = NULL;
+	    route_unlock_node (rp);
+
+	    rip_info_free (rinfo);
+	  }
+
+      /* Cancel RIP related timers. */
+      RIP_TIMER_OFF (rip->t_update);
+      RIP_TIMER_OFF (rip->t_triggered_update);
+      RIP_TIMER_OFF (rip->t_triggered_interval);
+
+      /* Cancel read thread. */
+      if (rip->t_read)
+	{
+	  thread_cancel (rip->t_read);
+	  rip->t_read = NULL;
+	}
+
+      /* Close RIP socket. */
+      if (rip->sock >= 0)
+	{
+	  close (rip->sock);
+	  rip->sock = -1;
+	}
+
+      /* Static RIP route configuration. */
+      for (rp = route_top (rip->route); rp; rp = route_next (rp))
+	if (rp->info)
+	  {
+	    rp->info = NULL;
+	    route_unlock_node (rp);
+	  }
+
+      /* RIP neighbor configuration. */
+      for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
+	if (rp->info)
+	  {
+	    rp->info = NULL;
+	    route_unlock_node (rp);
+	  }
+
+      /* Redistribute related clear. */
+      if (rip->default_information_route_map)
+	free (rip->default_information_route_map);
+
+      for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+	if (rip->route_map[i].name)
+	  free (rip->route_map[i].name);
+
+      XFREE (MTYPE_ROUTE_TABLE, rip->table);
+      XFREE (MTYPE_ROUTE_TABLE, rip->route);
+      XFREE (MTYPE_ROUTE_TABLE, rip->neighbor);
+      
+      XFREE (MTYPE_RIP, rip);
+      rip = NULL;
+    }
+
+  rip_clean_network ();
+  rip_passive_interface_clean ();
+  rip_offset_clean ();
+  rip_interface_clean ();
+  rip_distance_reset ();
+  rip_redistribute_clean ();
+}
+
+/* Reset all values to the default settings. */
+void
+rip_reset ()
+{
+  /* Reset global counters. */
+  rip_global_route_changes = 0;
+  rip_global_queries = 0;
+
+  /* Call ripd related reset functions. */
+  rip_debug_reset ();
+  rip_route_map_reset ();
+
+  /* Call library reset functions. */
+  vty_reset ();
+  access_list_reset ();
+  prefix_list_reset ();
+
+  distribute_list_reset ();
+
+  rip_interface_reset ();
+  rip_distance_reset ();
+
+  rip_zclient_reset ();
+}
+
+/* Allocate new rip structure and set default value. */
+void
+rip_init ()
+{
+  /* Randomize for triggered update random(). */
+  srand (time (NULL));
+
+  /* Install top nodes. */
+  install_node (&rip_node, config_write_rip);
+
+  /* Install rip commands. */
+  install_element (VIEW_NODE, &show_ip_rip_cmd);
+  install_element (VIEW_NODE, &show_ip_protocols_rip_cmd);
+  install_element (ENABLE_NODE, &show_ip_rip_cmd);
+  install_element (ENABLE_NODE, &show_ip_protocols_rip_cmd);
+  install_element (CONFIG_NODE, &router_rip_cmd);
+  install_element (CONFIG_NODE, &no_router_rip_cmd);
+
+  install_default (RIP_NODE);
+  install_element (RIP_NODE, &rip_version_cmd);
+  install_element (RIP_NODE, &no_rip_version_cmd);
+  install_element (RIP_NODE, &no_rip_version_val_cmd);
+  install_element (RIP_NODE, &rip_default_metric_cmd);
+  install_element (RIP_NODE, &no_rip_default_metric_cmd);
+  install_element (RIP_NODE, &no_rip_default_metric_val_cmd);
+  install_element (RIP_NODE, &rip_timers_cmd);
+  install_element (RIP_NODE, &no_rip_timers_cmd);
+  install_element (RIP_NODE, &rip_route_cmd);
+  install_element (RIP_NODE, &no_rip_route_cmd);
+  install_element (RIP_NODE, &rip_distance_cmd);
+  install_element (RIP_NODE, &no_rip_distance_cmd);
+  install_element (RIP_NODE, &rip_distance_source_cmd);
+  install_element (RIP_NODE, &no_rip_distance_source_cmd);
+  install_element (RIP_NODE, &rip_distance_source_access_list_cmd);
+  install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd);
+
+  /* Debug related init. */
+  rip_debug_init ();
+
+  /* Filter related init. */
+  rip_route_map_init ();
+  rip_offset_init ();
+
+  /* SNMP init. */
+#ifdef HAVE_SNMP
+  rip_snmp_init ();
+#endif /* HAVE_SNMP */
+
+  /* Access list install. */
+  access_list_init ();
+  access_list_add_hook (rip_distribute_update_all);
+  access_list_delete_hook (rip_distribute_update_all);
+
+  /* Prefix list initialize.*/
+  prefix_list_init ();
+  prefix_list_add_hook (rip_distribute_update_all);
+  prefix_list_delete_hook (rip_distribute_update_all);
+
+  /* Distribute list install. */
+  distribute_list_init (RIP_NODE);
+  distribute_list_add_hook (rip_distribute_update);
+  distribute_list_delete_hook (rip_distribute_update);
+
+  /* Distance control. */
+  rip_distance_table = route_table_init ();
+}
diff --git a/ripd/ripd.conf.sample b/ripd/ripd.conf.sample
new file mode 100644
index 0000000..2902ff9
--- /dev/null
+++ b/ripd/ripd.conf.sample
@@ -0,0 +1,24 @@
+! -*- rip -*-
+!
+! RIPd sample configuration file
+!
+! $Id: ripd.conf.sample,v 1.1 2002/12/13 20:15:30 paul Exp $
+!
+hostname ripd
+password zebra
+!
+! debug rip events
+! debug rip packet
+!
+router rip
+! network 11.0.0.0/8
+! network eth0
+! route 10.0.0.0/8
+! distribute-list private-only in eth0
+!
+!access-list private-only permit 10.0.0.0/8
+!access-list private-only deny any
+! 
+!log file ripd.log
+!
+log stdout
diff --git a/ripd/ripd.h b/ripd/ripd.h
new file mode 100644
index 0000000..2545db0
--- /dev/null
+++ b/ripd/ripd.h
@@ -0,0 +1,408 @@
+/* RIP related values and structures.
+ * Copyright (C) 1997, 1998, 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_RIP_H
+#define _ZEBRA_RIP_H
+
+/* RIP version number. */
+#define RIPv1                            1
+#define RIPv2                            2
+
+/* RIP command list. */
+#define RIP_REQUEST                      1
+#define RIP_RESPONSE                     2
+#define RIP_TRACEON                      3	/* Obsolete */
+#define RIP_TRACEOFF                     4	/* Obsolete */
+#define RIP_POLL                         5
+#define RIP_POLL_ENTRY                   6
+#define RIP_COMMAND_MAX                  7
+
+/* RIP metric infinity value.*/
+#define RIP_METRIC_INFINITY             16
+
+/* Normal RIP packet min and max size. */
+#define RIP_PACKET_MINSIZ                4
+#define RIP_PACKET_MAXSIZ              512
+
+#define RIP_HEADER_SIZE                  4
+#define RIP_RTE_SIZE                    20
+
+/* Max count of routing table entry in one rip packet. */
+#define RIP_MAX_RTE                     25
+
+/* RIP version 2 multicast address. */
+#ifndef INADDR_RIP_GROUP
+#define INADDR_RIP_GROUP        0xe0000009    /* 224.0.0.9 */
+#endif
+
+/* RIP timers */
+#define RIP_UPDATE_TIMER_DEFAULT        30
+#define RIP_TIMEOUT_TIMER_DEFAULT      180
+#define RIP_GARBAGE_TIMER_DEFAULT      120
+
+/* RIP peer timeout value. */
+#define RIP_PEER_TIMER_DEFAULT         180
+
+/* RIP port number. */
+#define RIP_PORT_DEFAULT               520
+#define RIP_VTY_PORT                  2602
+#define RIP_VTYSH_PATH        "/tmp/.ripd"
+
+/* Default configuration file name. */
+#define RIPD_DEFAULT_CONFIG    "ripd.conf"
+
+/* RIP route types. */
+#define RIP_ROUTE_RTE                    0
+#define RIP_ROUTE_STATIC                 1
+#define RIP_ROUTE_DEFAULT                2
+#define RIP_ROUTE_REDISTRIBUTE           3
+#define RIP_ROUTE_INTERFACE              4
+
+/* RIP MD5 authentication. */
+#define RIP_AUTH_MD5_SIZE               16
+
+/* RIP structure. */
+struct rip 
+{
+  /* RIP socket. */
+  int sock;
+
+  /* Default version of rip instance. */
+  u_char version;
+
+  /* Output buffer of RIP. */
+  struct stream *obuf;
+
+  /* RIP routing information base. */
+  struct route_table *table;
+
+  /* RIP only static routing information. */
+  struct route_table *route;
+  
+  /* RIP neighbor. */
+  struct route_table *neighbor;
+  
+  /* RIP threads. */
+  struct thread *t_read;
+
+  /* Update and garbage timer. */
+  struct thread *t_update;
+
+  /* Triggered update hack. */
+  int trigger;
+  struct thread *t_triggered_update;
+  struct thread *t_triggered_interval;
+
+  /* RIP timer values. */
+  unsigned long update_time;
+  unsigned long timeout_time;
+  unsigned long garbage_time;
+
+  /* RIP default metric. */
+  int default_metric;
+
+  /* RIP default-information originate. */
+  u_char default_information;
+  char *default_information_route_map;
+
+  /* RIP default distance. */
+  u_char distance;
+  struct route_table *distance_table;
+
+  /* For redistribute route map. */
+  struct
+  {
+    char *name;
+    struct route_map *map;
+    int metric_config;
+    u_int32_t metric;
+  } route_map[ZEBRA_ROUTE_MAX];
+};
+
+/* RIP routing table entry which belong to rip_packet. */
+struct rte
+{
+  u_int16_t family;		/* Address family of this route. */
+  u_int16_t tag;		/* Route Tag which included in RIP2 packet. */
+  struct in_addr prefix;	/* Prefix of rip route. */
+  struct in_addr mask;		/* Netmask of rip route. */
+  struct in_addr nexthop;	/* Next hop of rip route. */
+  u_int32_t metric;		/* Metric value of rip route. */
+};
+
+/* RIP packet structure. */
+struct rip_packet
+{
+  unsigned char command;	/* Command type of RIP packet. */
+  unsigned char version;	/* RIP version which coming from peer. */
+  unsigned char pad1;		/* Padding of RIP packet header. */
+  unsigned char pad2;		/* Same as above. */
+  struct rte rte[1];		/* Address structure. */
+};
+
+/* Buffer to read RIP packet. */
+union rip_buf
+{
+  struct rip_packet rip_packet;
+  char buf[RIP_PACKET_MAXSIZ];
+};
+
+/* RIP route information. */
+struct rip_info
+{
+  /* This route's type. */
+  int type;
+
+  /* Sub type. */
+  int sub_type;
+
+  /* RIP nexthop. */
+  struct in_addr nexthop;
+  struct in_addr from;
+
+  /* Which interface does this route come from. */
+  unsigned int ifindex;
+
+  /* Metric of this route. */
+  u_int32_t metric;
+
+  /* Tag information of this route. */
+  u_int16_t tag;
+
+  /* Flags of RIP route. */
+#define RIP_RTF_FIB      1
+#define RIP_RTF_CHANGED  2
+  u_char flags;
+
+  /* Garbage collect timer. */
+  struct thread *t_timeout;
+  struct thread *t_garbage_collect;
+
+  /* Route-map futures - this variables can be changed. */
+  struct in_addr nexthop_out;
+  u_char metric_set;
+  u_int32_t metric_out;
+  unsigned int ifindex_out;
+
+  struct route_node *rp;
+
+  u_char distance;
+
+#ifdef NEW_RIP_TABLE
+  struct rip_info *next;
+  struct rip_info *prev;
+#endif /* NEW_RIP_TABLE */
+};
+
+/* RIP specific interface configuration. */
+struct rip_interface
+{
+  /* RIP is enabled on this interface. */
+  int enable_network;
+  int enable_interface;
+
+  /* RIP is running on this interface. */
+  int running;
+
+  /* RIP version control. */
+  int ri_send;
+  int ri_receive;
+
+  /* RIPv2 authentication type. */
+#define RIP_NO_AUTH                0
+#define RIP_AUTH_DATA              1
+#define RIP_AUTH_SIMPLE_PASSWORD   2
+#define RIP_AUTH_MD5               3
+  int auth_type;
+
+  /* RIPv2 authentication string. */
+  char *auth_str;
+
+  /* RIPv2 authentication key chain. */
+  char *key_chain;
+
+  /* Split horizon flag. */
+  int split_horizon;
+  int split_horizon_default;
+
+  /* For filter type slot. */
+#define RIP_FILTER_IN  0
+#define RIP_FILTER_OUT 1
+#define RIP_FILTER_MAX 2
+
+  /* Access-list. */
+  struct access_list *list[RIP_FILTER_MAX];
+
+  /* Prefix-list. */
+  struct prefix_list *prefix[RIP_FILTER_MAX];
+
+  /* Wake up thread. */
+  struct thread *t_wakeup;
+
+  /* Interface statistics. */
+  int recv_badpackets;
+  int recv_badroutes;
+  int sent_updates;
+
+  /* Passive interface. */
+  int passive;
+};
+
+/* RIP peer information. */
+struct rip_peer
+{
+  /* Peer address. */
+  struct in_addr addr;
+
+  /* Peer RIP tag value. */
+  int domain;
+
+  /* Last update time. */
+  time_t uptime;
+
+  /* Peer RIP version. */
+  u_char version;
+
+  /* Statistics. */
+  int recv_badpackets;
+  int recv_badroutes;
+
+  /* Timeout thread. */
+  struct thread *t_timeout;
+};
+
+struct rip_md5_info
+{
+  u_int16_t family;
+  u_int16_t type;
+  u_int16_t packet_len;
+  u_char keyid;
+  u_char auth_len;
+  u_int32_t sequence;
+  u_int32_t reserv1;
+  u_int32_t reserv2;
+};
+
+struct rip_md5_data
+{
+  u_int16_t family;
+  u_int16_t type;
+  u_char digest[16];
+};
+
+/* RIP accepet/announce methods. */
+#define RI_RIP_UNSPEC                      0
+#define RI_RIP_VERSION_1                   1
+#define RI_RIP_VERSION_2                   2
+#define RI_RIP_VERSION_1_AND_2             3
+
+/* Default value for "default-metric" command. */
+#define RIP_DEFAULT_METRIC_DEFAULT         1
+
+/* RIP event. */
+enum rip_event 
+{
+  RIP_READ,
+  RIP_UPDATE_EVENT,
+  RIP_TRIGGERED_UPDATE,
+};
+
+/* Macro for timer turn on. */
+#define RIP_TIMER_ON(T,F,V) \
+  do { \
+    if (!(T)) \
+      (T) = thread_add_timer (master, (F), rinfo, (V)); \
+  } while (0)
+
+/* Macro for timer turn off. */
+#define RIP_TIMER_OFF(X) \
+  do { \
+    if (X) \
+      { \
+        thread_cancel (X); \
+        (X) = NULL; \
+      } \
+  } while (0)
+
+/* Prototypes. */
+void rip_init ();
+void rip_reset ();
+void rip_clean ();
+void rip_clean_network ();
+void rip_interface_clean ();
+void rip_interface_reset ();
+void rip_passive_interface_clean ();
+void rip_if_init ();
+void rip_if_down_all ();
+void rip_route_map_init ();
+void rip_route_map_reset ();
+void rip_snmp_init ();
+void rip_zclient_init ();
+void rip_zclient_start ();
+void rip_zclient_reset ();
+void rip_offset_init ();
+int if_check_address (struct in_addr addr);
+int if_valid_neighbor (struct in_addr addr);
+
+int rip_request_send (struct sockaddr_in *, struct interface *, u_char);
+int rip_neighbor_lookup (struct sockaddr_in *);
+void rip_redistribute_add (int, int, struct prefix_ipv4 *, unsigned int, 
+			   struct in_addr *);
+void rip_redistribute_delete (int, int, struct prefix_ipv4 *, unsigned int);
+void rip_redistribute_withdraw (int);
+void rip_zebra_ipv4_add (struct prefix_ipv4 *, struct in_addr *, u_int32_t, u_char);
+void rip_zebra_ipv4_delete (struct prefix_ipv4 *, struct in_addr *, u_int32_t);
+void rip_interface_multicast_set (int, struct interface *);
+void rip_distribute_update_interface (struct interface *);
+
+int config_write_rip_network (struct vty *, int);
+int config_write_rip_offset_list (struct vty *);
+int config_write_rip_redistribute (struct vty *, int);
+
+void rip_peer_init ();
+void rip_peer_update (struct sockaddr_in *, u_char);
+void rip_peer_bad_route (struct sockaddr_in *);
+void rip_peer_bad_packet (struct sockaddr_in *);
+void rip_peer_display (struct vty *);
+struct rip_peer *rip_peer_lookup (struct in_addr *);
+struct rip_peer *rip_peer_lookup_next (struct in_addr *);
+
+int rip_offset_list_apply_in (struct prefix_ipv4 *, struct interface *, u_int32_t *);
+int rip_offset_list_apply_out (struct prefix_ipv4 *, struct interface *, u_int32_t *);
+void rip_offset_clean ();
+
+void rip_info_free (struct rip_info *);
+u_char rip_distance_apply (struct rip_info *);
+void rip_redistribute_clean ();
+void rip_ifaddr_add (struct interface *, struct connected *);
+void rip_ifaddr_delete (struct interface *, struct connected *);
+
+/* There is only one rip strucutre. */
+extern struct rip *rip;
+
+/* Master thread strucutre. */
+extern struct thread_master *master;
+
+/* RIP statistics for SNMP. */
+extern long rip_global_route_changes;
+extern long rip_global_queries;
+
+#endif /* _ZEBRA_RIP_H */