Metropoli BBS
VIEWER: diag.c MODE: TEXT (ASCII)
/* File diag.c : IPX/SPX diagnostic 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 "diag.h"
#include "ipxrip.h"

extern BYTE *putword(WORD x,BYTE *s);
extern struct  ipxpktdv Ipxpktdv;
extern struct network_info *network_info_table[];
extern void wprintf(BYTE *str, int len,int video_mode,int scroll);
extern int read_key();
extern void pause(char *s);
extern int send_diag;
extern struct network_info *current_net, *pred_net;
extern void  disp_mesg(char *mesg);
extern void make_win(int x1,int y1,int x2,int y2, int box_type, char *mesg);

ROUT_TABLE *find_route(BYTE *net_id);

void send_config_req(INTERNET_ADDRESS *source,INTERNET_ADDRESS *dest,
			WORD len,BYTE excln_cnt,BYTE *excln_addr[6]);
NODE_INFO *node_lookup(INTERNET_ADDRESS *node_address, struct nodes_on_net *node_info,int append_flag);
void proc_diag_pkt(IPX_PKT *diag_pkt);
void send_diag_pkt(BYTE *dest_node, BYTE *dest_net);
void disp_node_info(NODE_INFO *node_info);

struct network_info *net_lookup(BYTE *net_id, int append_flag);
NODE_INFO *next_node(int *index,struct nodes_on_net *head,NODE_INFO *curr_node_ptr);
NODE_INFO *prev_node(int *index,struct nodes_on_net *head,NODE_INFO *curr_node_ptr);
struct network_info *next_net(struct network_info *present_net, int *index);
struct network_info *prev_net(struct network_info *present_net, int *index);
BYTE find_component_type(BYTE component_cnt,BYTE *components);


/* send diagnostic configuration request packet to the specifed node */
void send_diag_pkt(BYTE *dest_node, BYTE *dest_net)
{
BYTE dest_sock[] = {0x04,0x56};
WORD len;
INTERNET_ADDRESS src,dest;
ROUT_TABLE *rip_ptr;

memcpy(src.node_id,Ipxpktdv.eaddr,6);
memcpy(src.net_id,Ipxpktdv.net_id,4);
memcpy(src.socket,dest_sock,2);
memcpy(dest.node_id,dest_node,6);
memcpy(dest.net_id,dest_net,4);
memcpy(dest.socket,dest_sock,2);
len = 31;
send_config_req(&src,&dest,len,0,NULL);
}


void send_config_req(INTERNET_ADDRESS *source,INTERNET_ADDRESS *dest,
			WORD len,BYTE excln_cnt,BYTE *excln_addr[6])
{
ETH_IPX pkt;
BYTE ipxtype[3] = {0x81,0x37};
BYTE checksum[3] = {0xff,0xff}; /* ipx doesn't use checksum   */
BYTE tmp[3];
ROUT_TABLE *rip_ptr;
memcpy(pkt.source,source->node_id,ETHER_ADDR_LEN);
/* find the route to the destination   network    */
if(current_net != 0){ /* the destination network address is not known */
    rip_ptr = find_route(dest->net_id);
   if(rip_ptr == 0)
       return; /* no route to the given network */
   if(rip_ptr->route_info.no_of_hops == 0x00) /* it is on the same network */
      memcpy(pkt.destination,dest->node_id,ETHER_ADDR_LEN);
   else /* route it through the router  */
      memcpy(pkt.destination,rip_ptr->router_id,ETHER_ADDR_LEN);
}
else memcpy(pkt.destination,dest->node_id,ETHER_ADDR_LEN);
 memcpy(pkt.type,ipxtype,2);
memcpy(&pkt.pkt.header.source_node,source,sizeof(INTERNET_ADDRESS));
memcpy(&pkt.pkt.header.dest_node,dest,sizeof(INTERNET_ADDRESS));
memcpy(&pkt.pkt.header.length,putword(len,tmp),2);
pkt.pkt.header.transport_control = 0;
memcpy(pkt.pkt.header.checksum,checksum,2);
pkt.pkt.header.packet_type = 0; /* ipx packet */
if(excln_cnt == 0x00)
   pkt.pkt.data[0] = 0x00;
else
   memcpy(&(pkt.pkt.data)+1,excln_addr,ETHER_ADDR_LEN*excln_cnt);
/* On ethernet Minimum pkt length is 60 bytes */
if (Ipxpktdv.ether_type == ETHERNET_II) len = 60;
else len +=14;
if(send_pkt(Ipxpktdv.intno,&pkt,60) == -1)
   cprintf("\r\nERROR sending diagnostic req pkt\r\n ");
}



