1998-07-09 19:39:04 +00:00
/*
* Rest in pieces - RIP protocol
*
1999-05-11 09:53:45 +00:00
* Copyright ( c ) 1998 , 1999 Pavel Machek < pavel @ ucw . cz >
2004-07-13 20:53:56 +00:00
* 2004 Ondrej Filip < feela @ network . cz >
1998-07-09 19:39:04 +00:00
*
* Can be freely distributed and used under the terms of the GNU GPL .
1999-10-11 14:19:29 +00:00
*
2013-02-26 13:29:53 +00:00
FIXME : IPv6 support : packet size
2013-02-23 23:43:08 +00:00
FIXME : ( nonurgent ) IPv6 support : receive " route using " blocks
FIXME : ( nonurgent ) IPv6 support : generate " nexthop " blocks
2013-02-26 13:29:53 +00:00
next hops are only advisory , and they are pretty ugly in IPv6 .
2000-04-26 11:33:03 +00:00
I suggest just forgetting about them .
1999-11-25 13:38:25 +00:00
2004-06-23 23:59:48 +00:00
FIXME : ( nonurgent ) : fold rip_connection into rip_interface ?
1999-11-10 11:52:36 +00:00
1999-12-08 12:51:45 +00:00
FIXME : propagation of metric = infinity into main routing table may or may not be good idea .
1998-07-09 19:39:04 +00:00
*/
2000-04-30 18:47:48 +00:00
/**
2000-06-07 13:25:53 +00:00
* DOC : Routing Information Protocol
2000-04-30 18:47:48 +00:00
*
2000-06-07 13:25:53 +00:00
* RIP is a pretty simple protocol , so about a half of its code is interface
* with the core .
2000-06-05 17:13:36 +00:00
*
2000-06-07 13:25:53 +00:00
* We maintain our own linked list of & rip_entry structures - - it serves
* as our small routing table . RIP never adds to this linked list upon
* packet reception ; instead , it lets the core know about data from the packet
2010-09-03 15:15:02 +00:00
* and waits for the core to call rip_rt_notify ( ) .
2000-06-07 13:25:53 +00:00
*
* Within rip_tx ( ) , the list is
* walked and a packet is generated using rip_tx_prepare ( ) . This gets
2000-04-30 18:47:48 +00:00
* tricky because we may need to send more than one packet to one
2000-06-07 13:25:53 +00:00
* destination . Struct & rip_connection is used to hold context information such as how
* many of & rip_entry ' s we have already sent and it ' s also used to protect
* against two concurrent sends to one destination . Each & rip_interface has
2000-04-30 18:47:48 +00:00
* at most one & rip_connection .
*
2000-05-04 20:08:34 +00:00
* We are not going to honor requests for sending part of
2000-06-07 13:25:53 +00:00
* routing table . That would need to turn split horizon off etc .
2000-04-30 18:47:48 +00:00
*
2000-06-07 13:25:53 +00:00
* About triggered updates , RFC says : when a triggered update was sent ,
* don ' t send a new one for something between 1 and 5 seconds ( and send one
* after that ) . We do something else : each 5 seconds ,
2000-04-30 18:47:48 +00:00
* we look for any changed routes and broadcast them .
*/
2000-05-16 15:08:52 +00:00
# undef LOCAL_DEBUG
2013-02-26 13:29:53 +00:00
# define LOCAL_DEBUG 1
1998-07-09 19:39:04 +00:00
# include "nest/bird.h"
# include "nest/iface.h"
# include "nest/protocol.h"
# include "nest/route.h"
# include "lib/socket.h"
# include "lib/resource.h"
# include "lib/lists.h"
# include "lib/timer.h"
2000-03-31 23:30:21 +00:00
# include "lib/string.h"
1998-07-09 19:39:04 +00:00
# include "rip.h"
1999-02-15 13:34:43 +00:00
# define P ((struct rip_proto *) p)
# define P_CF ((struct rip_proto_config *)p->cf)
2013-09-16 21:57:40 +00:00
# undef TRACE
2000-03-09 16:38:51 +00:00
# define TRACE(level, msg, args...) do { if (p->debug & level) { log(L_TRACE "%s: " msg, p->name , ## args); } } while(0)
2000-03-09 15:12:41 +00:00
1999-05-31 20:30:16 +00:00
static struct rip_interface * new_iface ( struct proto * p , struct iface * new , unsigned long flags , struct iface_patt * patt ) ;
2012-06-25 00:56:09 +00:00
static inline int rip_is_old ( struct proto * p )
{ return p - > proto = = & proto_rip ; }
static inline int rip_is_ng ( struct proto * p )
{ return p - > proto = = & proto_ripng ; }
2000-06-05 17:13:36 +00:00
/*
2000-06-07 13:25:53 +00:00
* Output processing
2000-06-05 12:52:57 +00:00
*
* This part is responsible for getting packets out to the network .
1998-07-28 21:44:11 +00:00
*/
static void
rip_tx_err ( sock * s , int err )
{
2003-12-06 16:41:11 +00:00
struct rip_connection * c = ( ( struct rip_interface * ) ( s - > data ) ) - > busy ;
1998-07-28 21:44:11 +00:00
struct proto * p = c - > proto ;
2004-06-23 23:59:48 +00:00
log ( L_ERR " %s: Unexpected error at rip transmit: %M " , p - > name , err ) ;
1998-07-28 21:44:11 +00:00
}
2000-06-05 17:13:36 +00:00
/*
2000-06-05 12:52:57 +00:00
* rip_tx_prepare :
* @ e : rip entry that needs to be translated to form suitable for network
* @ b : block to be filled
*
* Fill one rip block with info that needs to go to the network . Handle
* nexthop and split horizont correctly . ( Next hop is ignored for IPv6 ,
* that could be fixed but it is not real problem ) .
*/
2000-04-26 11:07:57 +00:00
static int
2012-06-25 00:56:09 +00:00
rip_tx_prepare ( struct proto * p , struct rip_block * block , struct rip_entry * e , struct rip_interface * rif , int pos )
1999-11-25 13:38:25 +00:00
{
2012-06-25 00:56:09 +00:00
int split = neigh_connected_to ( p , & e - > whotoldme , rif - > iface ) ;
int nh_ok = neigh_connected_to ( p , & e - > nexthop , rif - > iface ) ;
int metric = split ? P_CF - > infinity : e - > metric ;
if ( rip_is_old ( p ) ) {
/* RIPv2 */
struct rip_block_v2 * b = ( void * ) block ;
b - > afi = htons ( AF_INET ) ;
b - > tag = htons ( e - > tag ) ;
b - > network = ip4_hton ( ipa_to_ip4 ( e - > n . prefix ) ) ;
b - > netmask = ip4_hton ( ip4_mkmask ( e - > n . pxlen ) ) ;
b - > nexthop = nh_ok ? ip4_hton ( ipa_to_ip4 ( e - > nexthop ) ) : IP4_NONE ;
b - > metric = htonl ( metric ) ;
2000-06-07 13:58:49 +00:00
2012-06-25 00:56:09 +00:00
} else {
/* RIPng */
struct rip_block_ng * b = ( void * ) block ;
b - > network = ip6_hton ( e - > n . prefix ) ;
b - > tag = htons ( e - > tag ) ;
b - > pxlen = e - > n . pxlen ;
b - > metric = metric ;
}
2000-04-26 11:07:57 +00:00
return pos + 1 ;
1999-11-25 13:38:25 +00:00
}
2000-06-05 17:13:36 +00:00
/*
2000-06-05 12:52:57 +00:00
* rip_tx - send one rip packet to the network
*/
1998-07-28 21:44:11 +00:00
static void
rip_tx ( sock * s )
{
1998-10-26 15:35:19 +00:00
struct rip_interface * rif = s - > data ;
struct rip_connection * c = rif - > busy ;
1998-07-28 21:44:11 +00:00
struct proto * p = c - > proto ;
struct rip_packet * packet = ( void * ) s - > tbuf ;
1999-11-25 14:54:08 +00:00
int i , packetlen ;
2000-04-26 11:07:57 +00:00
int maxi , nullupdate = 1 ;
1998-07-28 21:44:11 +00:00
1999-10-02 10:44:48 +00:00
DBG ( " Sending to %I \n " , s - > daddr ) ;
1998-12-22 19:41:04 +00:00
do {
1998-07-28 21:44:11 +00:00
2000-03-23 12:08:40 +00:00
if ( c - > done )
goto done ;
1998-07-28 21:44:11 +00:00
1998-12-22 19:41:04 +00:00
DBG ( " Preparing packet to send: " ) ;
packet - > heading . command = RIPCMD_RESPONSE ;
packet - > heading . unused = 0 ;
1999-05-11 09:53:45 +00:00
i = ! ! P_CF - > authtype ;
2012-06-25 00:56:09 +00:00
if ( rip_is_old ( p ) ) {
packet - > heading . version = 2 ;
maxi = ( ( P_CF - > authtype = = AT_MD5 ) ? PACKET_MD5_MAX : PACKET_MAX ) ;
} else {
/* RIPng has independent version numbering */
packet - > heading . version = 1 ;
maxi = 5 ; /* FIXME: This is some nonsense? */
}
2000-04-26 11:07:57 +00:00
1998-12-22 19:41:04 +00:00
FIB_ITERATE_START ( & P - > rtable , & c - > iter , z ) {
struct rip_entry * e = ( struct rip_entry * ) z ;
2013-02-23 23:43:08 +00:00
if ( ! rif - > triggered | | ( ! ( e - > updated < now - 2 ) ) ) { /* FIXME: Should be probably 1 or some different algorithm */
2000-04-26 11:07:57 +00:00
nullupdate = 0 ;
2004-06-05 09:27:49 +00:00
i = rip_tx_prepare ( p , packet - > block + i , e , rif , i ) ;
2000-04-26 11:07:57 +00:00
if ( i > = maxi ) {
1999-12-01 13:44:42 +00:00
FIB_ITERATE_PUT ( & c - > iter , z ) ;
goto break_loop ;
}
1998-12-22 19:41:04 +00:00
}
1999-02-13 19:14:16 +00:00
} FIB_ITERATE_END ( z ) ;
1998-12-22 19:41:04 +00:00
c - > done = 1 ;
break_loop :
1999-11-25 14:54:08 +00:00
packetlen = rip_outgoing_authentication ( p , ( void * ) & packet - > block [ 0 ] , packet , i ) ;
1999-05-11 09:53:45 +00:00
1998-12-22 19:41:04 +00:00
DBG ( " , sending %d blocks, " , i ) ;
2000-04-26 11:07:57 +00:00
if ( nullupdate ) {
2000-01-26 14:12:18 +00:00
DBG ( " not sending NULL update \n " ) ;
2000-03-22 14:26:03 +00:00
c - > done = 1 ;
2000-03-23 12:08:40 +00:00
goto done ;
2000-01-26 14:12:18 +00:00
}
2000-03-23 12:08:40 +00:00
if ( ipa_nonzero ( c - > daddr ) )
i = sk_send_to ( s , packetlen , c - > daddr , c - > dport ) ;
else
i = sk_send ( s , packetlen ) ;
1998-07-28 21:44:11 +00:00
1998-12-09 20:08:57 +00:00
DBG ( " it wants more \n " ) ;
1998-07-28 21:44:11 +00:00
1998-12-22 19:41:04 +00:00
} while ( i > 0 ) ;
if ( i < 0 ) rip_tx_err ( s , i ) ;
1998-12-09 20:08:57 +00:00
DBG ( " blocked \n " ) ;
1999-11-25 13:38:25 +00:00
return ;
2000-03-23 12:08:40 +00:00
done :
DBG ( " Looks like I'm " ) ;
c - > rif - > busy = NULL ;
rem_node ( NODE c ) ;
mb_free ( c ) ;
DBG ( " done \n " ) ;
return ;
1998-07-28 21:44:11 +00:00
}
2000-06-05 17:13:36 +00:00
/*
2000-06-05 12:52:57 +00:00
* rip_sendto - send whole routing table to selected destination
* @ rif : interface to use . Notice that we lock interface so that at
* most one send to one interface is done .
*/
1998-07-28 21:44:11 +00:00
static void
1998-10-26 15:35:19 +00:00
rip_sendto ( struct proto * p , ip_addr daddr , int dport , struct rip_interface * rif )
1998-07-28 21:44:11 +00:00
{
1998-10-26 15:35:19 +00:00
struct iface * iface = rif - > iface ;
2000-03-26 18:01:27 +00:00
struct rip_connection * c ;
1998-07-28 21:44:11 +00:00
static int num = 0 ;
1998-10-26 15:35:19 +00:00
if ( rif - > busy ) {
2004-06-23 23:59:48 +00:00
log ( L_WARN " %s: Interface %s is much too slow, dropping request " , p - > name , iface - > name ) ;
1998-10-26 15:35:19 +00:00
return ;
}
2000-03-26 18:01:27 +00:00
c = mb_alloc ( p - > pool , sizeof ( struct rip_connection ) ) ;
1998-10-26 15:35:19 +00:00
rif - > busy = c ;
1998-10-20 16:45:53 +00:00
1998-07-28 21:44:11 +00:00
c - > addr = daddr ;
c - > proto = p ;
c - > num = num + + ;
1998-10-26 15:35:19 +00:00
c - > rif = rif ;
1998-07-28 21:44:11 +00:00
1998-10-26 15:35:19 +00:00
c - > dport = dport ;
c - > daddr = daddr ;
if ( c - > rif - > sock - > data ! = rif )
1998-12-20 14:29:06 +00:00
bug ( " not enough send magic " ) ;
1998-07-28 21:44:11 +00:00
1998-12-22 19:41:04 +00:00
c - > done = 0 ;
2000-05-11 15:05:13 +00:00
FIB_ITERATE_INIT ( & c - > iter , & P - > rtable ) ;
1998-07-28 21:44:11 +00:00
add_head ( & P - > connections , NODE c ) ;
2000-05-11 15:05:13 +00:00
if ( ipa_nonzero ( daddr ) )
TRACE ( D_PACKETS , " Sending my routing table to %I:%d on %s " , daddr , dport , rif - > iface - > name ) ;
else
TRACE ( D_PACKETS , " Broadcasting routing table to %s " , rif - > iface - > name ) ;
1998-07-28 21:44:11 +00:00
1998-10-26 15:35:19 +00:00
rip_tx ( c - > rif - > sock ) ;
1998-07-28 21:44:11 +00:00
}
1999-03-17 10:20:23 +00:00
static struct rip_interface *
1998-12-04 11:45:51 +00:00
find_interface ( struct proto * p , struct iface * what )
{
struct rip_interface * i ;
1998-12-09 20:08:57 +00:00
1998-12-04 11:45:51 +00:00
WALK_LIST ( i , P - > interfaces )
if ( i - > iface = = what )
return i ;
return NULL ;
}
2000-06-05 17:13:36 +00:00
/*
2000-06-07 13:25:53 +00:00
* Input processing
2000-06-05 12:52:57 +00:00
*
* This part is responsible for any updates that come from network
1998-07-28 21:44:11 +00:00
*/
2012-08-14 14:25:22 +00:00
static int rip_rte_better ( struct rte * new , struct rte * old ) ;
2000-05-10 12:23:06 +00:00
static void
rip_rte_update_if_better ( rtable * tab , net * net , struct proto * p , rte * new )
{
rte * old ;
2012-08-14 14:25:22 +00:00
old = rte_find ( net , p - > main_source ) ;
if ( ! old | | rip_rte_better ( new , old ) | |
2004-06-23 21:36:55 +00:00
( ipa_equal ( old - > attrs - > from , new - > attrs - > from ) & &
( old - > u . rip . metric ! = new - > u . rip . metric ) ) )
2012-08-14 14:25:22 +00:00
rte_update ( p , net , new ) ;
2010-09-03 14:32:00 +00:00
else
rte_free ( new ) ;
2000-05-10 12:23:06 +00:00
}
2000-06-05 17:13:36 +00:00
/*
2012-06-25 00:56:09 +00:00
* process_block - let main routing table know about our new entry
2000-06-05 12:52:57 +00:00
* @ b : entry in network format
*
2012-06-25 00:56:09 +00:00
* This does some basic checking and then translates @ b to format
* used by bird core and feeds bird core with this route .
2000-06-05 12:52:57 +00:00
*/
1998-10-13 14:32:18 +00:00
static void
2012-06-25 00:56:09 +00:00
process_block ( struct proto * p , struct rip_block * block , ip_addr from , struct iface * iface , int version )
1998-10-13 14:32:18 +00:00
{
1999-03-17 10:20:23 +00:00
struct rip_interface * rif ;
2012-06-25 00:56:09 +00:00
ip_addr prefix , gw ;
int pxlen , metric , tag ;
CHK_MAGIC ;
if ( rip_is_old ( p ) ) {
/* RIPv2 */
struct rip_block_v2 * b = ( void * ) block ;
if ( ntohs ( b - > afi ) ! = AF_INET )
return ;
prefix = ipa_from_ip4 ( ip4_ntoh ( b - > network ) ) ;
gw = ip4_nonzero ( b - > nexthop ) ? ipa_from_ip4 ( ip4_ntoh ( b - > nexthop ) ) : from ;
metric = ntohl ( b - > metric ) ;
tag = ntohs ( b - > tag ) ;
/* FIXME (nonurgent): better handling of RIPv1? */
if ( version = = 1 )
pxlen = ip4_masklen ( ip4_class_mask ( ipa_to_ip4 ( prefix ) ) ) ;
else
pxlen = ip4_masklen ( ip4_ntoh ( b - > netmask ) ) ;
if ( pxlen < 0 ) {
log ( L_REMOTE " %s: Received invalid netmask for %I from %I " ,
p - > name , prefix , from ) ;
return ;
}
1999-03-17 10:20:23 +00:00
2012-06-25 00:56:09 +00:00
} else {
/* RIPng */
struct rip_block_ng * b = ( void * ) block ;
prefix = ip6_ntoh ( b - > network ) ;
gw = from ;
pxlen = b - > pxlen ;
metric = b - > metric ;
tag = ntohs ( b - > tag ) ;
/* Ignore nexthop block */
if ( metric = = 0xff )
return ;
1999-03-17 10:20:23 +00:00
2012-06-25 00:56:09 +00:00
if ( pxlen > MAX_PREFIX_LENGTH ) {
log ( L_REMOTE " %s: Received invalid pxlen %d for %I from %I " ,
p - > name , pxlen , prefix , from ) ;
return ;
}
}
if ( ( ! metric ) | | ( metric > P_CF - > infinity ) ) {
log ( L_REMOTE " %s: Received route %I/%d with invalid metric %d from %I " ,
p - > name , prefix , pxlen , metric , from ) ;
1998-10-20 16:12:43 +00:00
return ;
}
2012-06-25 00:56:09 +00:00
neighbor * neigh = neigh_find2 ( p , & gw , iface , 0 ) ;
if ( ! neigh ) {
log ( L_REMOTE " %s: Received route %I/%d with strange nexthop %I from %I " ,
p - > name , prefix , pxlen , gw , from ) ;
return ;
}
if ( neigh - > scope = = SCOPE_HOST ) {
2000-06-01 12:59:50 +00:00
DBG ( " Self-destined route, ignoring. \n " ) ;
return ;
}
1998-10-20 16:12:43 +00:00
2012-06-25 00:56:09 +00:00
TRACE ( D_PACKETS , " Received %I/%d metric %d from %I " ,
prefix , pxlen , metric , from ) ;
rta A = {
2014-04-29 15:23:38 +00:00
. src = p - > main_source ,
2012-06-25 00:56:09 +00:00
. source = RTS_RIP ,
. scope = SCOPE_UNIVERSE ,
. cast = RTC_UNICAST ,
. dest = RTD_ROUTER ,
. gw = gw ,
. from = from ,
. iface = neigh - > iface
} ;
if ( rip_is_old ( p ) ) pxlen + = 96 ; // XXXX: Hack
net * n = net_get ( p - > table , prefix , pxlen ) ;
rta * a = rta_lookup ( & A ) ;
rte * r = rte_get_temp ( a ) ;
if ( ! ( rif = neigh - > data ) ) {
rif = neigh - > data = find_interface ( p , A . iface ) ;
1998-12-09 20:08:57 +00:00
}
2000-06-01 12:59:50 +00:00
if ( ! rif )
1999-03-17 10:20:23 +00:00
bug ( " Route packet using unknown interface? No. " ) ;
2000-06-07 13:58:49 +00:00
2012-06-25 00:56:09 +00:00
r - > u . rip . metric = metric + rif - > metric ;
if ( r - > u . rip . metric > P_CF - > infinity )
r - > u . rip . metric = P_CF - > infinity ;
r - > u . rip . tag = tag ;
2000-05-11 10:33:18 +00:00
r - > u . rip . entry = NULL ;
2012-06-25 00:56:09 +00:00
1998-10-20 16:12:43 +00:00
r - > net = n ;
1998-10-13 14:32:18 +00:00
r - > pflags = 0 ; /* Here go my flags */
2000-05-10 12:23:06 +00:00
rip_rte_update_if_better ( p - > table , n , p , r ) ;
1998-12-09 20:08:57 +00:00
DBG ( " done \n " ) ;
1998-10-13 14:32:18 +00:00
}
1998-07-09 19:39:04 +00:00
2012-06-25 00:56:09 +00:00
# define BAD( x ) do { log( L_REMOTE "%s: " x, p->name ); return 1; } while(0)
1998-07-28 21:44:11 +00:00
2000-06-05 17:13:36 +00:00
/*
2000-06-05 12:52:57 +00:00
* rip_process_packet - this is main routine for incoming packets .
*/
1998-07-28 21:44:11 +00:00
static int
2012-03-15 11:23:49 +00:00
rip_process_packet ( struct proto * p , struct rip_packet * packet , int num , ip_addr whotoldme , int port , struct iface * iface )
1998-07-09 19:39:04 +00:00
{
int i ;
2012-06-25 00:56:09 +00:00
int auth = 0 ;
2000-06-01 12:59:50 +00:00
neighbor * neighbor ;
1998-07-09 19:39:04 +00:00
switch ( packet - > heading . version ) {
2012-06-25 00:56:09 +00:00
case 1 : DBG ( " Rip1: " ) ; break ;
case 2 : DBG ( " Rip2: " ) ; break ;
1998-07-09 19:39:04 +00:00
default : BAD ( " Unknown version " ) ;
}
switch ( packet - > heading . command ) {
1998-12-09 20:08:57 +00:00
case RIPCMD_REQUEST : DBG ( " Asked to send my routing table \n " ) ;
2000-05-19 16:22:53 +00:00
if ( P_CF - > honor = = HO_NEVER )
BAD ( " They asked me to send routing table, but I was told not to do it " ) ;
2012-03-15 11:23:49 +00:00
if ( ( P_CF - > honor = = HO_NEIGHBOR ) & & ( ! neigh_find2 ( p , & whotoldme , iface , 0 ) ) )
2000-05-19 16:22:53 +00:00
BAD ( " They asked me to send routing table, but he is not my neighbor " ) ;
1999-08-18 13:19:33 +00:00
rip_sendto ( p , whotoldme , port , HEAD ( P - > interfaces ) ) ; /* no broadcast */
1998-07-28 21:44:11 +00:00
break ;
2012-06-25 00:56:09 +00:00
1998-12-09 20:08:57 +00:00
case RIPCMD_RESPONSE : DBG ( " *** Rtable from %I \n " , whotoldme ) ;
1999-02-15 13:34:43 +00:00
if ( port ! = P_CF - > port ) {
2004-06-23 23:59:48 +00:00
log ( L_REMOTE " %s: %I send me routing info from port %d " , p - > name , whotoldme , port ) ;
2000-05-19 16:22:53 +00:00
return 1 ;
1998-07-09 19:39:04 +00:00
}
2012-03-15 11:23:49 +00:00
if ( ! ( neighbor = neigh_find2 ( p , & whotoldme , iface , 0 ) ) | | neighbor - > scope = = SCOPE_HOST ) {
2004-06-23 23:59:48 +00:00
log ( L_REMOTE " %s: %I send me routing info but he is not my neighbor " , p - > name , whotoldme ) ;
1998-07-28 21:44:11 +00:00
return 0 ;
1998-07-09 19:39:04 +00:00
}
2012-06-25 00:56:09 +00:00
/* Authentication is not defined for RIPng */
if ( rip_is_old ( p ) ) {
struct rip_block_auth * b = ( void * ) & packet - > block [ 0 ] ;
if ( b - > mustbeFFFF = = 0xffff ) {
if ( rip_incoming_authentication ( p , b , packet , num , whotoldme ) )
BAD ( " Authentication failed " ) ;
else
auth = 1 ;
}
1998-07-09 19:39:04 +00:00
}
2012-06-25 00:56:09 +00:00
if ( ( ! auth ) & & ( P_CF - > authtype ! = AT_NONE ) )
BAD ( " Packet is not authenticated and it should be " ) ;
for ( i = auth ; i < num ; i + + )
process_block ( p , & packet - > block [ i ] , whotoldme , iface , packet - > heading . version ) ;
1998-07-09 19:39:04 +00:00
break ;
2012-06-25 00:56:09 +00:00
1998-10-07 19:33:50 +00:00
case RIPCMD_TRACEON :
1998-12-20 14:29:06 +00:00
case RIPCMD_TRACEOFF : BAD ( " I was asked for traceon/traceoff " ) ;
case 5 : BAD ( " Some Sun extension around here " ) ;
1998-07-09 19:39:04 +00:00
default : BAD ( " Unknown command " ) ;
}
1998-07-28 21:44:11 +00:00
return 0 ;
1998-07-09 19:39:04 +00:00
}
2000-06-05 17:13:36 +00:00
/*
2000-06-05 12:52:57 +00:00
* rip_rx - Receive hook : do basic checks and pass packet to rip_process_packet
*/
1998-07-28 21:44:11 +00:00
static int
1998-07-09 19:39:04 +00:00
rip_rx ( sock * s , int size )
{
1998-10-26 15:35:19 +00:00
struct rip_interface * i = s - > data ;
struct proto * p = i - > proto ;
2012-03-15 11:23:49 +00:00
struct iface * iface = NULL ;
1998-07-09 19:39:04 +00:00
int num ;
2004-05-31 17:42:38 +00:00
/* In non-listening mode, just ignore packet */
if ( i - > mode & IM_NOLISTEN )
return 1 ;
2012-03-15 11:23:49 +00:00
if ( ! i - > iface | | s - > lifindex ! = i - > iface - > index )
return 1 ;
iface = i - > iface ;
2012-06-25 00:56:09 +00:00
2012-03-15 11:23:49 +00:00
2014-05-18 09:51:15 +00:00
if ( i - > check_ttl & & ( s - > rcv_ttl < 255 ) )
2013-06-25 13:33:00 +00:00
{
log ( L_REMOTE " %s: Discarding packet with TTL %d (< 255) from %I on %s " ,
2014-05-18 09:51:15 +00:00
p - > name , s - > rcv_ttl , s - > faddr , i - > iface - > name ) ;
2013-06-25 13:33:00 +00:00
return 1 ;
}
1998-07-09 19:39:04 +00:00
CHK_MAGIC ;
2012-06-25 00:56:09 +00:00
DBG ( " RIP: message came: %d bytes from %I via %s \n " , size , s - > faddr , iface ? iface - > name : " (dummy) " ) ;
1998-07-09 19:39:04 +00:00
size - = sizeof ( struct rip_packet_heading ) ;
if ( size < 0 ) BAD ( " Too small packet " ) ;
if ( size % sizeof ( struct rip_block ) ) BAD ( " Odd sized packet " ) ;
num = size / sizeof ( struct rip_block ) ;
2000-04-26 11:07:57 +00:00
if ( num > PACKET_MAX ) BAD ( " Too many blocks " ) ;
1998-07-09 19:39:04 +00:00
2012-06-25 00:56:09 +00:00
if ( ipa_equal ( iface - > addr - > ip , s - > faddr ) ) {
2000-05-10 12:46:47 +00:00
DBG ( " My own packet \n " ) ;
return 1 ;
}
2012-03-15 11:23:49 +00:00
rip_process_packet ( p , ( struct rip_packet * ) s - > rbuf , num , s - > faddr , s - > fport , iface ) ;
1998-07-28 21:44:11 +00:00
return 1 ;
1998-07-09 19:39:04 +00:00
}
2000-06-05 17:13:36 +00:00
/*
2000-06-07 13:25:53 +00:00
* Interface to BIRD core
1998-07-28 21:44:11 +00:00
*/
1998-07-09 19:39:04 +00:00
static void
rip_dump_entry ( struct rip_entry * e )
{
1998-10-07 19:33:50 +00:00
debug ( " %I told me %d/%d ago: to %I/%d go via %I, metric %d " ,
1998-12-22 19:41:04 +00:00
e - > whotoldme , e - > updated - now , e - > changed - now , e - > n . prefix , e - > n . pxlen , e - > nexthop , e - > metric ) ;
1998-10-07 19:33:50 +00:00
debug ( " \n " ) ;
1998-07-09 19:39:04 +00:00
}
2000-06-05 12:52:57 +00:00
/**
2000-06-05 17:13:36 +00:00
* rip_timer
* @ t : timer
*
* Broadcast routing tables periodically ( using rip_tx ) and kill
2000-06-07 13:25:53 +00:00
* routes that are too old . RIP keeps a list of its own entries present
* in the core table by a linked list ( functions rip_rte_insert ( ) and
* rip_rte_delete ( ) are responsible for that ) , it walks this list in the timer
* and in case an entry is too old , it is discarded .
2000-06-05 12:52:57 +00:00
*/
2000-06-05 17:13:36 +00:00
1998-07-09 19:39:04 +00:00
static void
rip_timer ( timer * t )
{
struct proto * p = t - > data ;
2000-05-11 10:33:18 +00:00
struct fib_node * e , * et ;
1998-07-09 19:39:04 +00:00
CHK_MAGIC ;
1998-12-09 20:08:57 +00:00
DBG ( " RIP: tick tock \n " ) ;
1998-10-20 16:12:43 +00:00
WALK_LIST_DELSAFE ( e , et , P - > garbage ) {
rte * rte ;
rte = SKIP_BACK ( struct rte , u . rip . garbage , e ) ;
2013-02-26 13:13:11 +00:00
CHK_MAGIC ;
2000-05-11 09:41:16 +00:00
DBG ( " Garbage: (%p) " , rte ) ; rte_dump ( rte ) ;
1998-10-20 16:12:43 +00:00
2000-06-21 19:40:46 +00:00
if ( now - rte - > lastmod > P_CF - > timeout_time ) {
2000-05-11 15:05:13 +00:00
TRACE ( D_EVENTS , " entry is too old: %I " , rte - > net - > n . prefix ) ;
2000-05-11 10:33:18 +00:00
if ( rte - > u . rip . entry ) {
rte - > u . rip . entry - > metric = P_CF - > infinity ;
rte - > u . rip . metric = P_CF - > infinity ;
}
1999-11-10 11:52:36 +00:00
}
2000-06-21 19:40:46 +00:00
if ( now - rte - > lastmod > P_CF - > garbage_time ) {
2000-05-11 15:05:13 +00:00
TRACE ( D_EVENTS , " entry is much too old: %I " , rte - > net - > n . prefix ) ;
1999-05-17 20:16:53 +00:00
rte_discard ( p - > table , rte ) ;
1998-10-20 16:12:43 +00:00
}
1998-07-09 19:39:04 +00:00
}
1998-07-28 21:44:11 +00:00
1998-12-09 20:08:57 +00:00
DBG ( " RIP: Broadcasting routing tables \n " ) ;
1998-10-20 16:12:43 +00:00
{
1998-12-22 19:41:04 +00:00
struct rip_interface * rif ;
2013-02-23 23:43:08 +00:00
if ( P_CF - > period > 2 ) { /* Bring some randomness into sending times */
if ( ! ( P - > tx_count % P_CF - > period ) ) P - > rnd_count = random_u32 ( ) % 2 ;
} else P - > rnd_count = P - > tx_count % P_CF - > period ;
1998-12-22 19:41:04 +00:00
WALK_LIST ( rif , P - > interfaces ) {
struct iface * iface = rif - > iface ;
1998-07-28 21:44:11 +00:00
1998-12-22 19:41:04 +00:00
if ( ! iface ) continue ;
2000-05-10 13:23:21 +00:00
if ( rif - > mode & IM_QUIET ) continue ;
1998-10-20 16:12:43 +00:00
if ( ! ( iface - > flags & IF_UP ) ) continue ;
2013-02-23 23:43:08 +00:00
rif - > triggered = P - > rnd_count ;
1998-10-20 16:12:43 +00:00
1998-12-22 19:41:04 +00:00
rip_sendto ( p , IPA_NONE , 0 , rif ) ;
1998-10-20 16:12:43 +00:00
}
2013-02-23 23:43:08 +00:00
P - > tx_count + + ;
P - > rnd_count - - ;
1998-10-20 16:12:43 +00:00
}
1998-10-07 19:33:50 +00:00
1998-12-09 20:08:57 +00:00
DBG ( " RIP: tick tock done \n " ) ;
1998-07-09 19:39:04 +00:00
}
2000-06-05 17:13:36 +00:00
/*
2000-04-28 10:14:59 +00:00
* rip_start - initialize instance of rip
*/
1999-02-08 22:50:32 +00:00
static int
1998-07-09 19:39:04 +00:00
rip_start ( struct proto * p )
{
1998-12-22 19:41:04 +00:00
struct rip_interface * rif ;
1998-12-09 20:08:57 +00:00
DBG ( " RIP: starting instance... \n " ) ;
1998-07-09 19:39:04 +00:00
2013-02-22 06:15:27 +00:00
ASSERT ( sizeof ( struct rip_packet_heading ) = = 4 ) ;
ASSERT ( sizeof ( struct rip_block ) = = 20 ) ;
ASSERT ( sizeof ( struct rip_block_auth ) = = 20 ) ;
2000-06-05 15:41:44 +00:00
2004-06-23 21:34:26 +00:00
# ifdef LOCAL_DEBUG
1998-07-09 19:39:04 +00:00
P - > magic = RIP_MAGIC ;
2004-06-23 21:34:26 +00:00
# endif
1998-12-22 19:41:04 +00:00
fib_init ( & P - > rtable , p - > pool , sizeof ( struct rip_entry ) , 0 , NULL ) ;
1998-07-09 19:39:04 +00:00
init_list ( & P - > connections ) ;
1998-10-20 16:12:43 +00:00
init_list ( & P - > garbage ) ;
1998-10-26 15:35:19 +00:00
init_list ( & P - > interfaces ) ;
1998-07-09 19:39:04 +00:00
P - > timer = tm_new ( p - > pool ) ;
P - > timer - > data = p ;
2013-02-23 23:43:08 +00:00
P - > timer - > recurrent = 1 ;
1998-07-09 19:39:04 +00:00
P - > timer - > hook = rip_timer ;
2013-02-23 23:43:08 +00:00
tm_start ( P - > timer , 2 ) ;
1999-05-11 09:53:45 +00:00
rif = new_iface ( p , NULL , 0 , NULL ) ; /* Initialize dummy interface */
1998-12-22 19:41:04 +00:00
add_head ( & P - > interfaces , NODE rif ) ;
1998-10-15 15:12:24 +00:00
CHK_MAGIC ;
1998-07-09 19:39:04 +00:00
1998-12-09 20:08:57 +00:00
DBG ( " RIP: ...done \n " ) ;
1999-02-08 22:50:32 +00:00
return PS_UP ;
1998-07-09 19:39:04 +00:00
}
static void
rip_dump ( struct proto * p )
{
int i ;
2004-05-31 20:57:38 +00:00
node * w ;
1998-10-26 15:35:19 +00:00
struct rip_interface * rif ;
1999-03-01 21:18:01 +00:00
CHK_MAGIC ;
1998-07-09 19:39:04 +00:00
WALK_LIST ( w , P - > connections ) {
1998-07-28 21:44:11 +00:00
struct rip_connection * n = ( void * ) w ;
debug ( " RIP: connection #%d: %I \n " , n - > num , n - > addr ) ;
1998-07-09 19:39:04 +00:00
}
i = 0 ;
1998-12-22 19:41:04 +00:00
FIB_WALK ( & P - > rtable , e ) {
1998-07-09 19:39:04 +00:00
debug ( " RIP: entry #%d: " , i + + ) ;
2004-06-23 23:59:48 +00:00
rip_dump_entry ( ( struct rip_entry * ) e ) ;
1998-12-22 19:41:04 +00:00
} FIB_WALK_END ;
1998-10-26 15:35:19 +00:00
i = 0 ;
WALK_LIST ( rif , P - > interfaces ) {
1998-12-09 15:22:40 +00:00
debug ( " RIP: interface #%d: %s, %I, busy = %x \n " , i + + , rif - > iface ? rif - > iface - > name : " (dummy) " , rif - > sock - > daddr , rif - > busy ) ;
1998-10-26 15:35:19 +00:00
}
}
1999-12-08 13:33:44 +00:00
static void
2000-05-06 22:57:39 +00:00
rip_get_route_info ( rte * rte , byte * buf , ea_list * attrs )
1999-12-08 13:33:44 +00:00
{
2000-05-06 22:57:39 +00:00
eattr * metric = ea_find ( attrs , EA_RIP_METRIC ) ;
eattr * tag = ea_find ( attrs , EA_RIP_TAG ) ;
buf + = bsprintf ( buf , " (%d/%d) " , rte - > pref , metric ? metric - > u . data : 0 ) ;
if ( tag & & tag - > u . data )
bsprintf ( buf , " t%04x " , tag - > u . data ) ;
1999-12-08 13:33:44 +00:00
}
1998-10-26 15:35:19 +00:00
static void
2004-06-05 09:27:49 +00:00
kill_iface ( struct rip_interface * i )
1998-10-26 15:35:19 +00:00
{
1998-12-09 20:08:57 +00:00
DBG ( " RIP: Interface %s disappeared \n " , i - > iface - > name ) ;
1998-10-26 15:35:19 +00:00
rfree ( i - > sock ) ;
mb_free ( i ) ;
}
2000-04-28 09:55:52 +00:00
/**
2000-06-05 17:13:36 +00:00
* new_iface
* @ p : myself
2000-06-07 13:25:53 +00:00
* @ new : interface to be created or % NULL if we are creating a magic
* socket . The magic socket is used for listening and also for
* sending requested responses .
2000-06-05 17:13:36 +00:00
* @ flags : interface flags
* @ patt : pattern this interface matched , used for access to config options
*
2000-06-07 13:25:53 +00:00
* Create an interface structure and start listening on the interface .
1998-12-09 15:22:40 +00:00
*/
1999-05-31 20:30:16 +00:00
static struct rip_interface *
1999-05-11 09:53:45 +00:00
new_iface ( struct proto * p , struct iface * new , unsigned long flags , struct iface_patt * patt )
1998-10-26 15:35:19 +00:00
{
1998-12-09 15:22:40 +00:00
struct rip_interface * rif ;
2000-05-10 13:23:21 +00:00
struct rip_patt * PATT = ( struct rip_patt * ) patt ;
1998-12-09 15:22:40 +00:00
1999-05-31 19:37:16 +00:00
rif = mb_allocz ( p - > pool , sizeof ( struct rip_interface ) ) ;
1998-12-09 15:22:40 +00:00
rif - > iface = new ;
rif - > proto = p ;
1998-12-22 19:41:04 +00:00
rif - > busy = NULL ;
2000-05-10 13:23:21 +00:00
if ( PATT ) {
rif - > mode = PATT - > mode ;
rif - > metric = PATT - > metric ;
rif - > multicast = ( ! ( PATT - > mode & IM_BROADCAST ) ) & & ( flags & IF_MULTICAST ) ;
2013-06-25 13:33:00 +00:00
rif - > check_ttl = ( PATT - > ttl_security = = 1 ) ;
2000-05-10 13:23:21 +00:00
}
1999-05-11 09:53:45 +00:00
/* lookup multicasts over unnumbered links - no: rip is not defined over unnumbered links */
1998-12-09 15:22:40 +00:00
2000-03-26 18:01:27 +00:00
if ( rif - > multicast )
1999-05-31 20:30:16 +00:00
DBG ( " Doing multicasts! \n " ) ;
1998-12-09 15:22:40 +00:00
rif - > sock = sk_new ( p - > pool ) ;
2009-09-04 09:06:51 +00:00
rif - > sock - > type = SK_UDP ;
1999-02-15 13:34:43 +00:00
rif - > sock - > sport = P_CF - > port ;
1998-12-09 15:22:40 +00:00
rif - > sock - > rx_hook = rip_rx ;
rif - > sock - > data = rif ;
rif - > sock - > rbsize = 10240 ;
1998-12-22 19:41:04 +00:00
rif - > sock - > iface = new ; /* Automagically works for dummy interface */
1998-12-09 15:22:40 +00:00
rif - > sock - > tbuf = mb_alloc ( p - > pool , sizeof ( struct rip_packet ) ) ;
rif - > sock - > tx_hook = rip_tx ;
rif - > sock - > err_hook = rip_tx_err ;
rif - > sock - > daddr = IPA_NONE ;
1999-02-15 13:34:43 +00:00
rif - > sock - > dport = P_CF - > port ;
2012-06-25 00:56:09 +00:00
rif - > sock - > flags = rip_is_old ( p ) ? SKF_V4ONLY : SKF_V6ONLY ;
1999-08-18 13:19:33 +00:00
if ( new )
2000-06-04 20:00:35 +00:00
{
2013-06-24 14:37:30 +00:00
rif - > sock - > tos = PATT - > tx_tos ;
rif - > sock - > priority = PATT - > tx_priority ;
2013-06-25 13:33:00 +00:00
rif - > sock - > ttl = PATT - > ttl_security ? 255 : 1 ;
2013-07-31 14:16:48 +00:00
rif - > sock - > flags | = SKF_LADDR_RX | ( rif - > check_ttl ? SKF_TTL_RX : 0 ) ;
2000-06-04 20:00:35 +00:00
}
1998-12-09 15:22:40 +00:00
2000-03-22 14:26:03 +00:00
if ( new ) {
2011-03-28 20:46:18 +00:00
if ( new - > addr - > flags & IA_PEER )
2004-06-23 23:59:48 +00:00
log ( L_WARN " %s: rip is not defined over unnumbered links " , p - > name ) ;
2000-03-26 18:01:27 +00:00
if ( rif - > multicast ) {
2012-06-25 00:56:09 +00:00
rif - > sock - > daddr = rip_is_old ( p ) ? IP4_ALL_RIP_ROUTERS : IP6_ALL_RIP_ROUTERS ;
2000-05-11 15:05:13 +00:00
} else {
2000-03-26 18:01:27 +00:00
rif - > sock - > daddr = new - > addr - > brd ;
2000-05-11 15:05:13 +00:00
}
1999-05-31 20:34:48 +00:00
}
1998-12-09 15:22:40 +00:00
1999-05-11 09:53:45 +00:00
if ( ! ipa_nonzero ( rif - > sock - > daddr ) ) {
2000-05-16 15:05:05 +00:00
if ( rif - > iface )
2004-06-23 23:59:48 +00:00
log ( L_WARN " %s: interface %s is too strange for me " , p - > name , rif - > iface - > name ) ;
2009-09-04 09:06:51 +00:00
} else {
2014-05-18 09:51:15 +00:00
if ( sk_open ( rif - > sock ) < 0 )
2009-09-04 09:06:51 +00:00
goto err ;
if ( rif - > multicast )
{
if ( sk_setup_multicast ( rif - > sock ) < 0 )
goto err ;
if ( sk_join_group ( rif - > sock , rif - > sock - > daddr ) < 0 )
goto err ;
}
else
{
2014-05-18 09:51:15 +00:00
if ( sk_setup_broadcast ( rif - > sock ) < 0 )
2009-09-04 09:06:51 +00:00
goto err ;
}
2004-05-31 17:42:38 +00:00
}
1999-05-31 20:30:16 +00:00
2000-05-11 15:05:13 +00:00
TRACE ( D_EVENTS , " Listening on %s, port %d, mode %s (%I) " , rif - > iface ? rif - > iface - > name : " (dummy) " , P_CF - > port , rif - > multicast ? " multicast " : " broadcast " , rif - > sock - > daddr ) ;
1998-10-26 15:35:19 +00:00
1998-12-09 15:22:40 +00:00
return rif ;
2009-09-04 09:06:51 +00:00
err :
2014-05-18 09:51:15 +00:00
sk_log_error ( rif - > sock , p - > name ) ;
log ( L_ERR " %s: Cannot open socket for %s " , p - > name , rif - > iface ? rif - > iface - > name : " (dummy) " ) ;
2009-09-04 09:06:51 +00:00
if ( rif - > iface ) {
rfree ( rif - > sock ) ;
mb_free ( rif ) ;
return NULL ;
}
/* On dummy, we just return non-working socket, so that user gets error every time anyone requests table */
2010-02-21 13:34:53 +00:00
return rif ;
1998-07-09 19:39:04 +00:00
}
2000-03-22 14:26:03 +00:00
static void
rip_real_if_add ( struct object_lock * lock )
{
struct iface * iface = lock - > iface ;
struct proto * p = lock - > data ;
struct rip_interface * rif ;
2010-03-14 15:36:59 +00:00
struct iface_patt * k = iface_patt_find ( & P_CF - > iface_list , iface , iface - > addr ) ;
2000-03-22 14:26:03 +00:00
if ( ! k )
bug ( " This can not happen! It existed few seconds ago! " ) ;
DBG ( " adding interface %s \n " , iface - > name ) ;
rif = new_iface ( p , iface , iface - > flags , k ) ;
2000-05-19 16:44:25 +00:00
if ( rif ) {
add_head ( & P - > interfaces , NODE rif ) ;
DBG ( " Adding object lock of %p for %p \n " , lock , rif ) ;
rif - > lock = lock ;
2000-05-19 17:21:42 +00:00
} else { rfree ( lock ) ; }
2000-03-22 14:26:03 +00:00
}
1998-07-28 21:44:11 +00:00
static void
1999-05-06 21:38:11 +00:00
rip_if_notify ( struct proto * p , unsigned c , struct iface * iface )
1998-07-28 21:44:11 +00:00
{
1998-12-09 20:08:57 +00:00
DBG ( " RIP: if notify \n " ) ;
1999-05-06 21:38:11 +00:00
if ( iface - > flags & IF_IGNORE )
return ;
if ( c & IF_CHANGE_DOWN ) {
1998-10-26 15:35:19 +00:00
struct rip_interface * i ;
1999-05-06 21:38:11 +00:00
i = find_interface ( p , iface ) ;
1998-12-04 11:45:51 +00:00
if ( i ) {
rem_node ( NODE i ) ;
2000-03-22 14:26:03 +00:00
rfree ( i - > lock ) ;
2004-06-05 09:27:49 +00:00
kill_iface ( i ) ;
1998-12-04 11:45:51 +00:00
}
1998-10-26 15:35:19 +00:00
}
1999-05-06 21:38:11 +00:00
if ( c & IF_CHANGE_UP ) {
2010-03-14 15:36:59 +00:00
struct iface_patt * k = iface_patt_find ( & P_CF - > iface_list , iface , iface - > addr ) ;
2000-03-22 14:26:03 +00:00
struct object_lock * lock ;
2002-03-10 12:32:12 +00:00
struct rip_patt * PATT = ( struct rip_patt * ) k ;
1998-12-04 11:45:51 +00:00
if ( ! k ) return ; /* We are not interested in this interface */
2000-05-10 11:48:34 +00:00
2000-03-22 14:26:03 +00:00
lock = olock_new ( p - > pool ) ;
2002-03-10 12:32:12 +00:00
if ( ! ( PATT - > mode & IM_BROADCAST ) & & ( iface - > flags & IF_MULTICAST ) )
2012-06-25 00:56:09 +00:00
lock - > addr = rip_is_old ( p ) ? IP4_ALL_RIP_ROUTERS : IP6_ALL_RIP_ROUTERS ;
2002-03-10 12:32:12 +00:00
else
lock - > addr = iface - > addr - > brd ;
2000-03-22 14:26:03 +00:00
lock - > port = P_CF - > port ;
lock - > iface = iface ;
lock - > hook = rip_real_if_add ;
lock - > data = p ;
2000-03-26 18:01:27 +00:00
lock - > type = OBJLOCK_UDP ;
2000-03-22 14:26:03 +00:00
olock_acquire ( lock ) ;
1998-10-26 15:35:19 +00:00
}
1998-07-28 21:44:11 +00:00
}
1999-05-31 19:16:22 +00:00
static struct ea_list *
2004-06-05 09:27:49 +00:00
rip_gen_attrs ( struct linpool * pool , int metric , u16 tag )
1999-05-31 19:16:22 +00:00
{
struct ea_list * l = lp_alloc ( pool , sizeof ( struct ea_list ) + 2 * sizeof ( eattr ) ) ;
l - > next = NULL ;
l - > flags = EALF_SORTED ;
l - > count = 2 ;
l - > attrs [ 0 ] . id = EA_RIP_TAG ;
l - > attrs [ 0 ] . flags = 0 ;
2000-03-04 22:30:44 +00:00
l - > attrs [ 0 ] . type = EAF_TYPE_INT | EAF_TEMP ;
1999-05-31 19:16:22 +00:00
l - > attrs [ 0 ] . u . data = tag ;
1999-12-08 13:33:44 +00:00
l - > attrs [ 1 ] . id = EA_RIP_METRIC ;
1999-05-31 19:16:22 +00:00
l - > attrs [ 1 ] . flags = 0 ;
2000-03-04 22:30:44 +00:00
l - > attrs [ 1 ] . type = EAF_TYPE_INT | EAF_TEMP ;
1999-05-31 19:16:22 +00:00
l - > attrs [ 1 ] . u . data = metric ;
return l ;
}
static int
rip_import_control ( struct proto * p , struct rte * * rt , struct ea_list * * attrs , struct linpool * pool )
{
2012-08-14 14:25:22 +00:00
if ( ( * rt ) - > attrs - > src - > proto = = p ) /* My own must not be touched */
1999-05-31 19:16:22 +00:00
return 1 ;
if ( ( * rt ) - > attrs - > source ! = RTS_RIP ) {
2004-06-05 09:27:49 +00:00
struct ea_list * new = rip_gen_attrs ( pool , 1 , 0 ) ;
1999-05-31 19:16:22 +00:00
new - > next = * attrs ;
* attrs = new ;
}
return 0 ;
}
static struct ea_list *
rip_make_tmp_attrs ( struct rte * rt , struct linpool * pool )
{
2004-06-05 09:27:49 +00:00
return rip_gen_attrs ( pool , rt - > u . rip . metric , rt - > u . rip . tag ) ;
1999-05-31 19:16:22 +00:00
}
static void
rip_store_tmp_attrs ( struct rte * rt , struct ea_list * attrs )
{
2000-05-10 06:56:42 +00:00
rt - > u . rip . tag = ea_get_int ( attrs , EA_RIP_TAG , 0 ) ;
rt - > u . rip . metric = ea_get_int ( attrs , EA_RIP_METRIC , 1 ) ;
1999-05-31 19:16:22 +00:00
}
2000-06-05 17:13:36 +00:00
/*
2000-06-05 12:52:57 +00:00
* rip_rt_notify - core tells us about new route ( possibly our
* own ) , so store it into our data structures .
*/
1998-10-07 19:33:50 +00:00
static void
2010-02-13 11:26:26 +00:00
rip_rt_notify ( struct proto * p , struct rtable * table UNUSED , struct network * net ,
2010-09-03 15:15:02 +00:00
struct rte * new , struct rte * old UNUSED , struct ea_list * attrs )
1998-10-07 19:33:50 +00:00
{
1998-10-15 15:12:24 +00:00
CHK_MAGIC ;
2010-09-03 15:15:02 +00:00
struct rip_entry * e ;
1998-10-07 19:33:50 +00:00
2010-09-03 15:15:02 +00:00
e = fib_find ( & P - > rtable , & net - > n . prefix , net - > n . pxlen ) ;
if ( e )
1998-12-22 19:41:04 +00:00
fib_delete ( & P - > rtable , e ) ;
1998-10-07 19:33:50 +00:00
if ( new ) {
1998-12-22 19:41:04 +00:00
e = fib_get ( & P - > rtable , & net - > n . prefix , net - > n . pxlen ) ;
1998-10-07 19:33:50 +00:00
1998-10-17 10:25:22 +00:00
e - > nexthop = new - > attrs - > gw ;
2000-03-27 12:21:11 +00:00
e - > metric = 0 ;
e - > whotoldme = IPA_NONE ;
2000-05-11 10:33:18 +00:00
new - > u . rip . entry = e ;
2000-03-29 08:58:06 +00:00
2000-05-10 12:38:05 +00:00
e - > tag = ea_get_int ( attrs , EA_RIP_TAG , 0 ) ;
e - > metric = ea_get_int ( attrs , EA_RIP_METRIC , 1 ) ;
2000-03-29 08:58:06 +00:00
if ( e - > metric > P_CF - > infinity )
e - > metric = P_CF - > infinity ;
2012-08-14 14:25:22 +00:00
if ( new - > attrs - > src - > proto = = p )
2000-03-27 12:21:11 +00:00
e - > whotoldme = new - > attrs - > from ;
2000-04-07 09:02:17 +00:00
if ( ! e - > metric ) /* That's okay: this way user can set his own value for external
2000-03-29 08:58:06 +00:00
routes in rip . */
1999-12-08 13:33:44 +00:00
e - > metric = 5 ;
1998-10-07 19:33:50 +00:00
e - > updated = e - > changed = now ;
1998-10-13 14:32:18 +00:00
e - > flags = 0 ;
1998-10-07 19:33:50 +00:00
}
}
2004-07-13 20:53:56 +00:00
static int
rip_rte_same ( struct rte * new , struct rte * old )
{
/* new->attrs == old->attrs always */
return new - > u . rip . metric = = old - > u . rip . metric ;
}
1998-10-20 16:12:43 +00:00
static int
1998-10-13 14:32:18 +00:00
rip_rte_better ( struct rte * new , struct rte * old )
{
2012-08-14 14:25:22 +00:00
struct proto * p = new - > attrs - > src - > proto ;
2000-03-29 08:58:06 +00:00
1999-11-10 11:52:36 +00:00
if ( ipa_equal ( old - > attrs - > from , new - > attrs - > from ) )
return 1 ;
1998-10-13 14:32:18 +00:00
if ( old - > u . rip . metric < new - > u . rip . metric )
return 0 ;
if ( old - > u . rip . metric > new - > u . rip . metric )
return 1 ;
2012-08-14 14:25:22 +00:00
if ( old - > attrs - > src - > proto = = new - > attrs - > src - > proto ) /* This does not make much sense for different protocols */
2000-03-29 08:58:06 +00:00
if ( ( old - > u . rip . metric = = new - > u . rip . metric ) & &
2000-06-21 19:40:46 +00:00
( ( now - old - > lastmod ) > ( P_CF - > timeout_time / 2 ) ) )
2000-03-29 08:58:06 +00:00
return 1 ;
1998-10-13 14:32:18 +00:00
return 0 ;
}
2000-06-05 17:13:36 +00:00
/*
2000-06-05 12:52:57 +00:00
* rip_rte_insert - we maintain linked list of " our " entries in main
2000-06-07 12:29:08 +00:00
* routing table , so that we can timeout them correctly . rip_timer ( )
2000-06-05 12:52:57 +00:00
* walks the list .
*/
1998-10-20 16:12:43 +00:00
static void
2004-06-05 09:27:49 +00:00
rip_rte_insert ( net * net UNUSED , rte * rte )
1998-10-20 16:12:43 +00:00
{
2012-08-14 14:25:22 +00:00
struct proto * p = rte - > attrs - > src - > proto ;
2000-05-11 09:41:16 +00:00
CHK_MAGIC ;
DBG ( " rip_rte_insert: %p \n " , rte ) ;
1998-10-20 16:12:43 +00:00
add_head ( & P - > garbage , & rte - > u . rip . garbage ) ;
}
2000-06-05 17:13:36 +00:00
/*
2000-06-05 12:52:57 +00:00
* rip_rte_remove - link list maintenance
*/
1998-10-20 16:12:43 +00:00
static void
2004-06-05 09:27:49 +00:00
rip_rte_remove ( net * net UNUSED , rte * rte )
1998-10-20 16:12:43 +00:00
{
2013-02-20 23:44:59 +00:00
# ifdef LOCAL_DEBUG
2013-11-23 10:50:34 +00:00
struct proto * p = rte - > attrs - > src - > proto ;
2000-05-11 09:41:16 +00:00
CHK_MAGIC ;
DBG ( " rip_rte_remove: %p \n " , rte ) ;
2013-02-20 23:44:59 +00:00
# endif
1998-10-20 16:12:43 +00:00
rem_node ( & rte - > u . rip . garbage ) ;
}
2012-08-14 14:25:22 +00:00
static struct proto *
rip_init ( struct proto_config * cfg )
1998-07-09 19:39:04 +00:00
{
2012-08-14 14:25:22 +00:00
struct proto * p = proto_new ( cfg , sizeof ( struct rip_proto ) ) ;
2009-05-31 13:24:27 +00:00
p - > accept_ra_types = RA_OPTIMAL ;
1998-07-09 19:39:04 +00:00
p - > if_notify = rip_if_notify ;
1998-10-07 19:33:50 +00:00
p - > rt_notify = rip_rt_notify ;
1999-05-31 19:16:22 +00:00
p - > import_control = rip_import_control ;
1999-05-31 20:30:16 +00:00
p - > make_tmp_attrs = rip_make_tmp_attrs ;
p - > store_tmp_attrs = rip_store_tmp_attrs ;
1998-10-13 14:32:18 +00:00
p - > rte_better = rip_rte_better ;
2004-07-13 20:53:56 +00:00
p - > rte_same = rip_rte_same ;
1998-10-20 16:12:43 +00:00
p - > rte_insert = rip_rte_insert ;
p - > rte_remove = rip_rte_remove ;
2012-08-14 14:25:22 +00:00
return p ;
1999-03-01 21:18:01 +00:00
}
1998-12-04 11:45:51 +00:00
1999-03-01 21:18:01 +00:00
void
rip_init_config ( struct rip_proto_config * c )
{
init_list ( & c - > iface_list ) ;
c - > infinity = 16 ;
c - > period = 30 ;
c - > garbage_time = 120 + 180 ;
1999-11-10 11:52:36 +00:00
c - > timeout_time = 120 ;
1999-05-26 14:37:47 +00:00
c - > passwords = NULL ;
1999-05-11 09:53:45 +00:00
c - > authtype = AT_NONE ;
1998-07-09 19:39:04 +00:00
}
2000-04-28 10:14:59 +00:00
static int
2008-11-08 22:33:22 +00:00
rip_get_attr ( eattr * a , byte * buf , int buflen UNUSED )
2000-04-28 10:14:59 +00:00
{
switch ( a - > id ) {
2012-05-04 21:05:47 +00:00
case EA_RIP_METRIC : bsprintf ( buf , " metric: %d " , a - > u . data ) ; return GA_FULL ;
case EA_RIP_TAG : bsprintf ( buf , " tag: %d " , a - > u . data ) ; return GA_FULL ;
2000-04-28 10:14:59 +00:00
default : return GA_UNKNOWN ;
}
}
2000-05-16 14:58:06 +00:00
static int
rip_pat_compare ( struct rip_patt * a , struct rip_patt * b )
{
return ( ( a - > metric = = b - > metric ) & &
2013-06-24 14:37:30 +00:00
( a - > mode = = b - > mode ) & &
( a - > tx_tos = = b - > tx_tos ) & &
( a - > tx_priority = = b - > tx_priority ) ) ;
2000-05-16 14:58:06 +00:00
}
2000-05-10 12:32:45 +00:00
static int
rip_reconfigure ( struct proto * p , struct proto_config * c )
{
2000-05-10 13:42:50 +00:00
struct rip_proto_config * new = ( struct rip_proto_config * ) c ;
2000-05-10 13:23:21 +00:00
int generic = sizeof ( struct proto_config ) + sizeof ( list ) /* + sizeof(struct password_item *) */ ;
2000-05-10 12:32:45 +00:00
2000-05-16 14:58:06 +00:00
if ( ! iface_patts_equal ( & P_CF - > iface_list , & new - > iface_list , ( void * ) rip_pat_compare ) )
return 0 ;
2000-05-10 13:05:39 +00:00
return ! memcmp ( ( ( byte * ) P_CF ) + generic ,
( ( byte * ) new ) + generic ,
sizeof ( struct rip_proto_config ) - generic ) ;
2000-05-10 12:32:45 +00:00
}
2011-11-06 23:31:23 +00:00
static void
rip_copy_config ( struct proto_config * dest , struct proto_config * src )
{
/* Shallow copy of everything */
proto_copy_rest ( dest , src , sizeof ( struct rip_proto_config ) ) ;
/* We clean up iface_list, ifaces are non-sharable */
init_list ( & ( ( struct rip_proto_config * ) dest ) - > iface_list ) ;
/* Copy of passwords is OK, it just will be replaced in dest when used */
}
1998-07-09 19:39:04 +00:00
struct protocol proto_rip = {
1999-02-08 22:50:32 +00:00
name : " RIP " ,
2000-01-17 11:52:50 +00:00
template : " rip%d " ,
2012-06-25 00:56:09 +00:00
tables : RTB_IPV4 ,
2000-04-01 10:20:12 +00:00
attr_class : EAP_RIP ,
2012-01-24 10:31:00 +00:00
preference : DEF_PREF_RIP ,
1999-12-08 13:33:44 +00:00
get_route_info : rip_get_route_info ,
2000-04-28 10:14:59 +00:00
get_attr : rip_get_attr ,
1999-02-08 22:50:32 +00:00
init : rip_init ,
dump : rip_dump ,
start : rip_start ,
2000-05-10 12:32:45 +00:00
reconfigure : rip_reconfigure ,
2011-11-06 23:31:23 +00:00
copy_config : rip_copy_config
1998-07-09 19:39:04 +00:00
} ;
2012-06-25 00:56:09 +00:00
struct protocol proto_ripng = {
name : " RIPng " ,
template : " ripng%d " ,
tables : RTB_IPV6 ,
attr_class : EAP_RIP ,
preference : DEF_PREF_RIP ,
get_route_info : rip_get_route_info ,
get_attr : rip_get_attr ,
init : rip_init ,
dump : rip_dump ,
start : rip_start ,
reconfigure : rip_reconfigure ,
copy_config : rip_copy_config
} ;