/* $Id: nbr.c,v 1.1 1999/08/23 16:18:35 naamato Exp $ */
/*
 * Copyright(c) 1998 by Hitachi.Ltd All rights reserved.
 *
 */

#include "defs.h"
#include "igmp_def.h"
#include "dvmrp_def.h"
#include "./config2/config.h"

#define FILE_NAME_SIZE 256

#define CNF_QUIT   3 

extern int igmp_sock;
extern char *recv_buf;
extern int insock;
extern int trace_mode;
extern int dvmrp_flag;

void wait_command();
void wait_timeout();
char *timer_init();
void parse_file();
void print_usage();

char usage[] = "Usage: dnbr [-f conf]\n";
char version[]="DVMRP tool (dnbr) -- Version 1.0 Beta1";
char copyright[]="All Right Reserved, Copyright(c) 1998, Hitachi,Ltd";

FILE *fp;
char *config;
CONFIG *configp;
CONF_PARAGET gettbl;
int cnt;  /* config parameter counter */

char *wait_timer;
int wait_flag=0;

#define FILE_MODE         0
#define INTERACTIVE_MODE  1

int mode;
int debug = 0;

main(argc, argv)
int argc;
char **argv;
{
    char opt;
    extern char *optarg;
    fd_set read_fd,tmp_fd,igmp_fd;
    int recv_len;
    int nfd;
    struct timeval  t;
    int rtn,dummy;
    int n;
    char *log_file;
    int fd_val, fd_wid;

    log_file=NULL;
    dummy = rtn = 0;
    
    while((opt = getopt(argc,argv,"f:l:d:h")) != -1) {
        switch(opt) {
	case 'l' : log_file = malloc(FILE_NAME_SIZE);
	           strcpy(log_file,optarg);
	           break;
	case 'f' : configp=init_config(optarg);
	           mode = FILE_MODE;
	           rtn = 1;
	           break;
	case 'd':  debug = atoi(optarg);
	           break;
	case 'h':  fprintf(stderr,usage);
	           exit(1);
	default :  fprintf(stderr,usage);
	           exit(1);
	}
    }

    printf("\n %s \n\n",version);
/*    printf(" %s \n\n",copyright);*/

    if(!configp) {
	configp = init_config(NULL);
	mode = INTERACTIVE_MODE;
	printf(" Running interactive mode, Enter 'help' or command:\n");
	printf(" dnbr> ");
	fflush(stdout);
    }

    interface_init();
    dvmrp_init();

    multicast_init();
    router_init(log_file);

    time_init();
    wait_timer = timer_init(0,NULL,wait_timeout);

    FD_ZERO(&read_fd);
    FD_SET(igmp_sock, &read_fd);
    FD_SET(igmp_sock, &igmp_fd);
    if(igmp_sock >= insock) fd_wid = igmp_sock+1;
    else fd_wid = insock+1;

    t.tv_sec = 0;
    t.tv_usec = 10000;

    for(;;) {
        timer_check();
	FD_ZERO(&read_fd);
	FD_SET(igmp_sock, &read_fd);
	if(mode == INTERACTIVE_MODE)
	    FD_SET(insock, &read_fd);

/*	memcpy((char *)&tmp_fd, (char *)&read_fd, sizeof(read_fd));*/
	
	if((n=select(fd_wid,&read_fd,NULL,NULL,&t))<0) {
	    perror("select");
	    continue;
	}

	for(fd_val=0; n--; fd_val++) {

	    while(!FD_ISSET(fd_val, &read_fd))
		fd_val++;

	    /*	if(FD_ISSET(igmp_sock,&read_fd)) {*/
	    if(FD_ISSET(fd_val, &igmp_fd)) {
		recv_len = recvfrom(igmp_sock,recv_buf,1024,0,NULL,&dummy);
		igmp_recv(recv_len);
	    }

	    if(mode == INTERACTIVE_MODE && fd_val == insock) {
		rtn = do_command();
		if(rtn == CNF_QUIT) break;
		printf(" dnbr> ");
		fflush(stdout);
	    }
	}

	if(mode == FILE_MODE) {
	    if(!wait_flag) {
		rtn = do_command();
		if(rtn == CNF_QUIT) break;
		else if(rtn == CNF_EOF) {
		    end_config(configp);
		    configp = init_config(NULL);
		    mode = INTERACTIVE_MODE;
		    printf(" \n Transit to interactive mode, Enter 'help' or command:\n");
		    printf(" dnbr> ");
		    fflush(stdout);
		}
	    }
	}
	else
	    if(rtn == CNF_QUIT) break;

    }

    end_config(configp);

    multicast_term();
}

