/* 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 =¤t_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 = ¤t_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);
}