/************************************************************************/
/*	Routing Protocol Simulator	Release 1.0	1994/3/17	*/
/*                                              1.21    1997/2/10       */
/*									*/
/*		module 	: router management				*/
/*		file	: router.c					*/
/*									*/
/*   Copyright (c) 1994-1997 by Systems Development Laboratory Hitachi,	*/
/*   Ltd. All rights reserved.						*/
/*----------------------------------------------------------------------*/
/*	UPDATE HISTORY							*/
/*	1996.6.20        Add new function   			        */
/*                           network_up(), network_down()               */
/************************************************************************/
static char copyright[]=
  "@(#)Copyright (c) 1994-1997 by Systems Development Laboratory Hitachi,Ltd.\n All rights researved.\n";

#include "rps.h"
#include "router.h"
#include "rps_bgp.h"
#include "rps_token.h"
#include "rps_ospf.h"

#define SEND    1
#define NOSEND  0

void router_up();
void router_down();
void router_dump();
void router_if_dump();
struct RT_CONF *router_search();
void all_interface_up();
void interface_up();
void interface_down();
void hop_up();
void hop_down();
void link_state_up();
void link_state_down();
void table_update();
void lsdb_update();
void if_table_make();
void router_timeout();
void rt_unreachable();
void router_wait();

extern char *inetaddr_to_char();
extern char *token_arg();
extern byte *make_lsdb();
extern byte *timer_init();
extern char *time_to_char();
extern char *ospf_rt_table();
extern struct NET_TBL *get_net_list();

struct RT_CONF *rt_list = NULL ;
int wait_timer_flag;

/*

  router_alloc - router management memory allocate

*/
struct RT_CONF *router_alloc()
{
    struct RT_CONF *rtp;

    if((rtp = (struct RT_CONF *)malloc(sizeof(struct RT_CONF))) == NULL) {
	return NULL;
    }
    else {
       	bzero(rtp,sizeof(struct RT_CONF));
	return rtp;
    }
}

/*

  add_router_list - add router management list

*/
void add_router_list(add_rtp)
struct RT_CONF *add_rtp;
{
    struct RT_CONF *rtp;
    
    if(rt_list == NULL) {
	rt_list = add_rtp;
    }
    else {
	for(rtp=rt_list;rtp->next;rtp = rtp->next);
	rtp->next = add_rtp;
    }
}

/*

  protocol_init()

*/
void protocol_init()
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    
    for(rt=rt_list;rt;rt=rt->next) {
	for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	    switch(rtif->protocol) {
	    case T_PROTO_BGP : break;
	    case T_PROTO_OSPF :    ospf_init(rt->router_id,rtif->proto_info);
				 break;
		default : log_trace(stderr,"no configuration protocol in protocol init \n");
				break;
	    }
	}
    }
}

/*

  protocol_term()

*/
void protocol_term()
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    
    for(rt=rt_list;rt;rt=rt->next) {
	for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	    switch(rtif->protocol) {
	    case T_PROTO_BGP : break;
	    case T_PROTO_OSPF :  ospf_term(rt->router_id,rtif->proto_info);
				 break;
		default : log_trace(stderr,"no configuration protocol in protocol init \n");
		break;
	    }
	}
    }
}

/*

  all_router_up

*/
void all_router_up()
{
    struct RT_CONF *rt;

    if(rt_list == NULL) return;
    
    for(rt=rt_list;rt;rt=rt->next) {
	router_up(rt->router_id);
	router_trace_off(rt->router_id);
    }
}

/*

  router_up

*/
void router_up(router_id)
u_long router_id;
{
    struct RT_CONF *up_rt;
    struct RT_IFCONF *rtif;

    if(!router_id) {
	log_trace(stderr,"invalid up router_id\n");
	return;
    }
		  
    if(!(up_rt = router_search(router_id)))
      return;

    if(up_rt->trace_flag) {
	  log_trace(up_rt->trace_fp,"\n <<< routerUP (ID : %s) >>>\n",
		    inetaddr_to_char(ntohl(router_id)));
    }
    
    log_trace(stderr,"\n <<< routerUP (ID : %s) >>>\n",
	      inetaddr_to_char(ntohl(router_id)));

    for(rtif=up_rt->rt_ifp;rtif;rtif=rtif->next) {
	interface_up(up_rt->router_id,RT_IF_ADDR(rtif));
/*	if_table_make(rtif);*/
	switch(rtif->protocol) {
	case  T_PROTO_BGP : break;
	case T_PROTO_OSPF : /*rtif->rt_table = make_lsdb(router_id,RT_IF_ADDR(rtif));*/
	    /*		routing_table_dump(rtif->rt_table);*/
	    		ospf_start(router_id,rtif);
	    break;
	    default : break;
	}
    }
			    
}

/*

  all_router_down

*/
void all_router_down()
{
    struct RT_CONF *rt;

    if(rt_list == NULL) return;
    
    for(rt=rt_list;rt;rt=rt->next) {
	router_down(rt->router_id);
	router_trace_off(rt->router_id);
    }
}