typedef enum {
    C_ROUTER_LIST=1,
    C_NETWORK_LIST,
    C_ROUTE_LIST,
    C_CONF_FILE,
    C_TRACE_FILE,
    C_ROUTER,
    C_NETWORK,
    C_ROUTE,
    C_MEMBER,
    C_PROBE,
    C_REPORT,
    C_PRUNE,
    C_GRAFT,
    C_GACK,
    C_WAIT,
    C_DUMP,
    C_SG,
    C_DEBUG,
    C_NODEBUG,
    C_QUIT,
    C_HELP,
    C_ENABLE,   /* experiment */
    C_DISABLE   /* experiment */
} COMMAND;

typedef enum {
    RC_UP=1,
    RC_DOWN,
    RC_ENABLE,
    RC_DISABLE
} ROUTER_COMMAND;

typedef enum {
    NC_ADD=1,
    NC_DELETE,
    NC_CHANGE
} NETWORK_COMMAND;

typedef enum {
    PC_SEND=1,
    PC_RECV
} PKT_COMMAND;

typedef enum {
    MC_JOIN=1,
    MC_LEAVE
} MEM_COMMAND;

typedef enum {
    P_ADDR=1,
    P_NET,
    P_ROUTE,
    P_TUNNEL,
    P_GEN,
    P_FILE,
    P_CAPFLAG,
    P_VER,
    P_ROUTER,
    P_SRC,
    P_DST,
    P_GROUP,
    P_TIME,
    P_NBR,
    P_TIMEOUT,
    P_LIST,
    P_ENTRY,
    P_TRACEFILE
} RT_PARAM;

typedef enum {
    DBG_DETAIL=1,
    DBG_TTY
} DBG_COMMAND;

struct token {
    int type;
    char *name;
};

struct token cmd_token[]= {
    {C_ROUTER_LIST,"router-list"},
    {C_NETWORK_LIST,"network-list"},
    {C_ROUTE_LIST,"route-list"},
    {C_CONF_FILE,  "config-file"},
    {C_TRACE_FILE, "trace-file"},
    {C_ROUTER,     "router"},
    {C_NETWORK,    "network"},
    {C_ROUTE,      "route"},
    {C_MEMBER,     "member"},
    {C_PROBE,      "probe"},
    {C_REPORT,     "report"},
    {C_PRUNE,      "prune"},
    {C_GRAFT,        "graft"},
    {C_GACK,       "gack"},
    {C_WAIT,       "wait"},
    {C_DUMP,       "dump"},
    {C_SG,         "sg"},
    {C_DEBUG,      "debug"},
    {C_NODEBUG,    "nodebug"},
    {C_QUIT,       "quit"},
    {C_HELP,       "help"},
    {C_ENABLE,     "enable"},
    {C_DISABLE,    "disable"}
};

struct token rtr_cmd_token[]={
    {RC_UP, "up"},
    {RC_DOWN, "down"},
    {RC_ENABLE, "enable"},
    {RC_DISABLE, "disable"}
};

struct token net_cmd_token[]={
    {NC_ADD,  "add"},
    {NC_DELETE, "delete"},
    {NC_CHANGE, "change"}
};

struct token pkt_cmd_token[]={
    {PC_SEND, "send"},
    {PC_RECV, "recv"}
};