/* determine the type of diagnostic response pkt and update the network and node
information table */

void proc_diag_pkt(IPX_PKT *diag_pkt)
{
NODE_INFO  *node_info, *node_add;
struct network_info *net_add;
CONFIG_RESP_PKT *config;
int hash_ret;

if(diag_pkt->header.packet_type == 0 || diag_pkt->header.packet_type == 4){
   net_add = net_lookup(diag_pkt->header.source_node.net_id,TRUE);
   if(net_add != 0)
      node_add = node_lookup(&diag_pkt->header.source_node,&net_add->node_info,TRUE);
      /* update the node information table, node statistics */
      if(node_add != 0){
	 config = (CONFIG_RESP_PKT *)diag_pkt;
	 node_add->component_cnt = config->component_cnt;
	 memcpy(node_add->components,config->components,9);
	 node_add->status = ACTIVE;
      }
}
}

NODE_INFO *node_lookup(INTERNET_ADDRESS *node_address, struct nodes_on_net *node_info,int append_flag)
{
 NODE_INFO *hash_ptr,*tmp_ptr,*res,*oldptr;
int hash_indx,ch;
BYTE buf[13];
hash_indx = hash_addr(node_address->node_id,ETHER_ADDR_LEN);
hash_ptr = node_info->node_info_table[hash_indx].head;
oldptr = hash_ptr;
for(tmp_ptr = hash_ptr;tmp_ptr != 0; tmp_ptr = tmp_ptr->next){
     /* is the node info already known  */
   if(memcmp(tmp_ptr->node_addr.node_id,node_address->node_id,6) == 0){
      tmp_ptr->status = ACTIVE;
      tmp_ptr->clock_ticks = DIAG_TX_INTERVAL * DIAG_RETRIES;
      return(tmp_ptr);
    }
    oldptr = tmp_ptr;
}
if(append_flag != TRUE) return(0);
/* append the new entry at the end of the current bucket */
res = (NODE_INFO *)malloc(sizeof(NODE_INFO));
if(res == 0) return(0);
/* increment the node count */
node_info->node_count++;
memcpy(&res->node_addr,node_address,sizeof(INTERNET_ADDRESS));
res->status = INACTIVE;
res->clock_ticks = DIAG_TX_INTERVAL * DIAG_RETRIES;
res->next = 0;
res->name[0] = '\0';
if(oldptr == 0){
   node_info->node_info_table[hash_indx].head = res;
   res->prev = 0;
}
else{
   oldptr->next = res;
   res->prev = oldptr;
}
node_info->node_info_table[hash_indx].tail = res;
#ifdef DIAG_DBG
buf[0]='\0';
prnt_hex(hash_ptr->node_addr.node_id,buf,6);
cprintf("\r\n node added %s\r\n ",buf);
#endif
return(res);
}