/*

  all_rt_unreachable

*/
void all_rt_unreachable()
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    u_long area;

    for(rt=rt_list;rt;rt=rt->next) {
	for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	    switch(rtif->protocol) {
	    case T_PROTO_BGP : break;
	    case T_PROTO_OSPF : /*delete_lsdb(rt->router_id,RT_IF_ADDR(rtif));
		rtif->rt_table = ospf_rt_table(rt->router_id,rtif);*/
	      ospf_rt_aging(rt->router_id,rtif->proto_info);
		router_wait(rt->router_id,10);
		break;
		default :break;
	    }
	}
    }
}


/*

  router_down

*/
void router_down(router_id)
u_long router_id;
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    
    if(!router_id) {
	log_trace(stderr,"invalid down router_id\n");
	return;
    }

    rt = router_search(router_id);
    
    if(rt->trace_flag) {
	log_trace(rt->trace_fp,"\n <<< routerDOWN (ID : %s) >>>\n",
		  inetaddr_to_char(ntohl(router_id)));
    }
    
    log_trace(stderr,"\n <<< routerDOWN (ID : %s) >>>\n",
	      inetaddr_to_char(ntohl(router_id)));
        
    for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	if(rtif->state == INTF_UP)
	  interface_down(rt->router_id,RT_IF_ADDR(rtif));
    }
}

/*

  router_search

*/
struct RT_CONF *router_search(id)
u_long id;
{
    struct RT_CONF *rt;

    if(!id) {
	log_trace(stderr,"invalid search router_id in router_search\n");
	return;
    }

    for(rt=rt_list;rt;rt=rt->next) {
	if(id == rt->router_id) break;
    }

    if(!rt)
      log_trace(stderr,"can't find router in router_search\n");
    
    return rt;
}

/*

  get_router_id

*/
u_long get_router_id(ifaddr)
u_long ifaddr;
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;

    if(!ifaddr) {
	log_trace(stderr," invalid argment <ifaddr = %d> in get_router_id\n",ifaddr);
	return 0;
    }
    
    for(rt=rt_list;rt;rt=rt->next) {
	for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	    if(RT_IF_ADDR(rtif) == ifaddr) return rt->router_id;
	}
    }

    return 0;
}

/*

  get_proto_info

*/
byte *get_proto_info(id,rt_if)
u_long id;
u_long rt_if;
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;

    if(!id || !rt_if) {
	log_trace(stderr,"invalid argment <id = %d, rt_if = %d> in get_proto_info\n",id,rt_if);
	return NULL;
    }
    
    if(!(rt = router_search(id))) return NULL;

    for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	if(RT_IF_ADDR(rtif) == rt_if)
	  return rtif->proto_info;
    }

    return NULL;
}

/*

  get_local_rtif

*/
struct RT_IFCONF *get_local_rtif(rmt_addr)
u_long rmt_addr;
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;

    if(!rmt_addr) {
	log_trace(stderr,"invalid argment <rmt_addr = %d> in get_local_rtif\n",rmt_addr);
	return NULL ;
    }
    
    for(rt=rt_list;rt;rt=rt->next) {
	for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	    if(IF_ADDR(rtif->remote_addr) == rmt_addr)
	      return rtif;
	}
    }

    return NULL;
}

/*

  if_router_alloc - router interface info area allocation

*/
struct RT_IFCONF *router_if_alloc()
{
    struct RT_IFCONF *rt_ifp;

    if((rt_ifp = (struct RT_IFCONF *)malloc(sizeof(struct RT_IFCONF))) == NULL) {
	return NULL;
    }
    else {
	bzero(rt_ifp,sizeof(struct RT_IFCONF));
	
	return rt_ifp;
    }
}

/*

  all_interface_up

*/
void all_interface_up()
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    
    if(rt_list == NULL) return;
    
    for(rt=rt_list;rt;rt=rt->next) {
	for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	    rtif->state = INTF_UP;

	    switch(rtif->protocol) {
	    case T_PROTO_BGP	: break;
	    case T_PROTO_OSPF 	: rtif->rt_table =
	                              ospf_rt_table(rt->router_id,rtif);
		                  break;
	    default 		: break;
	    }

	}
    }
}

/*

  interface_up

*/
void interface_up(rt_id,rt_if)
u_long rt_id;
u_long rt_if;
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    
    if(!rt_id || !rt_if) {
	log_trace(stderr,"invalid argment <rt_id = %d, rt_if = %d> in interface_up\n",rt_id,rt_if);
	return ;
    }

    if(!(rt = router_search(rt_id)))
      return ;

    if(rt->trace_flag) {
	log_trace(rt->trace_fp,"\n <<< interfaceUP (ID : %s, ",
		  inetaddr_to_char(ntohl(rt_id)));
	log_trace(rt->trace_fp,"IF : %s) >>>\n",
		  inetaddr_to_char(ntohl(rt_if)));
    }

    log_trace(stderr,"\n <<< interfaceUP (ID : %s, ",
	      inetaddr_to_char(ntohl(rt_id)));
    log_trace(stderr,"IF : %s) >>>\n",
	      inetaddr_to_char(ntohl(rt_if)));
    
    for(rtif=rt->rt_ifp;rtif;rtif=rtif->next)
	if(rt_if == RT_IF_ADDR(rtif)) break;

    if(get_link_state(rt_id,rt_if) == INTF_DOWN) {
	link_state_up(rt_id,rt_if);
	switch(rtif->protocol) {
	case  T_PROTO_BGP : break;
	case T_PROTO_OSPF : dr_selection();
			    lsdb_update(rt_if);
	    		    delete_lsdb(rt_id,rt_if);
	    		    ospf_if_up(rt_id,rtif->proto_info);
		break;
	    default : break;
	}
    }

    rtif->state = INTF_UP;

    switch(rtif->protocol) {
    case T_PROTO_BGP	: break;
    case T_PROTO_OSPF 	: rtif->rt_table = ospf_rt_table(rt_id,rtif);
	                  break;
    default 		: break;
    }
}