struct token mem_cmd_token[]={
    {MC_JOIN, "join"},
    {MC_LEAVE,"leave"}
};

struct token param_token[]={
    {P_ADDR, "addr"},
    {P_NET, "network"},
    {P_ROUTE,"adv-route"},
    {P_TUNNEL, "tunnel"},
    {P_GEN, "generate"},
    {P_FILE, "file"},
    {P_CAPFLAG, "cap"},
    {P_VER, "ver"},
    {P_ROUTER, "router"},
    {P_SRC, "src"},
    {P_DST, "dst"},
    {P_GROUP, "group"},
    {P_TIME, "time"},
    {P_NBR, "nbr"},
    {P_TIMEOUT, "timeout"},
    {P_LIST, "list"},
    {P_ENTRY, "entry"},
    {P_TRACEFILE, "tracefile"}
};

struct token dbg_cmd_token[]={
    {DBG_DETAIL, "detail"},
    {DBG_TTY, "tty"}
};

#define TRACE_COMMAND(tbl)  \
{ \
      int c; \
      trace(stderr," %s ",tbl.command); \
      for(c=0;c<tbl.paramcount;c++) trace(stderr,"%s ",tbl.paramtbl[c]); \
      trace(stderr,"\n"); \
}

#define PARAMTBL(cnt)  gettbl.paramtbl[cnt++]

log_command(cmd,tbl)
int cmd;
CONF_PARAGET *tbl;
{
      int c;
      char log_buf[256], temp[20];

      if(cmd == C_QUIT) {
	  strcpy(log_buf,"CMD quit \n");
      }
      else {
	  sprintf(log_buf,"CMD %s ",tbl->command); 
	  for(c=0;c<tbl->paramcount;c++) {
	      sprintf(temp,"%s ",tbl->paramtbl[c]);
	      strcat(log_buf,temp);
	  }
      }
      log(LOG_INFO,0," %s\n",log_buf); 
}

int token_type(list,token)
struct token *list;
char *token;
{
    struct token *p;
    
    for(p=list;p->name != NULL; p++) {
	if(!strcmp(token,p->name)) {
	    return p->type;
	}
    }

    return 0;
}

int do_packet_send_command(cmd)
char cmd;
{
    char c,buf[256],*bufp,if_name[8];
    char param;
    u_long addr,id,interval;
    int rt;
    u_long net,mask;
    char cap_flag;
    u_short major,minor,ver;
    int lifetime;
    u_long sg_src,sg_grp;
    u_long src,dst;
    FILE *fp;
    int metric;
    int type;

    strcpy(if_name,gettbl.paramtbl[cnt++]);
    src = dst = 0;
    switch(cmd) {
    case C_PROBE:
	ver = minor = major = 0;
	for(;cnt<gettbl.paramcount;) {
	    param = token_type(param_token,gettbl.paramtbl[cnt++]);
	    if(P_CAPFLAG == param) {
		cap_flag = atoh(gettbl.paramtbl[cnt++]);
	    }
	    else if(P_VER == param) {
		major = (short)atoi(gettbl.paramtbl[cnt++]);
		minor = (short)atoi(gettbl.paramtbl[cnt++]);
	    }
	    else if(P_NBR == param) {
		add_nbr_list2(if_name,inet_stoa(gettbl.paramtbl[cnt++]));
	    }
	    else if(P_SRC == param) {
		src = inet_stoa(gettbl.paramtbl[cnt++]);
	    }
	    else if(P_DST == param) {
		dst = inet_stoa(gettbl.paramtbl[cnt++]);
	    }
	}
	ver = DVMRP_VERSION(major,minor);
	dvmrp_probe_send2(if_name,src,dst,cap_flag,0,ver,NULL);
	del_nbr_list2(if_name);
	break;
    case C_REPORT:
	src = dst = 0;
	for(;cnt<gettbl.paramcount;) {
	    param = token_type(param_token,gettbl.paramtbl[cnt++]);
	    if(param == P_LIST) {
		addr = atol(gettbl.paramtbl[cnt++]);  /* route-list id */
	    }
	    else if(P_SRC == param) {
		src = inet_stoa(gettbl.paramtbl[cnt++]);
	    }
	    else if(P_DST == param) {
		dst = inet_stoa(gettbl.paramtbl[cnt++]);
	    }
	}
	do_report_send(if_name,src,dst,addr);
	break;
    case C_PRUNE:
    case C_GRAFT:
    case C_GACK:
	sg_src=addr=sg_grp=0;
	lifetime = DVMRP_DEFAULT_LIFETIME;
	for(;cnt<gettbl.paramcount;) {
	    param = token_type(param_token,gettbl.paramtbl[cnt++]);
	    if(param == P_SRC) 
		src = inet_stoa(gettbl.paramtbl[cnt++]);
	    else if(param == P_DST)
		dst = inet_stoa(gettbl.paramtbl[cnt++]);
	    else if(param == P_TIME) 
		lifetime = atoi(gettbl.paramtbl[cnt++]);
	    else if(param == P_ENTRY) {
		sg_src = inet_stoa(gettbl.paramtbl[cnt++]);
		sg_grp = inet_stoa(gettbl.paramtbl[cnt++]);
	    }
	}
	if(cmd == C_PRUNE) {
	    dvmrp_prune_send(if_name,src,dst,0,sg_src,sg_grp,lifetime);
	}
	else if(cmd == C_GRAFT) {
	    dvmrp_graft_send(if_name,src,dst,0,sg_src,sg_grp);
	}
	else if(cmd == C_GACK) {
	    dvmrp_gack_send(if_name,src,dst,0,sg_src,sg_grp);
	}
	break;
    default:
	break;
    }
}

