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 */