/* 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;inode_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