/* display the node information table  */
void node_list()
{
extern struct network_info *current_net;
int i,crow,nodes,node_count=0,ch,y;
NODE_INFO *tmpptr,*oldptr;
unsigned char buf[25];
struct nodes_on_net   *head, *tmp_head;

restore();
_setcursortype(_NOCURSOR);
make_win(1,2,78,24,2,"NODE INFORMATION" );
if(current_net == 0){
   pause("No networks selected");
   return;
}
current_net = net_lookup(current_net->net_id,TRUE);
head =&current_net->node_info;
tmp_head = head;
nodes = node_count = head->node_count; /* no of nodes in the network  */
if(node_count == 0){
  pause("No nodes are active on this network");
  return;
}

reverse();
gotoxy(3,4);
buf[0]='\0';
prnt_hex(current_net->net_id,buf,4);
gotoxy(2,1);
cprintf("Network  %s                                           Nodes  %u",buf,head->node_count);
window(1,1,80,25);
restore();
make_win(3,5,17,21,1,"Node Address");
crow =i=0;
gotoxy(1,1);
tmpptr = head->node_info_table[i].head;
if(tmpptr == 0) tmpptr=next_node(&i,head,tmpptr);
if(strlen(tmpptr->name) >0){
 reverse();
 cprintf("%-12s",tmpptr->name);
 restore();
}
else wprintf(tmpptr->node_addr.node_id,6,REVERSE,FALSE);
crow=1;
while(tmpptr != 0 && crow <14 && i < MAX_PRIME ){
   tmpptr=next_node(&i,head,tmpptr);
   if(tmpptr != 0){
      gotoxy(1,wherey()+1);
      if(strlen(tmpptr->name) >0) cprintf("%-12s",tmpptr->name);
      else  wprintf(tmpptr->node_addr.node_id,6,NORMAL,FALSE);
      crow++;
   }
}
i=0;
crow=1;
head = &current_net->node_info;
tmpptr = head->node_info_table[i].head;
if(tmpptr == 0) tmpptr=next_node(&i,head,tmpptr);
disp_mesg("ESC Close Window                                           Enter - Node Status ");
gotoxy(1,1);
disp_node_info(tmpptr);
while(1){
    ch = read_key();
    switch(ch){
    case ESC :          return;


    case  UP_ARROW  :        /* scroll up by one line */
			  buf[0] = '\0';
			  oldptr=tmpptr;
			  tmpptr = prev_node(&i,head,tmpptr);
			  if(tmpptr ==  0 || nodes >= node_count){
			    tmpptr = next_node(&i,head,tmpptr);
			    break;
			  }
			  y=wherey();gotoxy(1,y);
			  if(strlen(oldptr->name) >0) cprintf("%-12s",oldptr->name);
			  else  wprintf(oldptr->node_addr.node_id,6,NORMAL,FALSE);
			  if(nodes < node_count && crow == 1) scroll_down(1,1);
			  else{
			     crow--;
			     gotoxy(1,y-1);
			  }
			  if(strlen(tmpptr->name) >0) {
			     reverse();
			     cprintf("%-12s",tmpptr->name);
			     restore();
			  }
			  else wprintf(tmpptr->node_addr.node_id,6,REVERSE,FALSE);
			  disp_node_info(tmpptr);
			  nodes++;
			  break;


    case  DOWN_ARROW :    /* scroll down by one line   */
			  buf[0] = '\0';
			  oldptr = tmpptr;
			  tmpptr=next_node(&i,head,tmpptr);
			  if(nodes <=1 || tmpptr == 0){
			     tmpptr = prev_node(&i,head,tmpptr);
			     break;
			  }
			  y=wherey();
			  gotoxy(1,y);
			  if(strlen(oldptr->name) >0) cprintf("%-12s",oldptr->name);
			  else wprintf(oldptr->node_addr.node_id,6,NORMAL,FALSE);
			  if(tmpptr != 0){
			     if(nodes > 1 && crow >= 14 ) scroll_up(1,1,14);
			     else{
				crow++;
				gotoxy(1,y+1);
			     }
			     if(strlen(tmpptr->name) >0){
				reverse();
				cprintf("%-12s",tmpptr->name);
				restore();
			     }
			     else wprintf(tmpptr->node_addr.node_id,6,REVERSE,FALSE);
			     disp_node_info(tmpptr);
			     nodes--;
			  }
			  break;

   default :              break;

   }
  }
}

/* scan the node information table to find the successor of the given node  */

NODE_INFO *next_node(int *index,struct nodes_on_net *head,NODE_INFO *curr_node_ptr)
{
if(curr_node_ptr != 0) curr_node_ptr=curr_node_ptr->next;
while(curr_node_ptr == 0 && *index < (MAX_PRIME-1)){
   (*index)++;
   curr_node_ptr=head->node_info_table[*index].head;
}
if(*index >= MAX_PRIME) return(0);
return(curr_node_ptr);
}

/* scan the node information table to find the predecessor of the given node  */

NODE_INFO *prev_node(int *index,struct nodes_on_net *head,NODE_INFO *curr_node_ptr)
{
if(curr_node_ptr != 0) curr_node_ptr=curr_node_ptr->prev;
while(curr_node_ptr == 0 && *index >= 1){
   (*index)--;
   curr_node_ptr=head->node_info_table[*index].tail;
};
if(*index < 0 || curr_node_ptr == 0)return(0);
return(curr_node_ptr);
}