int do_packet_recv_command(cmd)
char cmd;
{
    char c,buf[256],*bufp,if_name[8];
    char param;
    u_long addr,id,interval;
     u_long net,mask;
    char cap_flag;
    u_short major,minor,ver;
    int lifetime;
    u_long sg_src,sg_grp;
    u_long src,dst;
    FILE *fp;
    int metric;
    int type;

    strcpy(if_name,gettbl.paramtbl[cnt++]);
    src = dst = 0;
    switch(cmd) {
    case C_PROBE:
	lifetime = 0;
	for(;cnt<gettbl.paramcount;) {
	    param = token_type(param_token,gettbl.paramtbl[cnt++]);
	    if(P_CAPFLAG == param) {
		cap_flag = atoh(gettbl.paramtbl[cnt++]);
	    }
	    else if(P_VER == param) {
		major = (short)atoi(gettbl.paramtbl[cnt++]);
		minor = (short)atoi(gettbl.paramtbl[cnt++]);
	    }
	    else if(param == P_TIMEOUT) {
		interval = atoi(gettbl.paramtbl[cnt++]);
		wait_command(interval);
	    }
	}
	ver = (u_short)(minor << 8 | major);
	comp_packet_recv(DVMRP_PROBE,interval);
	break;
    case C_REPORT:
	for(;cnt<gettbl.paramcount;) {
	    param = token_type(param_token,gettbl.paramtbl[cnt++]);
	    if(param == P_TIMEOUT) {
		interval = atoi(gettbl.paramtbl[cnt++]);
		wait_command(interval);
	    }
	}
	comp_packet_recv(DVMRP_REPORT,interval);
	break;
    case C_PRUNE:
    case C_GRAFT:
    case C_GACK:
	lifetime = 0;
	for(;cnt<gettbl.paramcount;) {
	    param = token_type(param_token,gettbl.paramtbl[cnt++]);
	    if(param == P_SRC) 
		src = inet_stoa(gettbl.paramtbl[cnt++]);
	    else if(param == P_DST)
		dst = inet_stoa(gettbl.paramtbl[cnt++]);
	    else if(param == P_TIME) 
		lifetime = atoi(gettbl.paramtbl[cnt++]);
	    else if(param == P_TIMEOUT) {
		interval = atoi(gettbl.paramtbl[cnt++]);
		wait_command(interval);
	    }
	    else if(param == P_ENTRY) {
		sg_src = inet_stoa(gettbl.paramtbl[cnt++]);
		sg_grp = inet_stoa(gettbl.paramtbl[cnt++]);
	    }
	}
	if(cmd == C_PRUNE) type = DVMRP_PRUNE;
	else if(cmd == C_GRAFT) type = DVMRP_GRAFT;
	else if(cmd == C_GACK) type = DVMRP_GRAFT_ACK;
	comp_packet_recv(type,interval);
	break;
    default:
	break;
    }
}