/*

  interface_down

*/
void interface_down(rt_id,rt_if)
u_long rt_id;
u_long rt_if;
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;

    if(!rt_id || !rt_if) {
	log_trace(stderr,"invalid argment <rt_id = %d, rt_if = %d> in interface_down\n",rt_id,rt_if);
	return ;
    }

    if(!(rt = router_search(rt_id)))
      return ;

    if(rt->trace_flag) {
	log_trace(rt->trace_fp,"\n <<< interfaceDOWN (ID : %s, ",
		  inetaddr_to_char(ntohl(rt_id)));
	log_trace(rt->trace_fp,"IF : %s) >>>\n",
		  inetaddr_to_char(ntohl(rt_if)));
    }

    log_trace(stderr,"\n <<< interfaceDOWN (ID : %s, ",
	      inetaddr_to_char(ntohl(rt_id)));
    log_trace(stderr,"IF : %s) >>>\n",
	      inetaddr_to_char(ntohl(rt_if)));	  

    link_state_down(rt_id,rt_if);

    for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	if(rt_if != RT_IF_ADDR(rtif)) continue;

	switch(rtif->protocol) {
	case T_PROTO_BGP  : break;
	case T_PROTO_OSPF : ospf_if_down(rtif->proto_info);
	    		    dr_selection();
	    		    lsdb_update(rt_if);
	    		    break;
	default : break;
	}
    }
    
}

/*

  hop_up

*/
void hop_up(id)
u_long id;
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;

    if(!id) {
	log_trace(stderr,"invalid argment <id = %d> in hop_up\n",id);
	return ;
    }

    log_trace(stderr,"\n <<< hopUP (ID %s) >>>\n",inetaddr_to_char(ntohl(id)));
    
    hop_link_state(id,INTF_UP);
    dr_selection();
    for(rt=rt_list;rt;rt=rt->next) {
	if(rt->trace_flag) {
	    log_trace(rt->trace_fp,"\n <<< hopUP (ID %s) >>>\n",inetaddr_to_char(ntohl(id)));
	}
	for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	    switch(rtif->protocol) {
	    case T_PROTO_BGP  : break;
	    case T_PROTO_OSPF :	table_update(rt->router_id,RT_IF_ADDR(rtif));
				ospf_rt_update(rt->router_id,rtif->proto_info,SEND);
				break;
	    default : break;
	    }
	}
    }
}

/*

  hop_down

*/
void hop_down(id)
u_long id;
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;

    if(!id) {
	log_trace(stderr,"invalid argment <id = %d> in hop_down\n",id);
	return ;
    }

    log_trace(stderr,"\n <<< hopDOWN (ID %s) >>>\n",inetaddr_to_char(ntohl(id)));
    
    hop_link_state(id,INTF_DOWN);
    rt_unreachable(id);
    dr_selection();
    for(rt=rt_list;rt;rt=rt->next) {
	if(rt->trace_flag) {
	    log_trace(rt->trace_fp,"\n <<< hopDOWN (ID %s) >>>\n",inetaddr_to_char(ntohl(id)));
	}
	for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	    switch(rtif->protocol) {
	    case T_PROTO_BGP  : break;
	    case T_PROTO_OSPF :	table_update(rt->router_id,RT_IF_ADDR(rtif));
		ospf_rt_update(rt->router_id,rtif->proto_info,NOSEND);
				break;
	    default : break;
	    }
	}
    }
}

/*

  rt_unreachable

*/
void rt_unreachable(down_hop)
u_long down_hop;
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    u_long area;
    int as;

    if(!down_hop) {
	log_trace(stderr,"invalid argment <down_hop = %d> in rt_unreachable\n",down_hop);
	return ;
    }
    
/*    log_trace(stderr,"down_hop = %s\n",inetaddr_to_char(down_hop));*/
    as = 0;
    area = 0;
    for(rt=rt_list;rt;rt=rt->next) {
	for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	    if((area=rt_area_check(down_hop,rt->router_id))
	    || (as=rt_as_check(down_hop,rt->router_id))) { 
		switch(rtif->protocol) {
		case T_PROTO_BGP : break;
		case T_PROTO_OSPF : ospf_rt_unreachable(rt->router_id,rtif->proto_info,area,as);
		    break;
		default :break;
		}
	    }
	}
    }
}

	
    