/*** search the network information table and return the pointer to the
     table if the given net_id is found in the table otherwise if the
     append flag is true then the new node is added to the table and a
     pointer to the new node is returned
***/
struct network_info *net_lookup(BYTE *net_id, int append_flag)
  {
  int net_hash_ret;
  struct network_info *tmpptr1,*tmpptr2,*oldptr;
  register int i;

  net_hash_ret = hash_addr(net_id,4);
  oldptr  = network_info_table[net_hash_ret];
  for(tmpptr1=network_info_table[net_hash_ret];tmpptr1!=0;tmpptr1=tmpptr1->next){
     if(memcmp(net_id,tmpptr1->net_id,4) == 0)
	   return(tmpptr1);
     oldptr = tmpptr1;
  }
  if(append_flag == FALSE)return(0);
  tmpptr2 = (struct network_info *)malloc(sizeof(struct network_info));
  if(tmpptr2 == 0) return(0);
  memcpy(tmpptr2->net_id,net_id,4);
  tmpptr2->next = 0;
  tmpptr2->name[0] = '\0';
  for(i=0;i<MAX_PRIME;i++)
    tmpptr2->node_info.node_info_table[i].head = tmpptr2->node_info.node_info_table[i].tail = 0;
  tmpptr2->node_info.node_count = 0;
  if(network_info_table[net_hash_ret] == 0){
     tmpptr2->prev = 0;
     network_info_table[net_hash_ret] = tmpptr2;
  }
  else{
     oldptr->next = tmpptr2;
     tmpptr2->prev = oldptr;
  }
#ifdef DIAG_DBG
  cprintf("\r\n net added \r \n");
#endif
  return(tmpptr2);
 }


/* display the all known networks */
void net_list()
{
extern struct network_info *current_net;
int i,crow,nodes,net_count=0,curs_pos,ch,y;
unsigned char buf[25];
struct network_info  *head, *oldptr, *tmpptr;

_setcursortype(_NOCURSOR);
make_win(8,5,19,22,2,"Networks");
crow =i=0;
tmpptr = network_info_table[i];
if(tmpptr == 0) tmpptr = next_net(tmpptr,&i);
if(tmpptr == 0){
   pause("No known networks");
   return;
}
if(strlen(tmpptr->name) >0) {
reverse();
cprintf("%-8.8s",tmpptr->name);
restore();
}else wprintf(tmpptr->net_id,4,REVERSE,FALSE);
crow=1;
while(tmpptr != 0 && crow <15){
   tmpptr=next_net(tmpptr,&i);
   if(tmpptr != 0){
      y=wherey();
      gotoxy(1,y+1);
      if(strlen(tmpptr->name) >0) {
	 cprintf("%-8.8s",tmpptr->name);
       }else wprintf(tmpptr->net_id,4,NORMAL,FALSE);
      crow++;
   }
}
i=0;
tmpptr = network_info_table[i];
if(tmpptr == 0) tmpptr=next_net(tmpptr,&i);
gotoxy(1,1);
net_count = 1;
disp_mesg("Esc Close Window                                           Enter Select Network");
while(1){
   ch = read_key();
    switch(ch){
    case ESC :          return;

    case CR :             if(tmpptr != 0){
			     pred_net = current_net;
			     current_net = tmpptr;
			     send_diag = TRUE;
			  }
			  break;

   case  DOWN_ARROW :        /* scroll up by one line */

			  oldptr = tmpptr;
			  tmpptr = next_net(tmpptr,&i);
			  if(tmpptr == 0){
			     tmpptr = prev_net(tmpptr,&i);
			     break;
			  }
			  buf[0] = '\0';
			  y=wherey();
			  gotoxy(1,y);
			  if(strlen(oldptr->name) >0){
			     cprintf("%-8.8s",oldptr->name);
			  }else wprintf(oldptr->net_id,4,NORMAL,FALSE);
			  if(net_count >= 14) scroll_up(1,1,14);
			  else{
			     crow++;
			     gotoxy(1,y+1);
			  }
			  net_count++;
			  if(strlen(tmpptr->name) >0) {
			      reverse();
			      cprintf("%-8.8s",tmpptr->name);
			      restore();
			  }else  wprintf(tmpptr->net_id,4,REVERSE,FALSE);
			  break;

    case UP_ARROW :    /* scroll down by one line   */
			  if(net_count <= 1) break;
			  buf[0] = '\0';
			  oldptr = tmpptr;
			  tmpptr = prev_net(tmpptr,&i);
			  if(tmpptr == 0){
			     tmpptr = next_net(tmpptr,&i);
			     break;
			  }
			  y=wherey();gotoxy(1,y);
			     if(strlen(oldptr->name) >0) {
				 cprintf("%-8.8s",oldptr->name);
			    }else wprintf(oldptr->net_id,4,NORMAL,FALSE);
			  if(net_count >= 14) scroll_down(1,1);
			  else{
			  gotoxy(1,y-1);
			  crow--;
			  }
			  if(strlen(tmpptr->name) >0) {
			     reverse();
			     cprintf("%-8.8s",tmpptr->name);
			     restore();
			  }else wprintf(tmpptr->net_id,4,REVERSE,FALSE);
			  net_count--;
			  break;
   }
  }
}