/*
 *
 */
int do_command()
{
    char c,buf[256],*bufp,if_name[8];
    char cmd,sub_cmd,param;
    u_long addr,id,interval;
    int rt;
    u_long net,mask;
    char cap_flag;
    u_short major,minor,ver;
    int lifetime;
    u_long sg_src,sg_grp;
    FILE *fp;
    int metric;
    int type;
    char *dvmrp_packet[]={NULL,"probe","report",NULL,NULL,NULL,NULL,"prune",
			      "graft","graft_ack",NULL};

    if((rt = get_config_command(configp,&gettbl))<0) {
	printf(" Config read error !\n");
	return 0;
    }

    if(rt == CNF_EOF) {
	return CNF_EOF;
    }
    else {
	cmd = token_type(cmd_token,gettbl.command);
	if(mode == FILE_MODE)
	    TRACE_COMMAND(gettbl);
    }

    log_command(cmd,&gettbl);
    switch(cmd) {
    case C_ROUTER_LIST : 
	cnt = 0;
	id = atol(gettbl.paramtbl[cnt++]);
	param = token_type(param_token,gettbl.paramtbl[cnt++]);
	if(P_ADDR == param) {
	    cap_flag = 0;
	    major = DVMRP_VERSION_MAJOR; 
	    minor = DVMRP_VERSION_MINOR;
	    addr = inet_stoa(gettbl.paramtbl[cnt++]);
	    for(;cnt<gettbl.paramcount;) {
		param = token_type(param_token,gettbl.paramtbl[cnt++]);
		if(P_CAPFLAG == param) {
		    cap_flag = atoh(gettbl.paramtbl[cnt++]);
		}
		else if(P_VER == param) {
		    major = (short)atoi(gettbl.paramtbl[cnt++]);
		    minor = (short)atoi(gettbl.paramtbl[cnt++]);
		}
	    }
	    ver = (u_short)(minor << 8 | major);
	    router_add(id,addr,cap_flag,ver);
	}
	else if(P_ROUTE == param) {
	    for(;cnt<gettbl.paramcount;) {
		addr = atol(gettbl.paramtbl[cnt++]);
		router_add_net(id,addr);
	    }
	}
	else if(P_TUNNEL == param) {
	    addr = inet_stoa(gettbl.paramtbl[cnt++]);
	    /* TODO : router_add_tunnel(id, addr);*/
	    printf("\n not implementation yet \n");
	}
	else if(P_TRACEFILE == param) {
	    router_trace(id,gettbl.paramtbl[cnt++]);
	}
	else if(P_NET == param) {
	    printf(" WARNING 'network' is obsolete. Replace 'adv-route'\n");
	}
	else {
	    printf("Unknown Parameter at 'router-list' command\n");
	}
	break;
    case C_NETWORK_LIST: printf(" WARNING 'network-list' command is obsolete. Replace 'route-list' command\n");
         break;
    case C_ROUTE_LIST:
	cnt = 0;
	id = atol(gettbl.paramtbl[cnt++]);
	param = token_type(param_token,gettbl.paramtbl[cnt++]);
	if(param == P_ADDR) {
	    for(;cnt<gettbl.paramcount;) {
		prefix_parse(gettbl.paramtbl[cnt++],&net,&mask);
		create_network_list(id,net,mask,atoi(gettbl.paramtbl[cnt++]));
	    }
	}
	else if(param == P_GEN) {
	    prefix_parse(gettbl.paramtbl[cnt++],&net,&mask);
	    metric = atoi(gettbl.paramtbl[cnt++]);
	    generate_network_list(id,net,mask,metric,atoi(gettbl.paramtbl[cnt++]));
	}
	else if(param == P_FILE) {
	    if(!(fp = fopen(gettbl.paramtbl[cnt++],"r")))
		printf(" NEWOROK FILE can't open \n");
	    parse_file(fp,id);
	}
	else {
	    printf("\n Unknown parameter 'route-list' \n");
	}
	break;
    case C_ROUTER : 
	sub_cmd = token_type(rtr_cmd_token,gettbl.paramtbl[0]);
	id = atol(gettbl.paramtbl[1]);
	addr = inet_stoa(gettbl.paramtbl[2]);
	if(sub_cmd == RC_UP) {
	    router_up(id);
	}
	else if(sub_cmd == RC_DOWN) {
	    router_down(id);
	}
	else if(sub_cmd == RC_ENABLE) {
	    router_enable(id);
	}
	else if(sub_cmd == RC_DISABLE) {
	    router_disable(id);
	}
	else {
	    printf("\n Unknown Operation 'router' command\n");
	}
	break;
    case C_NETWORK:printf(" WARNING 'network' command is obsolete. Replace 'route' command\n");
        break;
    case C_ROUTE:
	cnt = 0;
	sub_cmd = token_type(rtr_cmd_token,gettbl.paramtbl[cnt++]);
	id = atoi(gettbl.paramtbl[cnt++]);
	param = token_type(param_token,gettbl.paramtbl[cnt++]);
	if(param == P_ADDR) {
	    prefix_parse(gettbl.paramtbl[cnt++],&net,&mask);
	}
	else if(param == P_FILE) {
	    /* TODO */
	    printf("\n not implementation yet 'file' parameter \n");
	}
	else {
	    printf("\n Unknown parameter 'route' command \n");
	}
	metric = atoi(gettbl.paramtbl[cnt++]);
	if(sub_cmd == NC_ADD)
	    add_network(id,net,mask,metric);
	else if(sub_cmd == NC_DELETE)
	    delete_network(id,net,mask,metric);
	else if(sub_cmd == NC_CHANGE)
	    change_network(id,net,mask,metric);
	router_update_route(id,net,mask,metric);
	break;
    case C_MEMBER:
	cnt=0;
	sub_cmd = token_type(mem_cmd_token,gettbl.paramtbl[cnt++]);
	id = atoi(gettbl.paramtbl[cnt++]);
	for(;cnt<gettbl.paramcount;) {
	    param = token_type(param_token,gettbl.paramtbl[cnt++]);
	    if(param == P_SRC) 
		sg_src = inet_stoa(gettbl.paramtbl[cnt++]);
	    else if(param == P_GROUP)
		sg_grp = inet_stoa(gettbl.paramtbl[cnt++]);
	}
	if(sub_cmd==MC_JOIN) 
	    member_add(id,sg_grp);
	else if(sub_cmd == MC_LEAVE) 
	    member_delete(id,sg_grp);
	else 
	    printf("\n Unknown Operation 'member' command\n");
	break;
    case C_PROBE:
    case C_REPORT:
    case C_PRUNE:
    case C_GRAFT:
    case C_GACK:
	cnt=0;
	sub_cmd = token_type(rtr_cmd_token,gettbl.paramtbl[cnt++]);
	if(sub_cmd == PC_SEND) 
	    do_packet_send_command(cmd);
	else if(sub_cmd == PC_RECV) 
	    do_packet_recv_command(cmd);
	else 
	    printf("\n Unknown Operation \n");
	break;
    case C_WAIT : 
	interval = atol(gettbl.paramtbl[0]);
	wait_command(interval);
	break;
    case C_CONF_FILE:
	configp = init_config(gettbl.paramtbl[0]);
	break;
    case C_TRACE_FILE:
	id = atol(gettbl.paramtbl[0]);
	router_trace(id,gettbl.paramtbl[1]);
	break;
    case C_DUMP:
	if(gettbl.paramcount > 1) {
	    id = atol(gettbl.paramtbl[0]);	
	    if(id) {
		router_dump(id,gettbl.paramtbl[1]);
	    }
	}
	else {
	    dump();
	}
	break;
    case C_SG: 
	cnt=0;
	sg_src = inet_stoa(gettbl.paramtbl[cnt++]);
	sg_grp = inet_stoa(gettbl.paramtbl[cnt++]);
	sg_create_entry(sg_src,sg_grp);
	break;
    case C_DEBUG:
	cnt = 0;
	trace_mode = TRACE_MODE_PKT;
	for(;cnt<gettbl.paramcount;) {
	    sub_cmd = token_type(dbg_cmd_token,gettbl.paramtbl[cnt++]);
	    if(sub_cmd == DBG_DETAIL) {
		trace_mode = TRACE_MODE_DETAIL;
	    }
	    else if(sub_cmd == DBG_TTY) {
		open_tty(gettbl.paramtbl[cnt++]);
		trace2(NULL,"\n");
	    }
	}
	break;
    case C_NODEBUG:
	trace_mode = TRACE_MODE_NONE;
	close_tty();
	break;
    case C_QUIT :
	rt = CNF_QUIT;
	break;
    case C_HELP:
	print_usage();
	break;
    case C_ENABLE:
        dvmrp_flag = 1;
	break;
    case C_DISABLE:
        dvmrp_flag = 0;
	break;
    default :
	if(strlen(gettbl.command))
	    printf("Unknown command '%s' \n",gettbl.command);
	break;
    }

    return rt;
}