/*

  get_rt_table

*/
char *get_rt_table(id,ifaddr)
u_long id;
u_long ifaddr;
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtifp;
    
    if(!id || !ifaddr) {
	log_trace(stderr,"invalid argment <id = %d, ifaddr = %d> in get_rt_table\n",id,ifaddr);
	return NULL;
    }

    if(!(rt = router_search(id)))
      return;
    
    for(rtifp=rt->rt_ifp;rtifp!=NULL;rtifp=rtifp->next) {
	if(RT_IF_ADDR(rtifp) == ifaddr)
	  break;
    }

    if(rtifp)
      return rtifp->rt_table;
    else
      return NULL;
}

/*

  table_make

*/
void table_make(id)
u_long id;
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;

    if(!id) {
	log_trace(stderr,"invalid argment <id = %d> in table_make\n",id);
	return ;
    }

    if(!(rt = router_search(id)))
      return ;
    
    for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	if(rtif->state == INTF_UP) {
	    if_table_make(rtif);
	}
    }
}

/*

  if_table_make

*/
void if_table_make(rtif)
struct RT_IFCONF *rtif;
{
    if(!rtif) {
	log_trace(stderr,"invalid argment <rtif = %x> in if_table_make\n",rtif);
	return ;
    }

    switch(rtif->protocol) {
    case T_PROTO_BGP : break;
    case T_PROTO_OSPF : rtif->rt_table = ospf_rt_table(rtif->self->router_id,rtif);
    default : break;
    }
}
						 
/*

  lsdb_update

*/
void lsdb_update(rt_if)
u_long rt_if;
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    
    if(!rt_if) {
	log_trace(stderr,"invalid argment <rt_if = %d> in lsdb_update\n",rt_if);
	return ;
    }

    for(rt=rt_list;rt;rt=rt->next) {
	for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	    if(rt_if != RT_IF_ADDR(rtif) && rtif->rt_table != NULL) {
		delete_lsdb(rt->router_id,RT_IF_ADDR(rtif));
		rtif->rt_table = ospf_rt_table(rt->router_id,rtif);
		/*ospf_rt_update(rt->router_id,rtif->proto_info,SEND);*/
	    }
	}
    }
}

/*

  table_update

*/
void table_update(id,rt_if)
u_long id;
u_long rt_if;
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    
    if(!id || !rt_if) {
	log_trace(stderr,"invalid argment <id = %d, rt_if = %d> in table_update\n",id,rt_if);
	return ;
    }

#ifdef DEBUG
    printf("\n Routing Table Update\n\n");
#endif
    
    if(!(rt = router_search(id)))
      return ;
    
    for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
        if(rt_if != RT_IF_ADDR(rtif)) continue;  /* if specified interface */
	if(rtif->rt_table != NULL) {             /* run table update       */
	    delete_lsdb(id,RT_IF_ADDR(rtif));    /* 1996.12.18             */
	    rtif->rt_table = ospf_rt_table(id,rtif);
	}
    }
}


/*

  add_router_if_list - add router interface list

*/
void add_router_if_list(rtp, add_rt_ifp)
struct RT_CONF *rtp;
struct RT_IFCONF *add_rt_ifp;
{
    struct RT_IFCONF *rt_ifp;
    struct RT_IFCONF *list = rtp->rt_ifp;
    
    if(list == NULL) {
	rtp->rt_ifp = add_rt_ifp;
    }
    else {
	for(rt_ifp=list;rt_ifp->next;rt_ifp = rt_ifp->next);
	rt_ifp->next = add_rt_ifp;
    }
}

/*

  rt_conf_check

*/
int rt_conf_check(id)
u_long id;
{
    struct RT_CONF *rt;

    for(rt=rt_list;rt;rt=rt->next) {
	if(rt->router_id == id) return 1;
    }

    return 0;
}

/*

  rt_if_conf_check

*/
int rt_if_conf_check(id,rt_if)
u_long id;
u_long rt_if;
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;

    for(rt=rt_list;rt;rt=rt->next) {
	if(rt->router_id == id) {
	    for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
		if(RT_IF_ADDR(rtif) == rt_if) return 1;
	    }
	}
    }

    return 0;
}

/*

  router_list_dump

*/
void router_list_dump()
{
    struct RT_CONF *rtp;

    for(rtp=rt_list;rtp;rtp=rtp->next) {
	printf("\n\n router ID: %s\n",rtp->mng_id);
	router_if_dump(stderr,rtp->rt_ifp);

    }
}

/*

  router_dump

*/
void router_dump(rt_id,file)
u_long rt_id;
char *file;
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    FILE *fp;
    time_t time;

    if(file != NULL) {
	if((fp = fopen(file,"a+")) == NULL) {
	    log_trace(stderr,"dump file (%s) open failure\n",file);
	    return;
	}
    }
    else {
	fp = stderr;
    }
    
    if(!(rt = router_search(rt_id)))
      return ;

    if(rt->trace_flag) {
	log_trace(rt->trace_fp,"\n <<< routerDUMP (%s) >>>\n",inetaddr_to_char(ntohl(rt_id)));
    }
    
    log_trace(stderr,"\n <<< routerDUMP (%s) >>>\n",inetaddr_to_char(ntohl(rt_id)));	  
    time = get_currnt_time();
    log_trace(fp,"Router ID %s Dump at %s\n",rt->mng_id,time_to_char(&time));
    
    for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	router_if_dump(fp,rtif);
	switch(rtif->protocol) {
	case T_PROTO_BGP : break;
	case T_PROTO_OSPF : ospf_dump(fp,rtif->proto_info);
	    break;
	default : break;
	}
    }

    fclose(fp);
}

