1998-07-10 03:39:04 +08:00
/*
* Rest in pieces - RIP protocol
*
1998-10-08 03:33:50 +08:00
* Copyright ( c ) 1998 Pavel Machek < pavel @ ucw . cz >
1998-07-10 03:39:04 +08:00
*
* Can be freely distributed and used under the terms of the GNU GPL .
*/
# define LOCAL_DEBUG
# include <string.h>
# include <stdlib.h>
# 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"
# include "rip.h"
static void
rip_reply ( struct proto * p )
{
1998-07-30 15:43:45 +08:00
#if 0
1998-07-10 03:39:04 +08:00
P - > listen - > tbuf = " ACK! " ;
sk_send_to ( P - > listen , 5 , P - > listen - > faddr , P - > listen - > fport ) ;
1998-07-30 15:43:45 +08:00
# endif
1998-07-10 03:39:04 +08:00
}
1998-07-29 05:44:11 +08:00
/*
* Entries
*/
1998-07-10 03:39:04 +08:00
1998-10-13 22:32:18 +08:00
static struct rip_entry *
new_entry ( struct proto * p )
{
struct rip_entry * e ;
e = mb_alloc ( p - > pool , sizeof ( struct rip_entry ) ) ;
bzero ( e , sizeof ( struct rip_entry ) ) ;
return e ;
}
1998-07-10 03:39:04 +08:00
static struct rip_entry *
1998-10-08 03:33:50 +08:00
find_entry ( struct proto * p , ip_addr network , int pxlen )
1998-07-10 03:39:04 +08:00
{
struct node * e ;
CHK_MAGIC ;
WALK_LIST ( e , P - > rtable ) {
if ( ipa_equal ( network , E - > network ) & &
1998-10-08 03:33:50 +08:00
( pxlen = = E - > pxlen ) ) {
1998-07-10 03:39:04 +08:00
return E ;
}
}
return NULL ;
}
1998-10-08 03:33:50 +08:00
/* Delete one of entries */
1998-07-10 03:39:04 +08:00
static void
1998-10-08 03:33:50 +08:00
kill_entry_ourrt ( struct proto * p , struct rip_entry * e )
1998-07-10 03:39:04 +08:00
{
struct rip_connection * c ;
1998-07-29 05:44:11 +08:00
net * n ;
1998-07-10 03:39:04 +08:00
rem_node ( NODE e ) ;
WALK_LIST ( c , P - > connections ) {
1998-10-08 03:33:50 +08:00
if ( c - > sendptr = = e ) {
1998-12-10 04:08:57 +08:00
DBG ( " Deleting from under someone's sendptr... \n " ) ;
1998-10-08 03:33:50 +08:00
c - > sendptr = ( void * ) ( NODE c - > sendptr ) - > next ;
}
1998-07-10 03:39:04 +08:00
}
mb_free ( e ) ;
}
1998-10-13 22:32:18 +08:00
#if 0
/* Currently unreferenced, and likely may stay that way */
1998-10-08 03:33:50 +08:00
/* Delete one of entries */
static void
kill_entry_mainrt ( struct proto * p , struct rip_entry * e )
{
struct rip_connection * c ;
net * n ;
n = net_find ( & master_table , 0 , e - > network , e - > pxlen ) ;
if ( ! n ) log ( L_ERR " Could not find entry to delete in main routing table. \n " ) ;
else rte_update ( n , p , NULL ) ;
}
static void
kill_entry ( struct proto * p , struct rip_entry * e )
{
kill_entry_mainrt ( p , e ) ;
kill_entry_ourrt ( p , e ) ;
}
1998-10-13 22:32:18 +08:00
# endif
1998-10-08 03:33:50 +08:00
1998-07-29 05:44:11 +08:00
/*
* Output processing
*/
static void
rip_tx_err ( sock * s , int err )
{
struct rip_connection * c = s - > data ;
struct proto * p = c - > proto ;
1998-12-10 04:08:57 +08:00
log ( L_ERR " Unexpected error at rip transmit: %m \n " ) ;
1998-07-29 05:44:11 +08:00
}
static void
rip_tx ( sock * s )
{
1998-10-26 23:35:19 +08:00
struct rip_interface * rif = s - > data ;
struct rip_connection * c = rif - > busy ;
1998-07-29 05:44:11 +08:00
struct proto * p = c - > proto ;
struct rip_packet * packet = ( void * ) s - > tbuf ;
int i , done = 0 ;
givemore :
1998-12-10 04:08:57 +08:00
DBG ( " Preparing packet to send: " ) ;
1998-07-29 05:44:11 +08:00
if ( ! ( NODE c - > sendptr ) - > next ) {
1998-12-10 04:08:57 +08:00
DBG ( " Looks like I'm " ) ;
1998-10-26 23:35:19 +08:00
c - > rif - > busy = NULL ;
rem_node ( NODE c ) ;
mb_free ( c ) ;
1998-12-10 04:08:57 +08:00
DBG ( " done \n " ) ;
1998-07-29 05:44:11 +08:00
return ;
}
1998-07-30 15:43:45 +08:00
packet - > heading . command = RIPCMD_RESPONSE ;
1998-07-29 05:44:11 +08:00
packet - > heading . version = RIP_V2 ;
1998-07-30 15:43:45 +08:00
packet - > heading . unused = 0 ;
1998-07-29 05:44:11 +08:00
for ( i = 0 ; i < 25 ; i + + ) {
if ( ! ( NODE c - > sendptr ) - > next )
break ;
1998-12-10 04:08:57 +08:00
DBG ( " . " ) ;
1998-07-30 15:43:45 +08:00
packet - > block [ i ] . family = htons ( 2 ) ; /* AF_INET */
1998-10-08 03:33:50 +08:00
packet - > block [ i ] . tag = htons ( 0 ) ; /* FIXME: What should I set it to? */
1998-07-29 05:44:11 +08:00
packet - > block [ i ] . network = c - > sendptr - > network ;
packet - > block [ i ] . netmask = ipa_mkmask ( c - > sendptr - > pxlen ) ;
packet - > block [ i ] . nexthop = IPA_NONE ; /* FIXME: How should I set it? */
1998-10-26 23:35:19 +08:00
packet - > block [ i ] . metric = htonl ( 1 + ( c - > sendptr - > metric ? : 1 ) ) ;
1998-10-08 03:33:50 +08:00
if ( ipa_equal ( c - > sendptr - > whotoldme , s - > daddr ) ) {
1998-12-10 04:08:57 +08:00
DBG ( " (split horizont) " ) ;
1998-10-08 03:33:50 +08:00
/* FIXME: should we do it in all cases? */
1998-12-02 00:17:10 +08:00
packet - > block [ i ] . metric = P - > infinity ;
1998-10-08 03:33:50 +08:00
}
1998-07-29 05:44:11 +08:00
ipa_hton ( packet - > block [ i ] . network ) ;
ipa_hton ( packet - > block [ i ] . netmask ) ;
ipa_hton ( packet - > block [ i ] . nexthop ) ;
c - > sendptr = ( void * ) ( NODE c - > sendptr ) - > next ;
}
1998-12-10 04:08:57 +08:00
DBG ( " , sending %d blocks, " , i ) ;
1998-07-29 05:44:11 +08:00
1998-10-26 23:35:19 +08:00
if ( ipa_nonzero ( c - > daddr ) )
i = sk_send_to ( s , sizeof ( struct rip_packet_heading ) + i * sizeof ( struct rip_block ) , c - > daddr , c - > dport ) ;
else
i = sk_send ( s , sizeof ( struct rip_packet_heading ) + i * sizeof ( struct rip_block ) ) ;
1998-07-29 05:44:11 +08:00
if ( i < 0 ) rip_tx_err ( s , i ) ;
if ( i > 0 ) {
1998-12-10 04:08:57 +08:00
DBG ( " it wants more \n " ) ;
1998-07-29 05:44:11 +08:00
goto givemore ;
}
1998-12-10 04:08:57 +08:00
DBG ( " blocked \n " ) ;
1998-07-29 05:44:11 +08:00
}
static void
1998-10-26 23:35:19 +08:00
rip_sendto ( struct proto * p , ip_addr daddr , int dport , struct rip_interface * rif )
1998-07-29 05:44:11 +08:00
{
1998-10-26 23:35:19 +08:00
struct iface * iface = rif - > iface ;
1998-07-29 05:44:11 +08:00
struct rip_connection * c = mb_alloc ( p - > pool , sizeof ( struct rip_connection ) ) ;
static int num = 0 ;
1998-10-26 23:35:19 +08:00
if ( rif - > busy ) {
log ( L_WARN " Interface %s is much too slow, dropping request \n " , iface - > name ) ;
return ;
}
rif - > busy = c ;
1998-10-21 00:45:53 +08:00
1998-07-29 05:44:11 +08:00
c - > addr = daddr ;
c - > proto = p ;
c - > num = num + + ;
1998-10-26 23:35:19 +08:00
c - > rif = rif ;
1998-07-29 05:44:11 +08:00
1998-10-26 23:35:19 +08:00
c - > dport = dport ;
c - > daddr = daddr ;
if ( c - > rif - > sock - > data ! = rif )
die ( " not enough send magic \n " ) ;
#if 0
1998-07-29 05:44:11 +08:00
if ( sk_open ( c - > send ) < 0 ) {
1998-10-26 23:35:19 +08:00
log ( L_ERR " Could not open socket for data send to %I:%d on %s \n " , daddr , dport , rif - > iface - > name ) ;
1998-07-29 05:44:11 +08:00
return ;
}
1998-10-26 23:35:19 +08:00
# endif
1998-07-29 05:44:11 +08:00
c - > sendptr = HEAD ( P - > rtable ) ;
add_head ( & P - > connections , NODE c ) ;
1998-10-26 23:35:19 +08:00
debug ( " Sending my routing table to %I:%d on %s \n " , daddr , dport , rif - > iface - > name ) ;
1998-07-29 05:44:11 +08:00
1998-10-26 23:35:19 +08:00
rip_tx ( c - > rif - > sock ) ;
1998-07-29 05:44:11 +08:00
}
1998-12-04 19:45:51 +08:00
struct rip_interface *
find_interface ( struct proto * p , struct iface * what )
{
struct rip_interface * i ;
1998-12-10 04:08:57 +08:00
1998-12-04 19:45:51 +08:00
WALK_LIST ( i , P - > interfaces )
if ( i - > iface = = what )
return i ;
return NULL ;
}
1998-07-29 05:44:11 +08:00
/*
* Input processing
*/
static int
process_authentication ( struct proto * p , struct rip_block * block )
{
1998-10-08 03:33:50 +08:00
/* FIXME: Should do md5 authentication */
1998-07-29 05:44:11 +08:00
return 0 ;
}
1998-10-13 22:32:18 +08:00
/* Let main routing table know about our new entry */
static void
advertise_entry ( struct proto * p , struct rip_block * b , ip_addr whotoldme )
{
rta * a , A ;
rte * r ;
net * n ;
1998-10-21 00:12:43 +08:00
neighbor * neighbor ;
1998-12-04 19:45:51 +08:00
struct rip_interface * i ;
1998-10-17 18:25:22 +08:00
1998-10-13 22:32:18 +08:00
bzero ( & A , sizeof ( A ) ) ;
A . proto = p ;
A . source = RTS_RIP ;
A . scope = SCOPE_UNIVERSE ;
A . cast = RTC_UNICAST ;
A . dest = RTD_ROUTER ;
A . tos = 0 ;
A . flags = 0 ;
A . gw = ipa_nonzero ( b - > nexthop ) ? b - > nexthop : whotoldme ;
A . from = whotoldme ;
1998-10-21 00:12:43 +08:00
neighbor = neigh_find ( p , & A . gw , 0 ) ;
if ( ! neighbor ) {
log ( L_ERR " %I asked me to route %I/%I using not-neighbor %I. \n " , A . from , b - > network , b - > netmask , A . gw ) ;
return ;
}
A . iface = neighbor - > iface ;
1998-12-10 04:08:57 +08:00
if ( ! ( i = neighbor - > data ) ) {
i = neighbor - > data = find_interface ( p , A . iface ) ;
}
1998-10-13 22:32:18 +08:00
/* set to: interface of nexthop */
a = rta_lookup ( & A ) ;
n = net_get ( & master_table , 0 , b - > network , ipa_mklen ( b - > netmask ) ) ; /* FIXME: should verify that it really is netmask */
r = rte_get_temp ( a ) ;
1998-12-04 19:45:51 +08:00
r - > u . rip . metric = ntohl ( b - > metric ) + i - > metric ;
if ( r - > u . rip . metric > P - > infinity ) r - > u . rip . metric = P - > infinity ;
1998-10-13 22:32:18 +08:00
r - > u . rip . tag = ntohl ( b - > tag ) ;
1998-10-21 00:12:43 +08:00
r - > net = n ;
1998-10-13 22:32:18 +08:00
r - > pflags = 0 ; /* Here go my flags */
rte_update ( n , p , r ) ;
1998-12-10 04:08:57 +08:00
DBG ( " done \n " ) ;
1998-10-13 22:32:18 +08:00
}
1998-07-10 03:39:04 +08:00
static void
process_block ( struct proto * p , struct rip_block * block , ip_addr whotoldme )
{
struct rip_entry * e ;
int metric = ntohl ( block - > metric ) ;
1998-07-29 05:44:11 +08:00
ip_addr network = block - > network ;
1998-07-10 03:39:04 +08:00
CHK_MAGIC ;
1998-12-02 00:17:10 +08:00
if ( ( ! metric ) | | ( metric > P - > infinity ) ) {
1998-07-10 03:39:04 +08:00
log ( L_WARN " Got metric %d from %I \n " , metric , whotoldme ) ;
return ;
}
1998-10-08 03:33:50 +08:00
/* FIXME: Check if destination looks valid - ie not net 0 or 127 */
1998-07-10 03:39:04 +08:00
1998-07-29 05:44:11 +08:00
debug ( " block: %I tells me: %I/%I available, metric %d... " , whotoldme , network , block - > netmask , metric ) ;
1998-07-10 03:39:04 +08:00
1998-10-13 22:32:18 +08:00
advertise_entry ( p , block , whotoldme ) ;
1998-07-10 03:39:04 +08:00
}
1998-07-29 05:44:11 +08:00
# define BAD( x ) { log( L_WARN "RIP / %s: " x "\n", p->name ); return 1; }
static int
1998-07-10 03:39:04 +08:00
rip_process_packet ( struct proto * p , struct rip_packet * packet , int num , ip_addr whotoldme , int port )
{
int i ;
1998-07-29 05:44:11 +08:00
int native_class = 0 ;
1998-07-10 03:39:04 +08:00
switch ( packet - > heading . version ) {
1998-12-10 04:08:57 +08:00
case RIP_V1 : DBG ( " Rip1: " ) ; break ;
case RIP_V2 : DBG ( " Rip2: " ) ; break ;
1998-07-10 03:39:04 +08:00
default : BAD ( " Unknown version " ) ;
}
switch ( packet - > heading . command ) {
1998-12-10 04:08:57 +08:00
case RIPCMD_REQUEST : DBG ( " Asked to send my routing table \n " ) ;
1998-12-09 23:22:40 +08:00
/* FIXME: should have configurable: ignore always, honour to neighbours, honour always. FIXME: use one global socket for these. FIXME: synchronization - if two ask me at same time */
1998-10-21 00:12:43 +08:00
rip_sendto ( p , whotoldme , port , NULL ) ; /* no broadcast */
1998-07-29 05:44:11 +08:00
break ;
1998-12-10 04:08:57 +08:00
case RIPCMD_RESPONSE : DBG ( " *** Rtable from %I \n " , whotoldme ) ;
1998-12-04 19:45:51 +08:00
if ( port ! = P - > port ) {
1998-10-21 00:45:53 +08:00
log ( L_ERR " %I send me routing info from port %d \n " , whotoldme , port ) ;
#if 0
1998-07-29 05:44:11 +08:00
return 0 ;
1998-10-21 00:45:53 +08:00
# else
log ( L_ERR " ...ignoring \n " ) ;
# endif
1998-07-10 03:39:04 +08:00
}
if ( ! neigh_find ( p , & whotoldme , 0 ) ) {
1998-10-21 00:45:53 +08:00
log ( L_ERR " %I send me routing info but he is not my neighbour \n " , whotoldme ) ;
1998-07-29 05:44:11 +08:00
return 0 ;
1998-07-10 03:39:04 +08:00
}
1998-10-08 03:33:50 +08:00
/* FIXME: Should check if it is not my own packet */
1998-07-10 03:39:04 +08:00
for ( i = 0 ; i < num ; i + + ) {
struct rip_block * block = & packet - > block [ i ] ;
if ( block - > family = = 0xffff )
if ( ! i ) {
if ( process_authentication ( p , block ) )
BAD ( " Authentication failed \n " ) ;
} else BAD ( " Authentication is not the first! " ) ;
1998-07-29 05:44:11 +08:00
ipa_ntoh ( block - > network ) ;
ipa_ntoh ( block - > netmask ) ;
ipa_ntoh ( block - > nexthop ) ;
if ( packet - > heading . version = = RIP_V1 ) {
block - > netmask = block - > network ; /* MJ: why are macros like this?! */
ipa_class_mask ( block - > netmask ) ;
}
1998-07-10 03:39:04 +08:00
process_block ( p , block , whotoldme ) ;
}
break ;
1998-10-08 03:33:50 +08:00
case RIPCMD_TRACEON :
case RIPCMD_TRACEOFF : BAD ( " I was asked for traceon/traceoff \n " ) ;
1998-07-10 03:39:04 +08:00
case 5 : BAD ( " Some Sun extension around here \n " ) ;
default : BAD ( " Unknown command " ) ;
}
rip_reply ( p ) ;
1998-07-29 05:44:11 +08:00
return 0 ;
1998-07-10 03:39:04 +08:00
}
1998-07-29 05:44:11 +08:00
static int
1998-07-10 03:39:04 +08:00
rip_rx ( sock * s , int size )
{
1998-10-26 23:35:19 +08:00
struct rip_interface * i = s - > data ;
struct proto * p = i - > proto ;
1998-07-10 03:39:04 +08:00
int num ;
CHK_MAGIC ;
1998-12-10 04:08:57 +08:00
DBG ( " RIP: message came: %d bytes \n " , size ) ;
1998-07-10 03:39:04 +08: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 ) ;
if ( num > 25 ) BAD ( " Too many blocks " ) ;
rip_process_packet ( p , ( struct rip_packet * ) s - > rbuf , num , s - > faddr , s - > fport ) ;
1998-07-29 05:44:11 +08:00
return 1 ;
1998-07-10 03:39:04 +08:00
}
1998-07-29 05:44:11 +08:00
/*
* Interface to rest of bird
*/
1998-07-10 03:39:04 +08:00
static void
rip_dump_entry ( struct rip_entry * e )
{
1998-10-08 03:33:50 +08:00
debug ( " %I told me %d/%d ago: to %I/%d go via %I, metric %d " ,
1998-07-29 05:44:11 +08:00
e - > whotoldme , e - > updated - now , e - > changed - now , e - > network , e - > pxlen , e - > nexthop , e - > metric ) ;
1998-10-08 03:33:50 +08:00
if ( e - > flags & RIP_F_EXTERNAL ) debug ( " [external] " ) ;
debug ( " \n " ) ;
1998-07-10 03:39:04 +08:00
}
static void
rip_timer ( timer * t )
{
struct proto * p = t - > data ;
struct rip_entry * e , * et ;
CHK_MAGIC ;
1998-12-10 04:08:57 +08:00
DBG ( " RIP: tick tock \n " ) ;
1998-10-21 00:12:43 +08:00
WALK_LIST_DELSAFE ( e , et , P - > garbage ) {
rte * rte ;
rte = SKIP_BACK ( struct rte , u . rip . garbage , e ) ;
1998-12-10 04:08:57 +08:00
DBG ( " Garbage: " ) ; rte_dump ( rte ) ;
1998-10-21 00:12:43 +08:00
1998-12-04 19:45:51 +08:00
if ( now - rte - > lastmod > P - > garbage_time ) {
1998-10-21 00:12:43 +08:00
debug ( " RIP: entry is too old: " ) ; rte_dump ( rte ) ;
rte_discard ( rte ) ;
}
1998-07-10 03:39:04 +08:00
}
1998-07-29 05:44:11 +08:00
1998-12-10 04:08:57 +08:00
DBG ( " RIP: Broadcasting routing tables \n " ) ;
1998-10-21 00:12:43 +08:00
{
1998-10-26 23:35:19 +08:00
struct rip_interface * i ;
WALK_LIST ( i , P - > interfaces ) {
struct iface * iface = i - > iface ;
1998-07-29 05:44:11 +08:00
1998-10-21 00:12:43 +08:00
if ( ! ( iface - > flags & IF_UP ) ) continue ;
if ( iface - > flags & ( IF_IGNORE | IF_LOOPBACK ) ) continue ;
1998-10-26 23:35:19 +08:00
rip_sendto ( p , IPA_NONE , 0 , i ) ;
1998-10-21 00:12:43 +08:00
}
}
1998-10-08 03:33:50 +08:00
1998-12-10 04:08:57 +08:00
DBG ( " RIP: tick tock done \n " ) ;
1998-07-10 03:39:04 +08:00
}
static void
rip_start ( struct proto * p )
{
1998-12-10 04:08:57 +08:00
DBG ( " RIP: starting instance... \n " ) ;
1998-07-10 03:39:04 +08:00
P - > magic = RIP_MAGIC ;
init_list ( & P - > rtable ) ;
init_list ( & P - > connections ) ;
1998-10-21 00:12:43 +08:00
init_list ( & P - > garbage ) ;
1998-10-26 23:35:19 +08:00
init_list ( & P - > interfaces ) ;
1998-07-10 03:39:04 +08:00
P - > timer = tm_new ( p - > pool ) ;
P - > timer - > data = p ;
P - > timer - > randomize = 5 ;
1998-12-04 19:45:51 +08:00
P - > timer - > recurrent = P - > period ;
1998-07-10 03:39:04 +08:00
P - > timer - > hook = rip_timer ;
1998-07-29 05:44:11 +08:00
tm_start ( P - > timer , 5 ) ;
1998-10-15 23:12:24 +08:00
CHK_MAGIC ;
1998-07-10 03:39:04 +08:00
1998-12-10 04:08:57 +08:00
DBG ( " RIP: ...done \n " ) ;
1998-07-10 03:39:04 +08:00
}
static void
rip_init ( struct protocol * p )
{
1998-12-10 04:08:57 +08:00
DBG ( " RIP: initializing RIP... \n " ) ;
1998-07-10 03:39:04 +08:00
}
static void
rip_dump ( struct proto * p )
{
int i ;
node * w , * e ;
1998-10-26 23:35:19 +08:00
struct rip_interface * rif ;
1998-07-10 03:39:04 +08:00
i = 0 ;
WALK_LIST ( w , P - > connections ) {
1998-07-29 05:44:11 +08:00
struct rip_connection * n = ( void * ) w ;
debug ( " RIP: connection #%d: %I \n " , n - > num , n - > addr ) ;
1998-07-10 03:39:04 +08:00
}
i = 0 ;
WALK_LIST ( e , P - > rtable ) {
debug ( " RIP: entry #%d: " , i + + ) ;
rip_dump_entry ( E ) ;
}
1998-10-26 23:35:19 +08:00
i = 0 ;
WALK_LIST ( rif , P - > interfaces ) {
1998-12-09 23:22:40 +08: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 23:35:19 +08:00
}
}
static int
rip_want_this_if ( struct rip_interface * iface )
{
return 1 ;
}
static void
kill_iface ( struct proto * p , struct rip_interface * i )
{
1998-12-10 04:08:57 +08:00
DBG ( " RIP: Interface %s disappeared \n " , i - > iface - > name ) ;
1998-10-26 23:35:19 +08:00
rfree ( i - > sock ) ;
mb_free ( i ) ;
}
1998-12-09 23:22:40 +08:00
/*
* new maybe null if we are creating initial send socket
*/
1998-10-26 23:35:19 +08:00
struct rip_interface *
1998-12-09 23:22:40 +08:00
new_iface ( struct proto * p , struct iface * new , unsigned long flags )
1998-10-26 23:35:19 +08:00
{
1998-12-09 23:22:40 +08:00
struct rip_interface * rif ;
int want_multicast ;
rif = mb_alloc ( p - > pool , sizeof ( struct rip_interface ) ) ;
rif - > iface = new ;
rif - > proto = p ;
want_multicast = 0 & & ( flags & IF_MULTICAST ) ;
/* FIXME: should have config option to disable this one */
rif - > sock = sk_new ( p - > pool ) ;
rif - > sock - > type = want_multicast ? SK_UDP_MC : SK_UDP ;
rif - > sock - > sport = P - > port ;
rif - > sock - > rx_hook = rip_rx ;
rif - > sock - > data = rif ;
rif - > sock - > rbsize = 10240 ;
rif - > sock - > iface = new ;
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 ;
rif - > sock - > dport = P - > port ;
rif - > sock - > ttl = 1 ; /* FIXME: care must be taken not to send requested responses from this socket */
if ( want_multicast )
rif - > sock - > daddr = ipa_from_u32 ( 0x7f000001 ) ; /* FIXME: must lookup address in rfc's */
if ( flags & IF_BROADCAST )
rif - > sock - > daddr = new - > brd ;
if ( flags & IF_UNNUMBERED )
rif - > sock - > daddr = new - > opposite ;
if ( ! ipa_nonzero ( rif - > sock - > daddr ) )
log ( L_WARN " RIP: interface %s is too strange for me " , rif - > iface - > name ) ;
if ( sk_open ( rif - > sock ) < 0 )
die ( " RIP/%s: could not listen on %s \n " , p - > name , rif - > iface - > name ) ;
1998-10-26 23:35:19 +08:00
1998-12-09 23:22:40 +08:00
return rif ;
1998-07-10 03:39:04 +08:00
}
1998-07-29 05:44:11 +08:00
static void
rip_if_notify ( struct proto * p , unsigned c , struct iface * old , struct iface * new )
{
1998-12-10 04:08:57 +08:00
DBG ( " RIP: if notify \n " ) ;
1998-10-26 23:35:19 +08:00
if ( old ) {
struct rip_interface * i ;
1998-12-04 19:45:51 +08:00
i = find_interface ( p , old ) ;
if ( i ) {
rem_node ( NODE i ) ;
kill_iface ( p , i ) ;
}
1998-10-26 23:35:19 +08:00
}
if ( new ) {
1998-12-09 23:22:40 +08:00
struct rip_interface * rif ;
1998-12-04 19:45:51 +08:00
struct iface_patt * k = iface_patt_match ( & P - > iface_list , new ) ;
if ( ! k ) return ; /* We are not interested in this interface */
1998-12-09 23:22:40 +08:00
DBG ( " adding interface %s \n " , new - > name ) ;
rif = new_iface ( p , new , new - > flags ) ;
rif - > metric = k - > u . rip . metric ;
add_head ( & P - > interfaces , NODE rif ) ;
1998-10-26 23:35:19 +08:00
}
1998-07-29 05:44:11 +08:00
}
1998-10-08 03:33:50 +08:00
static void
rip_rt_notify ( struct proto * p , struct network * net , struct rte * new , struct rte * old )
{
1998-10-15 23:12:24 +08:00
CHK_MAGIC ;
1998-10-08 03:33:50 +08:00
if ( old ) {
struct rip_entry * e = find_entry ( p , net - > n . prefix , net - > n . pxlen ) ;
1998-10-15 23:12:24 +08:00
1998-10-08 03:33:50 +08:00
if ( ! e )
log ( L_ERR " Deleting nonexistent entry?! \n " ) ;
kill_entry_ourrt ( p , e ) ;
}
if ( new ) {
struct rip_entry * e = new_entry ( p ) ;
e - > network = net - > n . prefix ;
e - > pxlen = net - > n . pxlen ;
1998-10-17 18:25:22 +08:00
e - > nexthop = new - > attrs - > gw ;
1998-10-13 22:32:18 +08:00
e - > tag = new - > u . rip . tag ;
e - > metric = new - > u . rip . metric ;
1998-10-17 18:25:22 +08:00
e - > whotoldme = new - > attrs - > from ;
1998-10-08 03:33:50 +08:00
e - > updated = e - > changed = now ;
1998-10-13 22:32:18 +08:00
e - > flags = 0 ;
add_head ( & P - > rtable , NODE e ) ;
1998-10-08 03:33:50 +08:00
}
}
1998-10-21 00:12:43 +08:00
static int
1998-10-13 22:32:18 +08:00
rip_rte_better ( struct rte * new , struct rte * old )
{
if ( old - > u . rip . metric < new - > u . rip . metric )
return 0 ;
if ( old - > u . rip . metric > new - > u . rip . metric )
return 1 ;
# define old_metric_is_much_older_than_new_metric 0
if ( ( old - > u . rip . metric = = new - > u . rip . metric ) & & ( old_metric_is_much_older_than_new_metric ) )
return 1 ;
return 0 ;
}
1998-10-15 23:12:24 +08:00
static int
rip_rta_same ( rta * a , rta * b )
{
/* As we have no specific data in rta, they are always the same */
return 1 ;
}
1998-10-21 00:12:43 +08:00
static void
rip_rte_insert ( net * net , rte * rte )
{
struct proto * p = rte - > attrs - > proto ;
add_head ( & P - > garbage , & rte - > u . rip . garbage ) ;
}
static void
rip_rte_remove ( net * net , rte * rte )
{
struct proto * p = rte - > attrs - > proto ;
rem_node ( & rte - > u . rip . garbage ) ;
}
1998-11-28 05:08:37 +08:00
void
rip_init_instance ( struct proto * p )
1998-07-10 03:39:04 +08:00
{
1998-10-21 00:12:43 +08:00
p - > preference = DEF_PREF_RIP ;
1998-07-10 03:39:04 +08:00
p - > start = rip_start ;
p - > if_notify = rip_if_notify ;
1998-10-08 03:33:50 +08:00
p - > rt_notify = rip_rt_notify ;
1998-10-13 22:32:18 +08:00
p - > rte_better = rip_rte_better ;
1998-10-15 23:12:24 +08:00
p - > rta_same = rip_rta_same ;
1998-10-21 00:12:43 +08:00
p - > rte_insert = rip_rte_insert ;
p - > rte_remove = rip_rte_remove ;
1998-07-10 03:39:04 +08:00
p - > dump = rip_dump ;
1998-12-04 19:45:51 +08:00
P - > infinity = 16 ;
P - > port = 520 ;
P - > period = 30 ;
P - > garbage_time = 120 + 180 ;
init_list ( & P - > iface_list ) ;
1998-07-10 03:39:04 +08:00
}
1998-11-28 05:08:37 +08:00
static void
rip_preconfig ( struct protocol * x )
{
1998-12-10 04:08:57 +08:00
DBG ( " RIP: preconfig \n " ) ;
1998-11-28 05:08:37 +08:00
}
1998-07-10 03:39:04 +08:00
static void
rip_postconfig ( struct protocol * p )
{
1998-12-09 23:22:40 +08:00
new_iface ( p , NULL , 0 ) ;
1998-07-10 03:39:04 +08:00
}
struct protocol proto_rip = {
{ NULL , NULL } ,
" RIP " ,
0 ,
rip_init ,
rip_preconfig ,
rip_postconfig
} ;