/* File IPXRIP.C : IPX Routing Information Protocol functions
*/
/*
Copyright (C) 1992 Indian Institute of Technology, Bombay
Written by V. Srinivas and Vishwas Joglekar,
Dept of Computer Science and Engineering.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "yapcbr.h"
#include "ipxwatch.h"
#include "ipxrip.h"
#include "diag.h"
extern struct rip_table *rip_lookup[];
extern struct rxstruct *rxptr;
extern struct my_route my_route_info;
extern struct ipxpktdv Ipxpktdv;
extern struct network_info *net_lookup(BYTE *net_id,int append_flag);
extern WORD getword(BYTE *);
void nlist();
int rip_hash_lookup(int hashret,RIP_INFO *route_info,BYTE *router_id );
void disp_route_info(ROUT_TABLE *rip_ptr);
void proc_rip_pkt(RIP_PKT *rip_pkt,unsigned char *disp,int bcast);
int check_more(int *row);
void *ibuf_alloc(int type);
ROUT_TABLE *find_route(BYTE *net_id);
/* search for the network/route information in the hashed list */
int rip_hash_lookup(int hashret,RIP_INFO *route_info,BYTE *router_id )
{
ROUT_TABLE *new_addr,*tmp,*hash_ptr;
WORD new_tick,old_tick;
int alt_route;
alt_route = FALSE;
hash_ptr = rip_lookup[hashret];
tmp=hash_ptr;
if((route_info->no_of_hops & 0x0f00) > 0x0f00 ) return(NOTFOUND);
#ifdef DBG1
cprintf("Searching Hash table, bucket %d\n",hashret);
#endif
while(hash_ptr != 0){
/* add the network information into the network information table */
/* is the route already known ? */
if(memcmp(hash_ptr->route_info.net_id,route_info->net_id,NET_ID_LEN) == 0){
/* check whether it is a new/faster route or the same */
new_tick = getword((BYTE *)&route_info->no_of_ticks);
if( new_tick > hash_ptr->route_info.no_of_ticks)
return(FOUND); /* new route is a slower route, discard */
if( new_tick < hash_ptr->route_info.no_of_ticks){
/* the new route is a faster route, delete the old route info */
hash_ptr->route_info.no_of_ticks = new_tick;
hash_ptr->route_info.no_of_hops = getword((BYTE *)&route_info->no_of_hops);
hash_ptr->dev = rxptr->dev; /* save the NIC no */
hash_ptr->age_timer = FLUSH_TIME; /* 60 secs timer */
memcpy(hash_ptr->router_id,router_id,ETHER_ADDR_LEN);
hash_ptr->alternate_route = 0;
return(FOUND);
}
else{ /* Is it is an alternate route with the same number of ticks ? */
if(memcmp(hash_ptr->router_id,router_id,ETHER_ADDR_LEN) == 0){
/* same route, reset the timer */
hash_ptr->age_timer = FLUSH_TIME; /* 60 secs timer */
return(FOUND);
}
else{
alt_route = TRUE;
break;
}
}
}
tmp = hash_ptr;
hash_ptr = hash_ptr->next;
} /* while */
/* address not in table, add */
new_addr = (struct rip_table *)ibuf_alloc(NOVLRIP);
if(new_addr == 0) {
printf("Malloc failed \n");
return(0);
}
memcpy(new_addr->route_info.net_id,route_info->net_id,NET_ID_LEN);
new_addr->route_info.no_of_ticks = getword((BYTE *)&route_info->no_of_ticks);
new_addr->route_info.no_of_hops = getword((BYTE *) &route_info->no_of_hops);
new_addr->dev = rxptr->dev; /* save the NIC no */
memcpy(new_addr->router_id,router_id,ETHER_ADDR_LEN);
new_addr->alternate_route = 0;
new_addr->next = 0;
new_addr->age_timer = FLUSH_TIME; /* 60 sec timer */
new_addr->net_status = 0;
if(alt_route == TRUE){ /* it is an alternate route */
hash_ptr->alternate_route = new_addr;
return(NOTFOUND);
}
if(tmp == 0) /* is this bucket empty ? */
rip_lookup[hashret] = new_addr;
else /* the bucket is not empty */
tmp->next = new_addr;
net_lookup(route_info->net_id,TRUE); /* update the network information table */
return(NOTFOUND);
}
/* list all the networks & the correspond routers by looking at the
route information table
*/
void nlist()
{
int i,temp,count=0;
ROUT_TABLE *rip_ptr;
make_win(8,5,74,22,1,"ROUTING INFORMATION");
disp_mesg("ESC Close Window");
make_win(9,6,73,21,1,"Network Router Address Hops Ticks Net Status Age Timer");
gotoxy(1,1);
_setcursortype(_NOCURSOR);
for(i=0;i< MAX_PRIME;i++){
rip_ptr = rip_lookup[i];
while(rip_ptr!= 0){
disp_route_info(rip_ptr);
if(check_more(&count) == ESC) return;
if(rip_ptr->alternate_route != 0){
disp_route_info(rip_ptr->alternate_route);
if(check_more(&count) == ESC) return;
}
rip_ptr = rip_ptr->next;
}/* while */
} /* for */
while(read_key()!= ESC);
}
/* Display routing table info */
void disp_route_info(ROUT_TABLE *rip_ptr)
{
unsigned char buff[50];
buff[0] = '\0';
prnt_hex(rip_ptr->route_info.net_id,buff,4);
cprintf(" %s ",buff);
/* cprintf("%2d ",rip_ptr->dev); */
buff[0] = '\0';
prnt_hex(rip_ptr->router_id,buff,6);
cputs(buff);
cprintf(" %.2u ",rip_ptr->route_info.no_of_hops);
cprintf(" %.2u ",rip_ptr->route_info.no_of_ticks);
cprintf(" %.2u ",rip_ptr->net_status);
cprintf(" %.4u \r\n",rip_ptr->age_timer);
}
/* Determine the type of RIP packet */
void proc_rip_pkt(RIP_PKT *rip_pkt,unsigned char *disp,int bcast)
{
WORD resp_type,len;
struct network_info *my_net;
extern struct network_info *current_net;
int i,no_of_routes,hashret;
resp_type = getword(rip_pkt->type); /* get rip pkt type */
switch(resp_type){
case ROUTE_REQUEST: /* route request pkt */
sprintf(disp,"Route Request -> ");
prnt_hex(rip_pkt->route_info[0].net_id,disp+strlen(disp),4);
break;
case ROUTE_RESP:
/* respose to a route request or a periodic broadcast */
if(bcast == TRUE){
/* It is a broadcast packet from a router, update
the router information table */
len = getword(rip_pkt->header.length); /* get length of IPX packet */
no_of_routes = (len-sizeof(IPX_HEADER) - sizeof(WORD))/sizeof(RIP_INFO);
if(no_of_routes >MAX_ROUTES) return; /* invalid rip packet */
sprintf(disp,"Route Info ");
/* get my network address by looking at the ipx header */
my_net = net_lookup(rip_pkt->header.source_node.net_id,TRUE);
if(current_net == 0){
current_net = my_net;
memcpy(my_route_info.route_info.net_id,my_net->net_id,4);
memcpy(Ipxpktdv.net_id,my_net->net_id,4);
}
hashret = hash_addr(my_net->net_id,4);
rip_hash_lookup(hashret,&my_route_info.route_info,my_route_info.router_id);
for(i=0;i<no_of_routes;i++){
hashret = hash_addr(rip_pkt->route_info[i].net_id,4);
rip_hash_lookup(hashret,&rip_pkt->route_info[i],rip_pkt->header.source_node.node_id);
}
}
else sprintf(disp,"Route Response ");
prnt_hex(rip_pkt->route_info[0].net_id,disp+strlen(disp),4);
sprintf(disp+strlen(disp),"%2.2d/%2.2d",getword((BYTE *) &rip_pkt->route_info[0].no_of_hops),
getword((BYTE *) &rip_pkt->route_info[0].no_of_ticks));
break;
default: break;
}
}
int check_more(int *pos)
{
int k =0;
fflush(stdin);
(*pos)++;
if(*pos == 13){
*pos=1;
gotoxy(5,20);
highvideo();
cprintf("More");
lowvideo();
k = getch();
}
else if(kbhit()!= 0)k= getch();
return(k);
}
/* determines the route to a given network and returns a pointer to the
routing information table, containing the router id and other information */
ROUT_TABLE *find_route(BYTE *net_id)
{
int hash_indx;
ROUT_TABLE *oldptr;
hash_indx = hash_addr(net_id,4);
for(oldptr = rip_lookup[hash_indx];oldptr != 0; oldptr = oldptr->next){
/* is the route already known ? */
if(memcmp(oldptr->route_info.net_id,net_id,NET_ID_LEN) == 0)
return(oldptr);
}
return(0);
}