/*

  router_if_dump

*/
void router_if_dump(fp,rt_ifp)
FILE *fp;
struct RT_IFCONF *rt_ifp;
{
    struct RT_IFCONF *rtifp;

    if(fp == NULL) fp = stderr;
    
    if(!rt_ifp) {
	log_trace(stderr,"invalid argment <rt_ifp = %x> in router_if_dump\n",rt_ifp);
	return ;
    }

    for(rtifp=rt_ifp;rtifp;rtifp=rtifp->next) {
	log_trace(fp,"\n interface ID : %s",rtifp->mng_id);
	log_trace(fp,"\n 	interface = ");
	if_addr_dump(fp,rtifp->local_addr);
	log_trace(fp,"  : neighbor = ");	
	if_addr_dump(fp,rtifp->remote_addr);
	log_trace(fp,"\n	 (router ID = %s) ",rtifp->self->mng_id);
	switch(rtifp->protocol) {
	case T_PROTO_BGP : log_trace(fp,"\n 	protocol = BGP \n");
	    		   proto_bgp_dump(fp,(struct proto_bgp *)rtifp->proto_info,fp);
	    		   break;
	case T_PROTO_OSPF :log_trace(fp,"\n 	protocol = OSPF \n");
	    		   proto_ospf_dump(fp,(struct PROTO_OSPF *)rtifp->proto_info);	    
	    		   break;
        default		  :break;
        }
	      
    }

}


/*

  router_trace_on

*/
int router_trace_on(id,file)
u_long id;
char *file;
{
    struct RT_CONF *rt;
    time_t start;
    
    if(!id) {
	log_trace(stderr,"invalid argment <id = %d> in router_trace_on\n",id);
	return 0;
    }

    if(!(rt = router_search(id)))
      return 0;

    rt->trace_flag = ON;

    if(rt->trace_fp == NULL) {
	if((rt->trace_fp = fopen(file,"a+")) == NULL) {
	    printf("trace file cannot open !\n");
	    return 0;
	}
    }
    else {
	if((rt->trace_fp = fopen(file,"a+")) == NULL) {
	    printf("trace file cannot open !\n");
	    return 0;
	}
    }

    start = get_currnt_time();
    log_trace(rt->trace_fp,"\n  Trace Start at : %s \n",time_to_char(&start));
    
    return 1;
}

/*

  router_trace_off

*/
int router_trace_off(id)
u_long id;
{
    struct RT_CONF *rt;
    time_t stop;
    
    if(!id) {
	log_trace(stderr,"invalid argment <id = %d> in router_trace_off\n",id);
	return 0;
    }

    if(!(rt = router_search(id)))
      return 0;

    rt->trace_flag = OFF;

    stop = get_currnt_time();

    if(rt->trace_fp != NULL) {
	log_trace(rt->trace_fp,"\n  Trace Stop at : %s \n",time_to_char(&stop));
	fclose(rt->trace_fp);
    }
}

/*

  get_trace_flag

*/
int get_trace_flag(id)
u_long id;
{
    struct RT_CONF *rt;

    if(!id) {
	log_trace(stderr,"invalid argment <id = %d> in get_trace_flag\n",id);
	return 0;
    }

    if(!(rt = router_search(id)))
      return 0;
    
    return(rt->trace_flag);
}

/*

  get_trace_fp

*/
FILE *get_trace_fp(id)
u_long id;
{
    struct RT_CONF *rt;

    if(!id) {
	log_trace(stderr,"invalid argment <id = %d> in router_trace_on\n",id);
	return 0;
    }

    if(!(rt = router_search(id)))
      return NULL;

    return(rt->trace_fp);
}


/*

  router_wait

*/
void router_wait(id,interval)
u_long id;
time_t interval;
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    byte *packet;
    char *wait_timer;
/*    time_t t;*/
    struct OSPF_IF *intf;

    if(!id) {
	log_trace(stderr,"invalid argment <id = %d> in router_wait\n",id);
	return ;
    }

    if(!(rt = router_search(id)))
      return ;

    if(rt->trace_flag) {
	log_trace(rt->trace_fp,"\n <<< wait start(%s) >>>\n",inetaddr_to_char(ntohl(id)));
    }
    
    log_trace(stderr,"\n <<< wait start(%s) >>>\n",inetaddr_to_char(ntohl(id)));
    
    wait_timer_flag = OFF;
    wait_timer = timer_init(id,NULL,router_timeout);
    timer_set(wait_timer,interval);
	      
/*    t = get_currnt_time();*/
    
    while(!wait_timer_flag) {
	timer_check();
	for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	    switch(rtif->protocol) {
	    case T_PROTO_BGP :break;
	    case T_PROTO_OSPF:ospf_recv_wait(id,rtif);
			  break;
		default : break;
	    }
	}
    }

    timer_stop(wait_timer);
    wait_timer_flag = OFF;

    if(rt->trace_flag) {
	log_trace(rt->trace_fp,"\n <<< wait stop(%s) >>>\n",inetaddr_to_char(ntohl(id)));
    }

    log_trace(stderr,"\n <<< wait stop(%s) >>>\n",inetaddr_to_char(ntohl(id))); 
}