void wait_command(interval)
int interval;
{
#if 0
    if(IS_DEBUG(DEBUG_TRACE)) 
	log(LOG_DEBUG,0," wait %d \n",interval);
#endif
    wait_flag = 1;
    timer_set(wait_timer,interval);
}

void wait_timeout(id,data)
u_long id;
char *data;
{
    timer_stop(wait_timer);
    wait_flag = 0;
}

int atoh(num)
char *num;
{
    char *buf, c;
    int hex;

    buf = num;
    hex = 0;
    while(*buf) {
	hex <<= 4;
        if(*buf >= '0' && *buf <= '9') hex |= *buf - '0';
	else if (*buf >= 'a' && *buf <= 'f') hex |= 10 + (*buf-'a');
	buf++;
    }

    return hex;
}

void parse_file(fp,id)
FILE *fp;
u_long id;
{
    char c,buf[256],*bufp;
    u_long net,mask;
    int metric;

    bufp = buf;
    while((c=getc(fp)) != EOF) {
        if(c == 0x0a) {
	    *bufp = '\0';
	    metric = atoi(buf);
	    create_network_list(id,net,mask,metric);
	    bzero(buf,256);
	    bufp = buf;
	}
	else if(c == ' ' || c == '\t') {
	    *bufp = '\0';
	    prefix_parse(buf,&net,&mask);
	    bzero(buf,256);
	    bufp = buf;
	}
	else {
	    *bufp++ = c;
	}
    }
	
}

void print_usage()
{
    printf("\n");
    printf(" router-list <list> addr <router-addr> \n");
    printf(" router-list <list> network <network-list> \n");
    printf(" network-list <list> addr <prefix> <metric> \n");
    printf(" network-list <list> generate <prefix> <metric> <num> \n");
    printf(" network-list <list> file <file_name> \n");
    printf(" router up | down <router-list> \n");
    printf(" network add | delete | change <network-list> addr <prefix> <metric>\n");
    printf(" member add | delete <router-list> addr <prefix> <metric>\n");
    printf(" quit \n");
    printf("\n");
}