/* determine the successor of the current network      */

struct network_info *next_net(struct network_info *present_net, int *index)
{

if(present_net != 0) present_net = present_net->next;
while(present_net==0 && *index < (MAX_PRIME-1)){
      (*index)++;
      present_net=network_info_table[*index];
}
return(present_net);
}


/* determine the predecessor of the current network      */

struct network_info *prev_net(struct network_info *present_net, int *index)
{

if(present_net != 0) present_net = present_net->prev;
while(present_net==0 && *index >= 1){
      (*index)--;
      present_net=network_info_table[*index];
}
return(present_net);
}



/* display the status and other information about the given node */

void disp_node_info(NODE_INFO *node_info)
{
  int oldx,oldy,newx,newy,ch;
  BYTE component_type;
  struct text_info win;
  extern NODE_INFO *current_node;

  gettextinfo(&win);
  oldx=win.curx; oldy=win.cury; /* save the old cursor position */
  window(20,win.wintop+oldy-3,55,win.wintop+oldy+2);
  clrscr();
  make_win(20,win.wintop+oldy-2,55,win.wintop+oldy+1,1,"NODE STATUS");
  gotoxy(1,1);

  /* determine the node type   */
  normvideo();
  cprintf(" NODE  TYPE  : ");
  component_type = find_component_type(node_info->component_cnt,node_info->components);
  switch((int)component_type){

   case DIAG_NODE    :       cprintf("WORKSTATION");
			     break;

   case DIAG_FILE_SERVER :  cprintf("FILE SERVER");
			    break;

   case DIAG_ROUTER  :      cprintf("ROUTER ");
			    break;

   default:                 cprintf("UNKNOWN ");
			    break;
  }
  gotoxy(1,2);
  switch(node_info->status){

  case ACTIVE :    cprintf(" STATUS  : UP  ");
		   break;


  case UNKNOWN :   cprintf(" STATUS : UNKNOWN ");
		   break;

  case INACTIVE :  cprintf(" STATUS  : DOWN  Since  %2d:%02d:%02d",node_info->down_time.ti_hour,
			node_info->down_time.ti_min, node_info->down_time.ti_sec);
		    break;
  default :        break;
  }

window(win.winleft,win.wintop,win.winright,win.winbottom);
  gotoxy(oldx,oldy);
  return;
}




/* determine the type of components in the diagnostic configuration reply
   packet
*/

 BYTE find_component_type(BYTE component_cnt,BYTE *components)
 {
   int count=0,i;

  for(i=0;i<component_cnt;i++) count+=(int)components[i];
  if(component_cnt == 3 &&  count == 5)return(DIAG_NODE);
  if((component_cnt == 3 &&  count == 6) ||
     (component_cnt==4 && count == 10)) return(DIAG_ROUTER);
  if((component_cnt == 3 &&  count == 7) ||
      (component_cnt == 4 && count == 11)) return(DIAG_FILE_SERVER);
  return(NULL);
}
[ RETURN TO DIRECTORY ]