/*

  router_timeout

*/
void router_timeout(id,data)
u_long id;
char *data;
{
    if(!id) {
	log_trace(stderr,"invalid argment <id = %d> in router_timeout\n",id);
	return ;
    }

    /*    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    
    for(rt=rt_list;rt;rt=rt->next) {
	for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	    switch(rtif->protocol) {
	    case T_PROTO_BGP : break;
	    case T_PROTO_OSPF : ospf_message_send(rtif,1);
		default : break;
	    }
	}
    } */
    wait_timer_flag = ON;
}    

/*

  config_free

*/
void config_free()
{
    struct RT_CONF *rt,*next_rt;
    struct RT_IFCONF *rtif,*next_if;
    
    for(rt=rt_list;rt;) {
	next_rt = rt->next;
	for(rtif=rt->rt_ifp;rtif;) {
	    next_if = rtif->next;
	    switch(rtif->protocol) {
	    case T_PROTO_BGP : break;
	    case T_PROTO_OSPF : ospf_config_free(rtif->proto_info);
	    default : break;
	    }
	    if_addr_free(rtif->local_addr);
	    if_addr_free(rtif->remote_addr);
	    free((char *)rtif->local_addr);
	    free((char *)rtif->remote_addr);	    
	    free((char *)rtif);
	    rtif = next_if;
	}
	rt = next_rt;
    }

    rt_list = NULL;
}


/*

  krl_route_add

*/
void krl_route_add(id,src_if,dst_if)
u_long id;
u_long src_if;
u_long dst_if;
{
    u_long dst,next_hop;
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    char addr[16],gw_addr[16];
    static char *argv[]={"/usr/etc/route","add","net",NULL,NULL,"1",NULL};
    
    if(!id || !src_if || !dst_if) {
	log_trace(stderr,"invalid argment <id = %d,src_if = %d,dst_if = %d> in krl_route_add\n",id,src_if,dst_if);
	return ;
    }

    dst = dst_if & 0xffff0000;
/*    strcpy(addr,inetaddr_to_char(dst));*/

    if(!(rt = router_search(id)))
      return ;
    
    for(rtif=rt->rt_ifp;rtif;rtif=rtif->next)
        if(src_if == RT_IF_ADDR(rtif)) break;

    next_hop = IF_ADDR(rtif->remote_addr);
/*    strcpy(gw_addr,inetaddr_to_char(next_hop));*/
/*
    argv[3] = addr;
    argv[4] = gw_addr;

  */
    sys_route_add(dst,next_hop);
}


/*

  krl_route_delete

*/
void krl_route_delete(id,src_if,dst_if)
u_long id;
u_long src_if;
u_long dst_if;
{
    u_long dst,next_hop;
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    char addr[16],gw_addr[16];
    static char *argv[]={"/usr/etc/route","delete","net",NULL,NULL,NULL};
    
    if(!id || !src_if || !dst_if) {
	log_trace(stderr,"invalid argment <id = %d,src_if = %d,dst_if = %d> in krl_route_delete\n",id,src_if,dst_if);
	return ;
    }

    dst = dst_if & 0xffff0000;
    strcpy(addr,inetaddr_to_char(dst));

    rt = router_search(id);
    for(rtif=rt->rt_ifp;rtif;rtif=rtif->next)
        if(src_if == RT_IF_ADDR(rtif)) break;

    next_hop = IF_ADDR(rtif->remote_addr);
    strcpy(gw_addr,inetaddr_to_char(next_hop));

    argv[3] = addr;
    argv[4] = gw_addr;

    sys_route_delete(dst,next_hop);
}

  
/*

  display_on

*/
void display_on(id,rt_if,proto,type)
u_long id;
u_long rt_if;
int proto;
int type;
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    time_t time;

    if(!id || !rt_if) {
	log_trace(stderr,"invalid argment <id = %d,rt_if = %d> in display_on\n",id,rt_if);
	return ;
    }

    if(!(rt = router_search(id)))
      return;

    for(rtif=rt->rt_ifp;rtif;rtif=rtif->next)
	if(rt_if == RT_IF_ADDR(rtif)) break;

    if(!rt_if)
      return ;
    
    if(rt->trace_flag) {
	log_trace(rt->trace_fp,"\n <<< displayON (%s) >>>\n",inetaddr_to_char(id));
    }
    
    log_trace(stderr,"\n <<< displayON (%s) >>>\n",inetaddr_to_char(id));
    
    switch(rtif->protocol) {
    case T_PROTO_BGP : break;
    case T_PROTO_OSPF : ospf_display(rtif->proto_info,type,ON);
	    break;
    default : break;
    }

}

  
/*

  display_off

*/
void display_off(id,rt_if,proto,type)
u_long id;
u_long rt_if;
int proto;
int type;
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;

    if(!id || !rt_if) {
	log_trace(stderr,"invalid argment <id = %s,rt_if = %d> in display_off\n",inetaddr_to_char(id),rt_if);
	return ;
    }

    if(!(rt = router_search(id)))
      return;

    for(rtif=rt->rt_ifp;rtif;rtif=rtif->next)
	if(rt_if == RT_IF_ADDR(rtif)) break;

    if(!rt_if)
      return ;
    
    if(rt->trace_flag) {
	log_trace(rt->trace_fp,"\n <<< displayOFF (%s) >>>\n",inetaddr_to_char(id));
    }
    
    log_trace(stderr,"\n <<< displayOFF (%s) >>>\n",inetaddr_to_char(id));
    
    switch(rtif->protocol) {
    case T_PROTO_BGP : break;
    case T_PROTO_OSPF : ospf_display(rtif->proto_info,type,OFF);
	    break;
    default : break;
    }

}

    
/*

  display_ok

*/
short display_ok(id,rt_if,type)
u_long id;
u_long rt_if;
int type;
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    short flag;
    
    if(!id || !rt_if) {
	log_trace(stderr,"invalid argment <id = %s,rt_if = %d> in display_ok\n",inetaddr_to_char(id),rt_if);
	return 1;
    }
    
    if(!(rt = router_search(id)))
      return 1;

    for(rtif=rt->rt_ifp;rtif;rtif=rtif->next)
	if(rt_if == RT_IF_ADDR(rtif)) break;

    if(!rtif)
      return 1;
    
    switch(rtif->protocol) {
    case T_PROTO_BGP : break;
    case T_PROTO_OSPF : flag = ospf_display_ok(rtif->proto_info,type);
	    break;
    default : break;
    }

    return flag;
}

    
/*

  route_flush

*/
void route_flush(id)
u_long id;
{
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    u_long area;

    if(!(rt = router_search(id)))
      return ;

    if(rt->trace_flag) {
	log_trace(rt->trace_fp,"\n <<< routeFLUSH (%s) >>>\n",inetaddr_to_char(id));
    }
    
    log_trace(stderr,"\n <<< routeFLUSH (%s) >>>\n",inetaddr_to_char(id));
    for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	switch(rtif->protocol) {
	case T_PROTO_BGP : break;
	case T_PROTO_OSPF : /*delete_lsdb(rt->router_id,RT_IF_ADDR(rtif));
		rtif->rt_table = ospf_rt_table(rt->router_id,rtif);*/
	      ospf_rt_aging(rt->router_id,rtif->proto_info);
		router_wait(rt->router_id,10);
		break;
	default :break;
	}
    }
}

/*

  network_up

*/
void network_up(net_addr)
u_long net_addr;
{
    u_long rt_id;
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    
    log_trace(stderr,"\n <<< networkUP (%s) >>>\n",inetaddr_to_char(ntohl(net_addr)));

    if(!(rt_id=net_link_state(net_addr, INTF_UP))) {
	log_trace(stderr,"\n network(%s) don't exit>\n",inetaddr_to_char(ntohl(net_addr)));
	return;
    }

    for(rt=rt_list;rt;rt=rt->next) {
	if(rt->trace_flag) {
	    log_trace(rt->trace_fp,"\n <<< networkUP (%s) >>>\n",inetaddr_to_char(ntohl(net_addr)));
	}
	for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	    switch(rtif->protocol) {
	    case T_PROTO_BGP  : break;
	    case T_PROTO_OSPF :	table_update(rt->router_id,RT_IF_ADDR(rtif));
				ospf_rt_update(rt->router_id,rtif->proto_info,SEND);
				break;
	    default : break;
	    }
	}
    }

}

/*

  network_down

*/
void network_down(net_addr)
u_long net_addr;
{
    u_long rt_id;
    u_long area;
    int as;
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    
    log_trace(stderr,"\n <<< networkDOWN (%s) >>>\n",inetaddr_to_char(ntohl(net_addr)));

    if(!(rt_id=net_link_state(net_addr, INTF_DOWN))) {
	log_trace(stderr,"\n network(%s) don't exit>\n",inetaddr_to_char(ntohl(net_addr)));
	return;
    }

    for(rt=rt_list;rt;rt=rt->next) {
      	if(rt->trace_flag) {
	    log_trace(rt->trace_fp,"\n <<< networkDOWN (%s) >>>\n",inetaddr_to_char(ntohl(net_addr)));
	}
    }
/*    rt_unreachable(rt_id);*/
        for(rt=rt_list;rt;rt=rt->next) {
	for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	    if((area=rt_area_check(rt_id,rt->router_id))
	    || (as=rt_as_check(rt_id,rt->router_id))) {
	        area = get_net_area(net_addr);
		switch(rtif->protocol) {
		case T_PROTO_BGP : break;
		case T_PROTO_OSPF : ospf_rt_unreachable(rt->router_id,rtif->proto_info,area,as);
		    break;
		default :break;
		}
	    }
	}
    }
}

/*

  area_up

*/
void area_up(area_id)
u_long area_id;
{
    u_long net_addr;
    u_long abr_id;
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    
    log_trace(stderr,"\n <<< area_up (%s) >>>\n",inetaddr_to_char(ntohl(area_id)));

    if(!(abr_id = get_abr_id(area_id))) {
	log_trace(stderr,"\n can't find abr\n");
	return ;
    }

    abr_link_state(abr_id,area_id,INTF_UP);
    for(rt=rt_list;rt;rt=rt->next) {
	if(rt->trace_flag) {
	    log_trace(rt->trace_fp,"\n <<< areaUP (ID %s) >>>\n",inetaddr_to_char(ntohl(area_id)));
	}
	for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	    switch(rtif->protocol) {
	    case T_PROTO_BGP  : break;
	    case T_PROTO_OSPF :	table_update(rt->router_id,RT_IF_ADDR(rtif));
				ospf_rt_update(rt->router_id,rtif->proto_info,SEND);
				break;
	    default : break;
	    }
	}
    }

}

/*

  area_down

*/
void area_down(area_id)
u_long area_id;
{
    u_long net_addr;
    u_long abr_id;
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    int as;
    
    log_trace(stderr,"\n <<< area_down (%s) >>>\n",inetaddr_to_char(ntohl(area_id)));

    if(!(abr_id = get_abr_id(area_id))) {
	log_trace(stderr,"\n can't find abr\n");
	return ;
    }
       
    for(rt=rt_list;rt;rt=rt->next) {
	if(rt->trace_flag) {
	    log_trace(rt->trace_fp,"\n <<< areaDOWN (%s) >>>\n",inetaddr_to_char(ntohl(net_addr)));
	}
    }
    abr_link_state(abr_id,area_id,INTF_DOWN);
/*    rt_unreachable(abr_id);*/

    as = 0;
    for(rt=rt_list;rt;rt=rt->next) {
	for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	    switch(rtif->protocol) {
	    case T_PROTO_BGP : break;
	    case T_PROTO_OSPF : ospf_rt_unreachable(rt->router_id,rtif->proto_info,area_id,as);
		    break;
		default :break;
	    }
	}
    }
}

/*

  as_up

*/
void as_up(as_num)
int as_num;
{
    u_long net_addr;
    u_long abr_id;
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    
    log_trace(stderr,"\n <<< as_up (%d) >>>\n",as_num);

/*    if(!(abr_id = get_abr_id(area_id))) {
	log_trace(stderr,"\n can't find abr\n");
	return ;
    }
*/
    as_link_state(as_num,INTF_UP);
    for(rt=rt_list;rt;rt=rt->next) {
	if(rt->trace_flag) {
	    log_trace(rt->trace_fp,"\n <<< asUP (AS %d) >>>\n",as_num);
	}
	for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	    switch(rtif->protocol) {
	    case T_PROTO_BGP  : break;
	    case T_PROTO_OSPF :	table_update(rt->router_id,RT_IF_ADDR(rtif));
				ospf_rt_update(rt->router_id,rtif->proto_info,SEND);
				break;
	    default : break;
	    }
	}
    }

}

/*

  as_down

*/
void as_down(as_num)
int as_num;
{
    u_long net_addr;
    u_long asbr_id;
    struct RT_CONF *rt;
    
    log_trace(stderr,"\n <<< as_down (%d) >>>\n",as_num);

    if(!(asbr_id = get_asbr_id(as_num))) {
	log_trace(stderr,"\n can't find asbr\n");
	return ;
    }
       
    for(rt=rt_list;rt;rt=rt->next) {
	if(rt->trace_flag) {
	    log_trace(rt->trace_fp,"\n <<< asDOWN (%s) >>>\n",inetaddr_to_char(net_addr));
	}
    }
    as_link_state(as_num,INTF_DOWN);
    rt_unreachable(asbr_id);
}

/*
  
  rtable_dump

*/
int rtable_dump(file)
char *file;
{
    FILE *fp;
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    
    fp = fopen(file,"w");
      
    if(rt_list == NULL) return;
    
    for(rt=rt_list;rt;rt=rt->next) {
	for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	    switch(rtif->protocol) {
	    case T_PROTO_BGP	: break;
	    case T_PROTO_OSPF 	: if(fp != NULL)
	                              ospf_bin_dump(fp,rtif->proto_info);
		                  else
				      ospf_dump(stderr,rtif->proto_info);
		                  break;
	    default 		: break;
	    }

	}
    }

    fclose(fp);
}

/*
  
  rtable_load

*/
int rtable_load(file)
char *file;
{
    FILE *fp;
    struct RT_CONF *rt;
    struct RT_IFCONF *rtif;
    
    if((fp = fopen(file,"r")) == NULL) return;
 
     log_trace(stderr,"\n <<< table load (%s) >>>\n",file);
    for(rt=rt_list;rt;rt=rt->next) {
	for(rtif=rt->rt_ifp;rtif;rtif=rtif->next) {
	    switch(rtif->protocol) {
	    case T_PROTO_BGP	: break;
	    case T_PROTO_OSPF 	: ospf_load(fp,rt->router_id,rtif);
/* #ifdef DEBUG
		ospf_dump(stderr,rtif->proto_info);
#endif */
		ospf_start(rt->router_id,rtif);
		break;
	    default 		: break;
	    }

	}
    }

    fclose(fp);
}

