/************************************************************************/
/*	Routing Protocol Simulator	Release 1.0	1994/3/17	*/
/*                                              1.21    1997/2/10       */
/*									*/
/*		module 	: routing table management	     	       	*/
/*		file	: lsdb.c			       		*/
/*									*/
/*   Copyright (c) 1994-1997 by Systems Development Laboratory Hitachi, */
/*   Ltd. All rights reserved.						*/
/*----------------------------------------------------------------------*/
/*	UPDATE HISTORY							*/
/*      1995/7/11  add binary lsdb dump routine       		        */
/*      1996/7/12  add flooding procedure                               */
/************************************************************************/
static char copyright[]=
  "@(#)Copyright (c) 1994 by Systems Development Laboratory Hitachi,Ltd.\n All rights researved.\n";

#include "rps.h"
#include "netmng.h"
#include "ospf_type.h"

extern struct AS_TBL *get_as_list();
extern struct RT_TBL *get_rt_list();
extern u_long as_num;
extern u_long area_num;
extern u_long get_dr_addr();
extern struct INDEX  *get_abr();
extern void get_min_path();
extern long get_net_cost();
extern long get_rt_cost();
extern long path_rt_cost();
extern struct LINK_TBL *get_link_list();
extern struct AS_TBL *get_router_as();
extern u_long path_exsit_area();
extern struct RT_TBL *rt_search();
extern struct RT_TBL *abr_search();
extern struct RT_TBL *asbr_search();
extern struct NET_TBL *get_link_net();
extern struct NET_TBL *get_net_list();
struct LS_RT_HDR_LIST *rt_link_load();
struct LS_NET_HDR_LIST *net_link_load();
struct LS_SUM_HDR_LIST *sum_net_link_load();
struct LS_SUM_HDR_LIST *sum_asbr_link_load();
struct LS_ASE_HDR_LIST *ase_link_load();

struct LSDB_LIST *lsdb_list = NULL;
time_t make_lsdb_time;

#define STUB		2
#define VIRTUAL 	3

char *ls_type[] =
{ "no type","Router","Network","Sum_net","Sum_asb","Ase"};

char *link_type[] =
{ "no type","Router", "Trans net","Stub net","Virtual"};

void lsdb_free();
u_short rt_link();
u_short rt_link_virtual();
void ls_rt_dump();

u_long ls_seq_num=INIT_LS_SEQ_NUM;
int need_remake_lsdb;  /* if make lsdb again */

/*

 lsdb_init

*/
void lsdb_init()
{
    lsdb_list = NULL;
}

/*

  make_lsdb

*/
byte *make_lsdb(id,intf,type,arg)
u_long id;
u_long intf;
int type;
int arg;
{
    struct AS_TBL *as;
    struct AREA_TBL *area;
    struct RT_TBL *rt;
    u_long area_num;
    u_long as_num;
    struct LSDB_LIST *lsdb;
    struct LSDB_LIST *list;
    
    if(!id || !intf) {
	log_trace(stderr,"invalid argment <id = %d,intf = %d> in make_lsdb\n",id,intf);
	return NULL;
    }

#ifdef DEBUG
    printf("Making Link State DataBase\n");
#endif
    as_num = get_as_num(id);
    if(type==VIRTUAL) {
	area_num = 0; /* backbone-area */
    }
    else {
	area_num = get_area_num(id,intf);
    }
    as=get_as_list(as_num);
    for(area=as->alist;area;area=area->next)
      if(area->number == area_num) break;

    if(!area) {
	log_trace(stderr,"not exit area <%s> data\n",inetaddr_to_char(area_num));
	return NULL;
    }

    for(list=lsdb_list;list;list=list->next) {
	if(list->area == (char *)area)
	    return (byte *)list;
    }
    
    MALLOC(lsdb,LSDB_LIST);
      
    lsdb->area = (char *)area;
    lsdb->rt_id = id;
    if(type==VIRTUAL) {
	lsdb->rt = make_rt_link_virtual(area,id,(u_long)arg);
	rt = rt_search(id);
	if(!rt_area_search(id,0))
	  add_abr_list(area,rt);
	lsdb->sum_net = make_sum_net_link(area,id);
	lsdb->sum_asbr = make_sum_asbr_link(area,id);
    }
    else {
	lsdb->rt = make_rt_link(area);
	lsdb->net = make_net_link(area);
	lsdb->sum_net = make_sum_net_link(area,id);
	lsdb->sum_asbr = make_sum_asbr_link(area,id);
    }
    if(type==STUB)
      lsdb->default_sum = make_default_sum_link(area,id,arg);
    else
      lsdb->ase = make_ase_link(area);
    
    make_lsdb_time = get_currnt_time();
    
    if(lsdb_list == NULL) {
	lsdb_list = lsdb;
    }
    else {
	for(list=lsdb_list;list->next;list=list->next);
	list->next = lsdb;
    }

/*    lsdb_dump();*/
    
    ls_seq_num++;
    need_remake_lsdb=0;
    
    return (byte *)lsdb;
}

/*

  delete_lsdb

*/
void delete_lsdb(id,intf)
u_long id;
u_long intf;
{
    struct AS_TBL *as;
    struct AREA_TBL *area;
    u_long area_num;
    u_long as_num;
    struct LSDB_LIST *list,*pre_list;
    
    if(!id || !intf) {
	log_trace(stderr,"invalid argment <id = %d,intf = %d> in delete_lsdb\n",id,intf);
	return ;
    }

    as_num = get_as_num(id);
    area_num = get_area_num(id,intf);
    as=get_as_list(as_num);
    for(area=as->alist;area;area=area->next)
      if(area->number == area_num) break;

    if(!area) {
	log_trace(stderr,"not exit area <%s> data\n",inetaddr_to_char(area_num));
	return ;
    }

    pre_list = lsdb_list;
    for(list=lsdb_list;list;list=list->next) {
	if(list->area == (char *)area) {
	    if(list == lsdb_list) lsdb_list = list->next;
	    else 	    pre_list->next = list->next;

	    lsdb_free(list);
	    break;
	}
	pre_list = list;
    }

}
    
/*

  make_rt_link

*/
struct LS_RT_HDR_LIST *make_rt_link(area)
struct AREA_TBL *area;
{
    struct RT_TBL *rt,*abr;
    struct NET_TBL *net;
    struct INDEX *index,*nidx,*aidx;
    struct LS_RT_HDR_LIST *ls_rt_list,*tmp;
    u_short rt_link_num;
    struct LS_HDR *hdr;
    struct LS_RT_HDR_LIST *rt_hdr;
    struct RT_INTF *cnet;
    u_short len;
    
    if(!area) {
	log_trace(stderr,"invalid argment <area = %x> in make_rt_link\n",area);
	return NULL;
    }

#ifdef DEBUG
    printf("start make_rt_link at %d \n", get_currnt_time());
#endif
    
    ls_rt_list = NULL;
    rt_link_num = 0;
    for(nidx=area->nlist;nidx;nidx=nidx->next) {
	net = (struct NET_TBL *)nidx->dst;

	for(index=net->cnct_rt;index;index=index->next) {
	    rt = (struct RT_TBL *)index->dst;

	    IF_STATE_DOWN(rt,net);

	    if(!rt_path_check(rt->id,area))
	      continue;

	    if(get_rt_link(ls_rt_list,rt) !=  NULL)
	      continue;
	    
	    MALLOC(rt_hdr,LS_RT_HDR_LIST);

	    if(abr_search(area,rt) != NULL)
	        rt_hdr->bits = BORDER_BIT;
	    if(asbr_search(area->as_idx,rt) != NULL)
	        rt_hdr->bits |= EXTERNAL_BIT;
	    
	    rt_hdr->hdr.ls_type = (u_char)LS_TYPE_RT;
	    rt_hdr->hdr.ls_id = rt->id;
	    rt_hdr->hdr.adv_rt = rt->id;
	    if(rt_hdr->hdr.ls_seq) {
		rt_hdr->hdr.ls_seq++;
	    }
	    else {
		rt_hdr->hdr.ls_seq  = ls_seq_num;
	    }
	    rt_link_num = rt_link(&(rt_hdr->rt_link),rt,area);
	    rt_hdr->link = rt_link_num;
	    rt_hdr->hdr.length = LS_RT_HDR_SIZE + rt_link_num * LS_RT_SIZE;

	    if(ls_rt_list == NULL) {
		ls_rt_list = rt_hdr;
		tmp = rt_hdr;
	    }
	    else {
		tmp->next = rt_hdr;
		tmp = rt_hdr;
	    }
	}
    }
#ifdef DEBUG
    printf("end make_rt_link at %d \n", get_currnt_time());
#endif

    return ls_rt_list;
}

/*

  make_rt_link_virtual

*/
struct LS_RT_HDR_LIST *make_rt_link_virtual(area,my_id,nbr_id)
struct AREA_TBL *area;
u_long my_id;
u_long nbr_id;
{
    struct RT_TBL *rt,*abr;
    struct NET_TBL *net;
    struct INDEX *index,*nidx,*aidx;
    struct LS_RT_HDR_LIST *ls_rt_list,*tmp;
    u_short rt_link_num;
    struct LS_HDR *hdr;
    struct LS_RT_HDR_LIST *rt_hdr;
    struct RT_INTF *cnet;
    u_short len;
    u_long rt_id[2],link_id;
    int rt_num;
    
    if(!area || !my_id || !nbr_id) {
	log_trace(stderr,"invalid argment <area = %x,my_id = %d,nbr_id = %d> in make_rt_link_virtual\n",area,my_id,nbr_id);
	return NULL;
    }

    ls_rt_list = NULL;
    rt_link_num = 0;
    rt_id[0] = my_id;
    rt_id[1] = nbr_id;
    net = get_link_net(rt_id[0],rt_id[1]);
    
    for(rt_num=0;rt_num<2;rt_num++) {
	rt = rt_search(rt_id[rt_num]);

	IF_STATE_DOWN(rt,net);

	if(!rt_path_check(rt->id,area))
	    continue;
	if(get_rt_link(ls_rt_list,rt) !=  NULL)
	    continue;
	    
	MALLOC(rt_hdr,LS_RT_HDR_LIST);

	if(abr_search(area,rt) != NULL)
	    rt_hdr->bits = BORDER_BIT;
	if(asbr_search(area->as_idx,rt) != NULL)
	    rt_hdr->bits |= EXTERNAL_BIT;
	    
	rt_hdr->hdr.ls_type = (u_char)LS_TYPE_RT;
	rt_hdr->hdr.ls_id = rt->id;
	rt_hdr->hdr.adv_rt = rt->id;
	rt_hdr->hdr.ls_seq = ls_seq_num;
	
	rt_link_num = rt_link(&(rt_hdr->rt_link),rt,area);
	if(rt->id == my_id) link_id = nbr_id;
	else if(rt->id == nbr_id) link_id = my_id;
	rt_link_num += rt_link_virtual(&(rt_hdr->rt_link),rt,net,link_id);
	rt_hdr->link = rt_link_num;
	rt_hdr->hdr.length = LS_RT_HDR_SIZE + rt_link_num * LS_RT_SIZE;

	if(ls_rt_list == NULL) {
	    ls_rt_list = rt_hdr;
	    tmp = rt_hdr;
	}
	else {
	    tmp->next = rt_hdr;
	    tmp = rt_hdr;
	}
    }

    return ls_rt_list;
}
	
/*

  rt_link

*/
u_short rt_link(list,rt,area)
struct LS_RT_LIST **list;
struct RT_TBL *rt;
struct AREA_TBL *area;
{
    struct LS_RT_LIST *ls_rtp,*tmp;
    struct RT_INTF *cnct,*ilist;
    struct NET_TBL *net;
    struct INDEX *index;
    struct RT_TBL *abr,*cnct_rt;
    u_short link;
    int cnct_num;

    if(!list || !rt || !area) {
	log_trace(stderr,"invalid argment <list = %x,rt = %x,area = %x> in rt_link\n",list,rt,area);
	return 0;
    }

    link = 0;
    for(cnct=rt->ilist;cnct;cnct=cnct->next) {

	if(cnct->state == INTF_DOWN) continue;

	net=cnct->net;
	cnct_num = 1;
	if(net->domain_type != ITYPE_AREA ||
	  (net->domain_type == ITYPE_AREA && (char *)area != net->domain))
	  continue;

	MALLOC(ls_rtp,LS_RT_LIST);

/*	log_trace(stderr,"rt_link : %s \n", inetaddr_to_char(net->addr));*/
	for(index=net->cnct_rt;index;index=index->next) {
	    cnct_rt = (struct RT_TBL *)index->dst;
	    if(cnct_rt == rt) continue;
	    for(ilist=cnct_rt->ilist;ilist;ilist=ilist->next) {
		if(ilist->net == net) {
		    if(ilist->state == INTF_UP) {
/*			log_trace(stderr,"connect : %s \n", inetaddr_to_char(cnct_rt->id));*/
			cnct_num++;
		    }
		}
	    }
	}
	
	if(cnct_num == 1) {
	    link++;
	    ls_rtp->type = RTIF_TYPE_STUB_NET;
	    ls_rtp->id = cnct->net->addr;
	    ls_rtp->data = cnct->net->mask;
	    ls_rtp->tos_num = 0;
	    ls_rtp->tos0_metric = cnct->cost;
	}
	else {
	    link++;
	    ls_rtp->type = (u_char)RTIF_TYPE_TRANS_NET;
	    ls_rtp->id = get_dr_addr(cnct->net->addr);
	    ls_rtp->data = cnct->ifaddr;
	    ls_rtp->tos_num = (u_char)0;
	    ls_rtp->tos0_metric = cnct->cost;
	}
	
	if(*list == NULL) {
	    *list = ls_rtp;
	    tmp = ls_rtp;
	}
	else {
	    tmp->next = ls_rtp;
	    tmp = ls_rtp;
	}
    }
    
    return link;
}

/*

  rt_link_virtual

*/
u_short rt_link_virtual(list,v_rt,net,nbr_id)
struct LS_RT_LIST **list;
struct RT_TBL *v_rt;
struct NET_TBL *net;
u_long nbr_id;
{
    struct LS_RT_LIST *ls_rtp,*tmp;
    struct RT_INTF *cnct;
    struct INDEX *index;
    struct RT_TBL *abr,*rt;
    u_short link;
    
    if(!list || !v_rt || !net || !nbr_id) {
	log_trace(stderr,"invalid argment <list = %x,v_rt = %x,net = %x,nbr_id = %d> in rt_link\n",list,v_rt,net,nbr_id);
	return 0;
    }

    link = 0;
    tmp = *list;
    get_min_path(v_rt->id);
    
    for(index=net->cnct_rt;index;index=index->next) {
	rt = (struct RT_TBL *)index->dst;

	if(rt != v_rt) continue;
	
	for(cnct=rt->ilist;cnct;cnct=cnct->next) {

	    if(cnct->state == INTF_DOWN || net != cnct->net) continue;
	
	    MALLOC(ls_rtp,LS_RT_LIST);

	    ls_rtp->type = (u_char)RTIF_TYPE_VIRTUAL;
	    ls_rtp->id = nbr_id;
	    ls_rtp->data = cnct->ifaddr;
	    ls_rtp->tos_num = (u_char)0;
	    ls_rtp->tos0_metric = (short)get_rt_cost(nbr_id);
	    link++;

	    if(*list == NULL) {
		*list = ls_rtp;
		tmp = ls_rtp;
	    }
	    else {
		tmp->next = ls_rtp;
		tmp = ls_rtp;
	    }
	}
    }
    
    return link;
}


/*

  rt_path_check

*/
int rt_path_check(rt_id,my_area)
u_long rt_id;
struct AREA_TBL *my_area;
{
    struct INDEX *index,*rindex;
    struct RT_TBL *rt,*abr;
    struct NET_TBL *net;
    struct AS_TBL *as;
    struct AREA_TBL *area;

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

#ifdef DEBUG
    time_count();
    printf("rt_path_check(%s , ", inetaddr_to_char(rt_id));
    printf("%s) at %d \n",inetaddr_to_char(my_area->number),get_currnt_time());
#endif
    as = my_area->as_idx;
    if(as->area_num == 1) {
	get_min_path(rt_id);
	for(index=my_area->nlist;index;index=index->next) {
	    net = (struct NET_TBL *)index->dst;
	    for(rindex=net->cnct_rt;rindex;rindex=rindex->next) {
		rt = (struct RT_TBL *)rindex->dst;
		if(rt->id == rt_id) continue;
		if(get_rt_cost(rt->id) != -1) return 1;
	    }
	}

	return 0;
    }
    else {
	get_min_path(rt_id);
	for(index=my_area->abrlist;index;index=index->next) {
	    abr = (struct RT_TBL *)index->dst;
	/*    if(abr->id == rt_id) continue;*/
	    if(get_rt_cost(abr->id) != -1) return 1;
	}

	return 0;
    }

}
	
/*

  get_rt_link

*/
struct LS_RT_HDR_LIST *get_rt_link(list,rt)
struct LS_RT_HDR_LIST *list;
struct RT_TBL *rt;
{
    struct LS_RT_HDR_LIST *hdr_list;

    if(!rt) {
	log_trace(stderr,"invalid argment <list = %x,rt = %x> in get_rt_link\n",list,rt);
	return NULL;
    }

    for(hdr_list=list;hdr_list;hdr_list=hdr_list->next) {
	if(hdr_list->hdr.ls_id == rt->id)
	  return hdr_list;
    }

    return NULL;
}

/*

  make_net_link

*/
struct LS_NET_HDR_LIST *make_net_link(area)
struct AREA_TBL *area;
{
    struct NET_TBL *net;
    struct RT_INTF *cnct,*cnet;
    struct INDEX *index,*rindex;
    struct RT_TBL *rt;
    struct LS_NET_HDR_LIST *net_hdr,*net_hdr_list,*net_hdr_tmp;
    struct LS_NET_LIST *net_link,*tmp;
    int rt_num;
    
    if(!area) {
	log_trace(stderr,"invalid argment <area = %x> in make_net_link\n",area);
	return NULL;
    }

#ifdef DEBUG
    printf("start make_net_link at %d \n", get_currnt_time());
#endif
    net_hdr_list = NULL;
    for(index=area->nlist;index;index=index->next) {
	net = (struct NET_TBL *)index->dst;

#ifdef DEBUG /* 1996.12.18 */
	printf("Network %s (%d)\n", 
	       inetaddr_to_char(net->addr),net->cnct_num);
#endif
	if(net->cnct_num == 1) continue;
	if(!get_dr_addr(net->addr)) continue;  /* if Non DR 1996.12.18 */

	MALLOC(net_hdr,LS_NET_HDR_LIST);
	
	net_hdr->hdr.ls_type = LS_TYPE_NET;
	net_hdr->hdr.ls_id = get_dr_addr(net->addr);
	net_hdr->hdr.adv_rt = net->dr->id;
	if(net_hdr->hdr.ls_seq) {
	    net_hdr->hdr.ls_seq += 1;
	}
	else {
	    net_hdr->hdr.ls_seq = ls_seq_num;
	}
	
	net_hdr->net_mask = net->mask;

	rt_num = 0;
	for(rindex=net->cnct_rt;rindex;rindex=rindex->next) {
	    rt = (struct RT_TBL *)rindex->dst;

	    IF_STATE_DOWN(rt,net);

	    if(!rt_path_check(rt->id,area))
	      continue;
	    MALLOC(net_link,LS_NET_LIST);

	    net_link->cnct_rt = rt->id;
	    if(net_hdr->net_link == NULL) {
		net_hdr->net_link = net_link;
		tmp = net_link;
	    }
	    else {
		tmp->next = net_link;
		tmp = net_link;
	    }
	    rt_num++;
	}

	if(rt_num < 2) continue;

	net_hdr->hdr.length = LS_NET_HDR_SIZE + rt_num * LS_NET_SIZE;
	if(net_hdr_list == NULL) {
	    net_hdr_list = net_hdr;
	    net_hdr_tmp = net_hdr;
	}
	else {
	    net_hdr_tmp->next = net_hdr;
	    net_hdr_tmp = net_hdr;
	}
    }

#ifdef DEBUG
    printf("end make_net_link at %d \n", get_currnt_time());
#endif

    return net_hdr_list;
}

/*

  make_default_sum_link

*/
struct LS_SUM_HDR_LIST *make_default_sum_link(my_area,id,cost)
struct AREA_TBL *my_area;
u_long id;
int cost;
{
    struct LS_SUM_HDR_LIST *sum_hdr;
    struct LS_SUM_LIST *sum_link;

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

    MALLOC(sum_hdr,LS_SUM_HDR_LIST);

    sum_hdr->hdr.ls_type = LS_TYPE_SUM_NET;
    sum_hdr->hdr.ls_id = 0;
    sum_hdr->hdr.adv_rt = id;
    sum_hdr->hdr.ls_seq = ls_seq_num;
    sum_hdr->net_mask = 0;

    MALLOC(sum_link,LS_SUM_LIST);

    sum_link->tos_metric = cost;
    sum_hdr->sum_link = sum_link;
    sum_hdr->hdr.length = LS_SUM_HDR_SIZE + LS_SUM_SIZE;

    return sum_hdr;
}

/*

  make_sum_net_link

*/
struct LS_SUM_HDR_LIST *make_sum_net_link(my_area,id)
struct AREA_TBL *my_area;
u_long id;
{
    struct AREA_TBL *area;
    struct AS_TBL *as;
    struct NET_TBL *net;
    struct INDEX *index,*nindex,*aindex,*myaindex;
    struct LS_SUM_HDR_LIST *sum_hdr,*sum_hdr_list,*sum_hdr_tmp;
    struct LS_SUM_LIST *sum_link,*tmp;
    struct RT_TBL *abr;
    u_long next_hop;
    u_long adv_rt;
    u_long cost;
    struct INDEX *abr_list;

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

#ifdef DEBUG
    printf("start make_sum_net_link at %d \n", get_currnt_time());
#endif

    as = my_area->as_idx;
    sum_hdr_list = NULL;
    for(area=as->alist;area;area=area->next) {

	if(area == my_area) continue;

	for(myaindex=my_area->abrlist;myaindex;myaindex=myaindex->next) {
	    abr = (struct RT_TBL *)myaindex->dst;

#ifdef DEBUG
    printf("get_min_path(%s) at %d\n", inetaddr_to_char(abr->id),get_currnt_time());
#endif
		get_min_path(abr->id);
	    for(index=area->nlist;index;index=index->next) {
		net = (struct NET_TBL *)index->dst;

		if(path_net_area(my_area,net) != abr->id)
		   continue;

		MALLOC(sum_hdr,LS_SUM_HDR_LIST);

       	/*	get_min_path(adv_rt);*/
		cost = (u_long)get_net_cost(id,net);
	    
		sum_hdr->hdr.ls_type = LS_TYPE_SUM_NET;
		sum_hdr->hdr.ls_id = net->addr;
		sum_hdr->hdr.adv_rt = abr->id;
		sum_hdr->hdr.ls_seq = ls_seq_num;

		sum_hdr->net_mask = net->mask;

		MALLOC(sum_link,LS_SUM_LIST);

		sum_link->tos_metric = cost;

		sum_hdr->hdr.length = LS_SUM_HDR_SIZE + LS_SUM_SIZE;
		if(sum_hdr->sum_link == NULL) {
		    sum_hdr->sum_link = sum_link;
		    tmp = sum_link;
		}
		else {
		    tmp->next = sum_link;
		    tmp = sum_link;
		}

		if(sum_hdr_list == NULL) {
		    sum_hdr_list = sum_hdr;
		    sum_hdr_tmp = sum_hdr;
		}
		else {
		    sum_hdr_tmp->next = sum_hdr;
		    sum_hdr_tmp = sum_hdr;
		}
	    }
	}
    }

#ifdef DEBUG
    printf("end make_sum_net_link at %d \n", get_currnt_time());
#endif

    return sum_hdr_list;
}


/*

  make_sum_asbr_link

*/
struct LS_SUM_HDR_LIST *make_sum_asbr_link(my_area,id)
struct AREA_TBL *my_area;
u_long id;
{
    struct AREA_TBL *area;
    struct AS_TBL *as;
    struct NET_TBL *net;
    struct INDEX *index,*nindex,*aindex;
    struct LS_SUM_HDR_LIST *sum_hdr,*sum_hdr_list,*sum_hdr_tmp;
    struct LS_SUM_LIST *sum_link,*tmp;
    struct RT_TBL *asbr,*abr;
    struct RT_INTF *cnet;
    u_long next_hop;
    u_long cost;

    if(!my_area || !id) {
	log_trace(stderr,"invalid argment <my_area = %x, id = %d> in make_sum_asbr_link\n",my_area,id);
	return 0;
    }
#ifdef DEBUG
    printf("start make_sum_asbr_link at %d \n", get_currnt_time());
#endif

    as = my_area->as_idx;
    sum_hdr_list = NULL;
    for(index=as->brlist;index;index=index->next) {
	asbr = (struct RT_TBL *)index->dst;

	if(rt_area_search(asbr->id,my_area->number))
	   continue;

	for(aindex=my_area->abrlist;aindex;aindex=aindex->next) {
	    abr = (struct RT_TBL *)aindex->dst;

	    if(abr != asbr) {
		get_min_path(abr->id);

		/* modify 1996.6.27 for unreachable check*/
		if(path_rt_cost(asbr->id, abr->id) == -1) {
		  /*    log_trace(stderr, "\n asbr unreachable \n");*/
		    continue;
		}
		/* */
		
		if(path_rt_area(my_area,asbr) != abr->id)
		    continue;
		cost = (u_long)get_rt_cost(asbr->id);
	    }
	    else {
		for(nindex=my_area->nlist;nindex;nindex=nindex->next) {
		    net=(struct NET_TBL *)nindex->dst;
		    GET_LINK_NET(asbr,cnet,net);
		    /* modify 1996.6.27 for unreachable check */
		    if(cnet->state == INTF_DOWN) continue;
		    /* */
		    cost = cnet->cost;
		}
	    }

	    MALLOC(sum_hdr,LS_SUM_HDR_LIST);

	    sum_hdr->hdr.ls_type = LS_TYPE_SUM_ASBR;
	    sum_hdr->hdr.ls_id = asbr->id;
	    sum_hdr->hdr.adv_rt = abr->id;
	    sum_hdr->hdr.ls_seq = ls_seq_num;
	    
	    sum_hdr->net_mask = 0;

	    MALLOC(sum_link,LS_SUM_LIST);

	    sum_link->tos_metric = cost;

	    sum_hdr->hdr.length = LS_SUM_HDR_SIZE + LS_SUM_SIZE;	    
	    if(sum_hdr->sum_link == NULL) {
		sum_hdr->sum_link = sum_link;
		tmp = sum_link;
	    }
	    else {
		tmp->next = sum_link;
		tmp = sum_link;
	    }

    
	    if(sum_hdr_list == NULL) {
		sum_hdr_list = sum_hdr;
		sum_hdr_tmp = sum_hdr;
	    }
	    else {
		sum_hdr_tmp->next = sum_hdr;
		sum_hdr_tmp = sum_hdr;
	    }
	}
    }

#ifdef DEBUG
    printf("end make_sum_asbr_link at %d \n", get_currnt_time());
#endif

    return sum_hdr_list;
}

/*

  make_ase_link

*/
struct LS_ASE_HDR_LIST *make_ase_link(my_area)
struct AREA_TBL *my_area;
{
    struct RT_TBL *asbr;
    struct AS_TBL *my_as,*ext_as;
    struct INDEX *index,*nindex;
    struct LINK_TBL *link;
    struct NET_TBL *net;
    struct AREA_TBL *area;
    struct LS_ASE_HDR_LIST *ase_hdr_list,*ase_hdr;

    if(!my_area) {
	log_trace(stderr,"invalid argment <my_area = %x> in make_ase_link\n",my_area);
	return 0;
    }
#ifdef DEBUG
    printf("start make_ase_link at %d \n", get_currnt_time());
#endif

    my_as = my_area->as_idx;
    ase_hdr_list = NULL;
    for(index=my_as->brlist;index;index=index->next) {
	asbr = (struct RT_TBL *)index->dst;
	for(link=get_link_list(LIST_HEAD,LIST_HEAD);link;link=link->next) {
	    if(asbr != link->org) continue;

	    if((ext_as = get_router_as(link->cnct)) == my_as) continue;

	    /* modify 1996.6.27 for unreachable check */
	    if(get_link_cost(link->org->id, link->cnct->id) == -1) continue;
	    /* */

	    for(area=ext_as->alist;area;area=area->next) {
		for(nindex=area->nlist;nindex;nindex=nindex->next) {
		    net = (struct NET_TBL *)nindex->dst;
		    ase_hdr = make_ase_hdr(ext_as->number,net,asbr->id);
		    add_ase_hdr_list(&ase_hdr_list,ase_hdr);
		}
	    }

	    for(nindex=ext_as->nlist;nindex;nindex=nindex->next) {
		net = (struct NET_TBL *)nindex->dst;
		ase_hdr = make_ase_hdr(ext_as->number,net,asbr->id);
		add_ase_hdr_list(&ase_hdr_list,ase_hdr);
	    }
	}
    }
#ifdef DEBUG
    printf("end make_ase_link at %d \n", get_currnt_time());
#endif

    return ase_hdr_list;
}

/*

  make_ase_hdr

*/
struct LS_ASE_HDR_LIST *make_ase_hdr(as_num,net,asbr_id)
u_long as_num;
struct NET_TBL *net;
u_long asbr_id;
{
    struct LS_ASE_HDR_LIST *ase_hdr;
    struct LS_ASE_LIST *ase_link;
    u_long next_hop;

    if(!net || !asbr_id) {
	log_trace(stderr,"invalid argment <net = %x, asbr_id = %d> in make_ase_hdr\n",net,asbr_id);
	return 0;
    }

    MALLOC(ase_hdr,LS_ASE_HDR_LIST);
    
    ase_hdr->hdr.ls_type = LS_TYPE_ASE;
    ase_hdr->hdr.ls_id = net->addr;
    ase_hdr->hdr.adv_rt = asbr_id;
    ase_hdr->hdr.ls_seq = ls_seq_num;
    
    ase_hdr->net_mask = net->mask;

    MALLOC(ase_link,LS_ASE_LIST);

    get_min_path(asbr_id);
    ase_link->tos_metric = (u_long)get_net_cost(asbr_id,net);
    ase_link->tos_metric |= ASE_E_bit;   /* default is Type 2 ASE */
    ase_link->forward_addr = 0;

    ase_link->ext_rt_tag = as_num;
    ase_link->ext_rt_tag |= OSPF_ASE_DEFAULT_TAG;  /* TAG is fixed */   

    ase_hdr->ase_link = ase_link;
    ase_hdr->hdr.length = LS_ASE_HDR_SIZE + LS_ASE_SIZE;
    
    return ase_hdr;
}

/*

  add_ase_hdr_list

*/
void add_ase_hdr_list(list,ase_hdr)
struct LS_ASE_HDR_LIST **list;
struct LS_ASE_HDR_LIST *ase_hdr;
{
    struct LS_ASE_HDR_LIST *hdr;
    
    if(*list == NULL) {
	*list = ase_hdr;
    }
    else {
	for(hdr=*list;hdr->next!=NULL;hdr=hdr->next);
	hdr->next = ase_hdr;
    }
}

/*

  get_lsdb_entry_num

*/
int get_lsdb_entry_num(lsdb)
struct LSDB_LIST *lsdb;
{
    int entry;
    struct LS_RT_HDR_LIST *rt;
    struct LS_NET_HDR_LIST *net;
    struct LS_SUM_HDR_LIST *sum_net;
    struct LS_SUM_HDR_LIST *sum_asbr;
    struct LS_ASE_HDR_LIST *ase;
    
    if(!lsdb) {
	log_trace(stderr,"invalid argment <lsdb = %x> in get_lsdb_entry_num\n",lsdb);
	return 0;
    }

    entry=0;
    for(rt=lsdb->rt;rt;rt=rt->next) entry++;
    for(net=lsdb->net;net;net=net->next) entry++;
    for(sum_net=lsdb->sum_net;sum_net;sum_net=sum_net->next) entry++;
    for(sum_asbr=lsdb->sum_asbr;sum_asbr;sum_asbr=sum_asbr->next) entry++;
    for(ase=lsdb->ase;ase;ase=ase->next) entry++;

    return entry;
}

/*

  search_lsdb

*/
char *search_lsdb(area_id,type,id,adv_rt)
u_long area_id;
u_char type;
u_long id;
u_long adv_rt;
{
    struct LSDB_LIST *lsdb;
    
    if(!id ||!adv_rt) {
	log_trace(stderr,"invalid argment <area_id = %x, id = %d, adv_rt = %d> in search_lsdb\n",area_id,id,adv_rt);
	return NULL;
    }

    for(lsdb=lsdb_list;lsdb;lsdb=lsdb->next) {
	if(((struct AREA_TBL *)lsdb->area)->number == area_id)
	    break;;
    }

    if(lsdb == NULL) return NULL;

    switch(type) {
    case LS_TYPE_RT : DB_SCAN(LS_RT_HDR_LIST,rt);
	break;
    case LS_TYPE_NET : DB_SCAN(LS_NET_HDR_LIST,net);
	break;
    case LS_TYPE_SUM_NET : DB_SCAN(LS_SUM_HDR_LIST,sum_net);
	break;
    case LS_TYPE_SUM_ASBR : DB_SCAN(LS_SUM_HDR_LIST,sum_asbr);
	break;
    case LS_TYPE_ASE : DB_SCAN(LS_ASE_HDR_LIST,ase);
	break;
    default : break;
    }

    return NULL;
}


/*

  make_lsdb_sum_list

*/
byte *make_lsdb_sum_list(my_id,rt_table,nbr_id)
u_long my_id;
char *rt_table;
u_long nbr_id;
{
    int num;
    struct LSDB_LIST *lsdb;
    struct LSDB_SUM_LIST *my_list,*nbr_list,*entry;
    time_t currnt_time;
    struct LSA_LIST *lsa_list;

    if(!rt_table || !nbr_id) {
	log_trace(stderr,"invalid argment <rt_table = %x, nbr_id = %d> in make_sum_net_link\n",rt_table,nbr_id);
	return ;
    }

    lsdb = (struct LSDB_LIST *)rt_table;
    MALLOC(lsa_list,LSA_LIST);

    if(lsdb->my_lsdb != NULL && lsdb->nbr_lsdb != NULL) {
	lsdb->next_sum = lsdb->my_lsdb;
	printf(" ---- already done !!\n");
	/*	return;*/
    }

    lsdb->my_lsdb = lsdb->nbr_lsdb = NULL;
    lsdb->my_entry_num = lsdb->nbr_entry_num = 0;

    lsa_list->lsdb = lsdb;
    lsa_list->my_lsdb = lsa_list->nbr_lsdb = NULL;
    lsa_list->my_entry_num = lsa_list->nbr_entry_num = 0;

    currnt_time = get_currnt_time() - make_lsdb_time;
    
    DB_ENTRY_LIST(LS_RT_HDR_LIST,rt);
    DB_ENTRY_LIST(LS_NET_HDR_LIST,net);
    DB_ENTRY_LIST(LS_SUM_HDR_LIST,sum_net);
    DB_ENTRY_LIST(LS_SUM_HDR_LIST,sum_asbr);
    DB_ENTRY_LIST(LS_ASE_HDR_LIST,ase);
    DB_ENTRY_LIST(LS_SUM_HDR_LIST,default_sum);

    lsdb->next_sum = lsdb->next_adv = lsdb->my_lsdb;

    lsa_list->my_lsdb = lsa_list->next_sum = lsdb->next_adv = lsdb->my_lsdb;
    lsa_list->my_entry_num = lsdb->my_entry_num;
    lsa_list->nbr_entry_num = lsdb->nbr_entry_num;

    return (byte *)lsa_list;
}
	       
/*

  free_lsdb_sum_list

*/
void free_lsdb_sum_list(lsa_list)
char *lsa_list;
{
    int num;
    struct LSDB_LIST *lsdb;
    struct LSDB_SUM_LIST *sum_list,*entry;
    time_t currnt_time;
    struct LSA_LIST *lsa;

    if(!lsa_list) {
	log_trace(stderr,"invalid argment <lsa_list = %x> in free_sum_list\n",lsa_list);
	return ;
    }

    lsa = (struct LSA_LIST *)lsa_list;
    for(sum_list=lsa->my_lsdb;sum_list;) {
       entry = sum_list->next;
       free((char *)sum_list);
       sum_list = entry;
    }
    for(sum_list=lsa->nbr_lsdb;sum_list;) {
       entry = sum_list->next;
       free((char *)sum_list);
       sum_list = entry;
    }

    free((char *)lsa);
}

/*

  get_lsdb_sum_list

*/
int get_lsdb_sum_list(my_id,rt_table,list,adv_rt)
u_long my_id;
char *rt_table;
struct LS_HDR *list;
u_long adv_rt;
{
    int num;
    int len,entry;
    struct LSDB_LIST *lsdb;
    struct LS_HDR *hdr,*ls_buf;
    struct LSDB_SUM_LIST *sum_list;
    u_short age;
    time_t currnt_time;
    struct LSA_LIST *lsa_list;
    
    if(!my_id || !rt_table || !list || !adv_rt) {
	log_trace(stderr,"invalid argment <my_id = %d, rt_table = %x, list = %x, adv_rt = %d> in get_lsdb_sum_list\n",my_id,rt_table,list,adv_rt);
	return 0;
    }

    /*    lsdb = (struct LSDB_LIST *)rt_table;
    entry = get_lsdb_entry_num(lsdb);*/
    lsa_list = (struct LSA_LIST *)rt_table;
    entry = lsa_list->my_entry_num;

    len = LS_HDR_SIZE * entry;
    
    hdr = list;

    currnt_time = get_currnt_time() - make_lsdb_time;
    num = len = 0;
    for(sum_list=lsa_list->next_sum;sum_list;lsa_list->next_sum=sum_list=sum_list->next) {
	
	hdr = sum_list->lsh;

	if((hdr->ls_type == LS_TYPE_RT || hdr->ls_type == LS_TYPE_NET)
	&& my_id != hdr->adv_rt && adv_rt_check(my_id,hdr,adv_rt))
	   continue;
	
	sum_list->lsh->ls_age = (u_short)(currnt_time - sum_list->age);
	list->ls_age = htons(sum_list->lsh->ls_age);
	list->ls_option = sum_list->lsh->ls_age;
	list->ls_type = sum_list->lsh->ls_type;
	list->ls_id = htonl(sum_list->lsh->ls_id);
	list->adv_rt = htonl(sum_list->lsh->adv_rt);
	list->ls_seq = htonl(sum_list->lsh->ls_seq);
	list->ls_chksum = htons(sum_list->lsh->ls_chksum);
	list->length = htons(sum_list->lsh->length);

	if(len + LS_HDR_SIZE > INTF_MTU) break;
	else {
	    len += LS_HDR_SIZE;
	    list++;
	    num++;
	}
    }

    return num;
}

/*

  get_lsdb_nbr_sum_list

*/
int get_lsdb_nbr_sum_list(my_id,rt_table,list,adv_rt)
u_long my_id;
char *rt_table;
struct LS_HDR *list;
u_long adv_rt;
{
    int num;
    int len,entry;
    struct LSDB_LIST *lsdb;
    struct LS_HDR *hdr;
    struct LSDB_SUM_LIST *sum_list;
    u_short age;
    time_t currnt_time;
    
    if(!my_id || !rt_table || !list || !adv_rt) {
	log_trace(stderr,"invalid argment <my_id = %d, rt_table = %x, list = %x, adv_rt = %d> in get_lsdb_sum_list\n",my_id,rt_table,list,adv_rt);
	return 0;
    }
    
    lsdb = (struct LSDB_LIST *)rt_table;
    entry = get_lsdb_entry_num(lsdb);
    len = LS_HDR_SIZE * entry;
    
    hdr = list;

    currnt_time = get_currnt_time() - make_lsdb_time;
    num = 0;
    for(sum_list=lsdb->nbr_lsdb;sum_list;sum_list=sum_list->next) {
	hdr = sum_list->lsh;
/*	if((hdr->ls_type == LS_TYPE_RT || hdr->ls_type == LS_TYPE_NET)
	&& my_id != hdr->adv_rt && adv_rt_check(my_id,hdr,adv_rt))
	   continue;
*/
	sum_list->lsh->ls_age = (u_short)(currnt_time - sum_list->age);
	bcopy(sum_list->lsh,list,LS_HDR_SIZE);
	list++;
	num++;
    }

    return num;
}

/*

  get_lsdb_sum_entry

*/
byte *get_lsdb_sum_entry(id, rt_table, entry)
u_long id;
byte *rt_table;
byte *entry;
{
    struct LSA_LIST *lsa;
    struct LSDB_SUM_LIST *sum_list,*list;

    if(!id || !rt_table) {
	log_trace(stderr,"invalid argument <id = %d, rt_table = %x>\n",id,rt_table);
	return NULL;
    }

    if(entry) {
	sum_list = ((struct LSDB_SUM_LIST *)entry)->next;
    }
    else {
	lsa = (struct LSA_LIST *)rt_table;
	sum_list = lsa->my_lsdb;
    }

    for(list=sum_list;list;list=list->next) {
	if(list->change == LSDB_CHANGE) break;
    }

    return (byte *)list;
}

/*

  search_lsdb_sum_list

*/
char *search_lsdb_sum_list(lsa_list,type,id,adv_rt)
byte *lsa_list;
u_char type;
u_long id;
u_long adv_rt;
{
    struct LSDB_SUM_LIST *lsdb_sum;
    struct LSA_LIST *lsa;
    
    if(!id ||!adv_rt) {
	log_trace(stderr,"invalid argment <id = %d, adv_rt = %d> in search_lsdb_sum_list\n",id,adv_rt);
	return NULL;
    }

    lsa = (struct LSA_LIST *)lsa_list;
    /*    for(lsdb=lsdb_list;lsdb;lsdb=lsdb->next) {
	if(((struct AREA_TBL *)lsdb->area)->number == area_id)
	    break;
    }
    
    if(lsdb == NULL) return NULL;
    */
    for(lsdb_sum = lsa->my_lsdb;lsdb_sum;lsdb_sum=lsdb_sum->next) {
	if(lsdb_sum->lsh->ls_type == type &&
	   lsdb_sum->lsh->ls_id == id &&
	   lsdb_sum->lsh->adv_rt == adv_rt) {
	    return (char *)lsdb_sum;
	}
    }

    return NULL;
}

/*

  search_lsdb_sum

*/
byte *search_lsdb_sum(area_id,my_id,lsdb_sum)
u_long area_id;
u_long my_id;
byte *lsdb_sum;
{
    struct LSDB_SUM_LIST *sum_list;
    byte *lsdb;
    struct LS_HDR *lsh;
    
    if(!lsdb_sum || !my_id) {
	log_trace(stderr,"invalid argment <lsdb_sum = %x, my_id = %d> in search_lsdb_sum\n",lsdb_sum,my_id); 
	return NULL;
    }
      
    sum_list = (struct LSDB_SUM_LIST *)lsdb_sum;
    lsh = sum_list->lsh;

    if((lsdb = search_lsdb(area_id,lsh->ls_type,lsh->ls_id,lsh->adv_rt)) == NULL) {
	return NULL;
    }
    else {
	return (byte *)lsdb;
    }
    

}
    
/*

  lsdb_sum_more

*/
int lsdb_sum_more(rt_table)
byte *rt_table;
{
    struct LSA_LIST *lsa;

    if(!rt_table) {
/*	log_trace(stderr,"invalid argment <rt_table = %x> in lsdb_sum_more\n",rt_table); */
	return 0;
    }
    
    lsa = (struct LSA_LIST *)rt_table;
    return (int)lsa->next_sum;
}

/*

  ls_hdr_check

*/
int ls_hdr_check(id,lsdb,lsh)
u_long id;
byte *lsdb;
struct LS_HDR *lsh;
{
    struct LSDB_SUM_LIST *sum_list;
    struct LS_HDR *hdr;

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

    for(sum_list=((struct LSDB_LIST *)lsdb)->my_lsdb;sum_list;sum_list=sum_list->next) {
	hdr = sum_list->lsh;
	if(lsh->ls_type == hdr->ls_type && ntohl(lsh->ls_id) == hdr->ls_id
	&& ntohl(lsh->adv_rt) == hdr->adv_rt
	&& ntohl(lsh->ls_seq) == hdr->ls_seq) {
	    if(sum_list->change == LSDB_CHANGE) {
		sum_list->change = LSDB_NOCHANGE;
	    }
	    return 1;
	}
	
    }

/*    if(lsh->ls_type != hdr->ls_type) printf("not match ls_type\n");
    if(ntohl(lsh->ls_id) != hdr->ls_id) {
	printf("not match ls_id\n");
	log_trace(stderr," %s\n",inetaddr_to_char(ntohl(lsh->ls_id)));
	log_trace(stderr," %s\n",inetaddr_to_char(hdr->ls_id));
    }
    if(ntohl(lsh->adv_rt) != hdr->adv_rt) printf("not match adv_rt\n");
    if(ntohl(lsh->ls_seq) != hdr->ls_seq) printf("not match ls_seq\n");
*/    
    ls_hdr_dump(stderr, lsh);
    return 0;
}

/*

  my_lsdb_entry_num

*/
int my_lsdb_entry_num(id,rt_table)
u_long id;
char *rt_table;
{
    struct LSDB_LIST *lsdb;

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

    lsdb = (struct LSDB_LIST *)rt_table;

    return lsdb->my_entry_num;
}

/*

  nbr_lsdb_entry_num

*/
int nbr_lsdb_entry_num(id,rt_table)
u_long id;
char *rt_table;
{
    struct LSDB_LIST *lsdb;

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

    lsdb = (struct LSDB_LIST *)rt_table;

    return lsdb->nbr_entry_num;
}

    
/*

  get_adv_lsdb

*/
int get_adv_lsdb(my_id,rt_table,adv_buf,nbr_id,trans_delay,area_type)
u_long my_id;
char *rt_table;
union ADV_LSDB **adv_buf;
u_long nbr_id;
time_t trans_delay;
int area_type;
{
    int adv_num;
    struct LSDB_LIST *lsdb;
    struct LSDB_SUM_LIST *lsdb_sum,*adv_lsdb;
    struct LS_HDR *h;
    char *buf;
    int len;
    
    if(!my_id || !rt_table || !adv_buf || !nbr_id) {
	log_trace(stderr,"invalid argment <my_id = %d, rt_table = %x, adv_buf = %x, nbr_id = %d> in get_adv_lsdb\n",my_id,rt_table,adv_buf,nbr_id);
	return 0;
    }

    lsdb = (struct LSDB_LIST *)rt_table;
    lsdb_sum = lsdb->my_lsdb;
    
    adv_num = 0;
    buf = (char *)*adv_buf;
    for(adv_lsdb=lsdb->next_adv;adv_lsdb;adv_lsdb=lsdb->next_adv=adv_lsdb->next) {
	h = adv_lsdb->lsh;
	len = (char *)*adv_buf - buf;
	if(len + h->length > INTF_MTU) break;
	switch(h->ls_type) {
	case LS_TYPE_RT :  adv_num += get_adv_rt_list(my_id,(struct LS_RT_HDR_LIST *)adv_lsdb->list,(char *)adv_buf,nbr_id,lsdb_sum,trans_delay,len);
	    break;
	case LS_TYPE_NET : adv_num += get_adv_net_list(my_id,(struct LS_NET_HDR_LIST *)adv_lsdb->list,(char *)adv_buf,nbr_id,lsdb_sum,trans_delay,len);
	    break;
	case LS_TYPE_SUM_NET : adv_num += get_adv_sum_list((struct LS_SUM_HDR_LIST *)adv_lsdb->list,(char *)adv_buf,nbr_id,lsdb_sum,trans_delay,len);
	    break;
	case LS_TYPE_SUM_ASBR : adv_num += get_adv_sum_list((struct LS_SUM_HDR_LIST *)adv_lsdb->list,(char *)adv_buf,nbr_id,lsdb_sum,trans_delay,len);
	    break;
	case LS_TYPE_ASE :     if(area_type) {
	adv_num += get_adv_ase_list((struct LS_ASE_HDR_LIST *)adv_lsdb->list,(char *)adv_buf,nbr_id,lsdb_sum,trans_delay,len);
    }
	    break;
	    default : break;
	}
    }
    
    if(!area_type) {
	if(LS_LEN(lsdb->default_sum) + (char *)adv_buf - buf > INTF_MTU) 
	  adv_num += get_adv_sum_list(lsdb->default_sum,(char *)adv_buf,nbr_id,lsdb_sum,trans_delay,len);
    }
	
    return adv_num;
}


/*

  get_lsdb_rt

*/
int get_lsdb_rt(rt_hdr,buff,diff_age,state)
struct LS_RT_HDR_LIST *rt_hdr;
char **buff;
u_short diff_age;
int state;
{
    struct LS_RT_LIST *rt;
    struct LS_RT *adv_rt_link;
    struct LS_HDR *lsh;
    struct LS_RT_HDR *tmp;
    short age;
    
    if(!rt_hdr || !buff) {
	log_trace(stderr,"invalid argment <rt_hdr = %x, buff = %x> in get_lsdb_rt\n",rt_hdr,buff);
	return 0;
    }

    tmp = (struct LS_RT_HDR *)*buff;
    lsh = &(tmp->hdr);

    LSHDR_COPY(lsh,rt_hdr);
    age = rt_hdr->hdr.ls_age + diff_age;
    lsh->ls_age = 0;
    
    tmp->bits = htons(rt_hdr->bits);
    tmp->link = htons(rt_hdr->link);

    adv_rt_link = &(tmp->rt_link);
    for(rt=rt_hdr->rt_link;rt;rt=rt->next) {
	if(age >= MAX_LS_AGE) {
	    rt->tos0_metric = 0xffff;
	}
	adv_rt_link->id = htonl(rt->id);
	adv_rt_link->data = htonl(rt->data);
	adv_rt_link->type = rt->type;
	adv_rt_link->tos_num = htons(rt->tos_num);
	adv_rt_link->tos0_metric = htons(rt->tos0_metric);
	adv_rt_link++;
    }
    encodecc(*buff,rt_hdr->hdr.length,17);
    
    if(age > MAX_LS_AGE)
    	rt_hdr->hdr.ls_age = MAX_LS_AGE;
    else
        rt_hdr->hdr.ls_age = age;

    lsh->ls_age = htons(rt_hdr->hdr.ls_age);

    return rt_hdr->hdr.length;
}

/*

  get_adv_rt_list

*/
int get_adv_rt_list(id,rt_list,buff,nbr,lsdb_sum,trans_delay,len)
u_long id;
struct LS_RT_HDR_LIST *rt_list;
char **buff;
u_long nbr;
struct LSDB_SUM_LIST *lsdb_sum;
time_t trans_delay;
int len;
{
    struct LS_RT_HDR_LIST *rt_hdr;
    int adv_num;
    struct LSDB_LIST *lsdb;
    struct LSDB_SUM_LIST *sum_list;
    time_t currnt_time;
    u_short diff_age;

    if(!id || !rt_list || !nbr || !lsdb_sum) {
	log_trace(stderr,"invalid argment <id = %d, rt_list = %x, nbr = %d, lsdb_sum = %x > in get_adv_rt_list\n",id,rt_list,nbr,lsdb_sum);
	return 0;
    }

    adv_num = 0;
    currnt_time = get_currnt_time() - make_lsdb_time;
/*    for(rt_hdr=rt_list;rt_hdr;rt_hdr=rt_hdr->next) {*/
    rt_hdr = rt_list;
	
/*	if(rt_hdr->hdr.adv_rt == nbr
	|| rt_hdr->hdr.adv_rt != id) return adv_num;
*/
    if(id != rt_hdr->hdr.adv_rt
    && adv_rt_check(id,&rt_hdr->hdr,nbr)) return adv_num;
       
	for(sum_list=lsdb_sum;sum_list;sum_list=sum_list->next) {
	    if(sum_list->state == LSDB_STATE_DELETE)
	      continue;
	    
	    if(sum_list->lsh == &rt_hdr->hdr) break;
	}

	if(sum_list->state == LSDB_STATE_DOWN) {
	    diff_age = MAX_LS_AGE;
	    rt_hdr->rt_link->tos0_metric = 0xffff;
	    sum_list->state = LSDB_STATE_DELETE;
	}
	else {
	    diff_age = currnt_time - sum_list->age + trans_delay;
	}

	if(len + rt_hdr->hdr.length > INTF_MTU) return adv_num;
	
	if(get_lsdb_rt(rt_hdr,buff,diff_age)) {
	    adv_num++;
	    *buff = (*buff + rt_hdr->hdr.length);
	}
/*    }*/

    return adv_num;
}

/*

  adv_rt_check

*/
int adv_rt_check(my_id,lsh,nbr_id)
u_long my_id;
struct LS_HDR *lsh;
u_long nbr_id;
{
    
    if(!my_id || !lsh || !nbr_id) {
	log_trace(stderr,"invalid argment <my_id = %d, lsh = %x, nbr_id = %d, nbr_id = %x > in adv_rt_check\n",my_id,lsh,nbr_id);
	return 0;
    }

    if(lsh->adv_rt == nbr_id)
      return 1;
    /*
    ls_hdr_dump(stderr,lsh);
    printf("adv_rt_check my_id=%s ", inetaddr_to_char(my_id));
printf(" nbr_id=%s", inetaddr_to_char(nbr_id));
*/
    get_min_path(my_id);
    if(path_rt_cost(lsh->adv_rt,nbr_id) == -1) {
      return 0;
    }
    else {
      return 1;
    }
}


/*

  get_lsdb_net

*/
int get_lsdb_net(net_hdr,buff,diff_age,state)
struct LS_NET_HDR_LIST *net_hdr;
char **buff;
u_short diff_age;
int state;
{
    struct LS_NET_LIST *net;
    struct LS_NET *net_link;
    struct LS_HDR *lsh;
    struct LS_NET_HDR *tmp;
    short age;
    
    if(!net_hdr || !buff) {
	log_trace(stderr,"invalid argment <net_hdr = %x, buff = %x> in get_lsdb_net\n",net_hdr,buff);
	return 0;
    }

    tmp = (struct LS_NET_HDR *)*buff;
    lsh = &(tmp->hdr);
    LSHDR_COPY(lsh,net_hdr);

    age = lsh->ls_age + diff_age;
    lsh->ls_age = 0;
    
    tmp->net_mask = htonl(net_hdr->net_mask);
    net_link = &(tmp->net_link);
    for(net=net_hdr->net_link;net;net=net->next) {
	net_link->cnct_rt = htonl(net->cnct_rt);
	net_link++;
    }
    
    encodecc(*buff,net_hdr->hdr.length,17);
    
    if(age > MAX_LS_AGE || state == LSDB_STATE_DOWN) {
      net_hdr->hdr.ls_age = MAX_LS_AGE;
    }
    else {
      net_hdr->hdr.ls_age = age;
    }
    lsh->ls_age = htonl(net_hdr->hdr.ls_age);

    return net_hdr->hdr.length;
}

/*

  get_adv_net_list

*/
int get_adv_net_list(id,net_list,buff,nbr,lsdb_sum,trans_delay,len)
u_long id;
struct LS_NET_HDR_LIST *net_list;
char **buff;
u_long nbr;
struct LSDB_SUM_LIST *lsdb_sum;
time_t trans_delay;
int len;
{
    struct LS_NET_HDR_LIST *net_hdr;
    int adv_num;
    struct LSDB_SUM_LIST *sum_list;
    time_t currnt_time;
    u_short diff_age;

    if(!id || !net_list || !nbr || !lsdb_sum) {
	log_trace(stderr,"invalid argment <id = %d, net_list = %x, nbr = %d, lsdb_sum = %x > in get_adv_net_list\n",id,net_list,nbr,lsdb_sum);
	return 0;
    }

    adv_num = 0;
    currnt_time = get_currnt_time() - make_lsdb_time;    
/*    for(net_hdr=net_list;net_hdr;net_hdr=net_hdr->next) {*/
    net_hdr = net_list;
	
	if(net_hdr->hdr.adv_rt == nbr
	|| net_hdr->hdr.adv_rt != id) return adv_num;

	for(sum_list=lsdb_sum;sum_list;sum_list=sum_list->next) {
	    if(sum_list->state == LSDB_STATE_DELETE)
	      continue;
	    
	    if(sum_list->lsh == &net_hdr->hdr) break;
	}

	if(sum_list->state == LSDB_STATE_DOWN) {
	    diff_age = MAX_LS_AGE;
	    sum_list->state = LSDB_STATE_DELETE;
	}
	else {
	    diff_age = currnt_time - sum_list->age + trans_delay;
	}

	if(len + net_hdr->hdr.length > INTF_MTU) return adv_num;
	
	get_lsdb_net(net_hdr,buff,diff_age);
	adv_num++;
	
	*buff = (*buff + net_hdr->hdr.length);
/*    }*/

    return adv_num;
}

/*

  get_lsdb_sum

*/
int get_lsdb_sum(sum_hdr,buff,diff_age,state)
struct LS_SUM_HDR_LIST *sum_hdr;
char **buff;
u_short diff_age;
int state;
{
    struct LS_SUM_LIST *sum;
    struct LS_SUM *sum_link;
    struct LS_HDR *lsh;
    struct LS_SUM_HDR *tmp;
    short age;
    
    if(!sum_hdr || !buff) {
	log_trace(stderr,"invalid argment <sum_hdr = %x, buff = %x > in get_lsdb_sum\n",sum_hdr,buff);
	return 0;
    }

    tmp = (struct LS_SUM_HDR *)*buff;
    lsh = &(tmp->hdr);
    LSHDR_COPY(lsh,sum_hdr);
    age = lsh->ls_age + diff_age;    
    lsh->ls_age = 0;

    tmp->net_mask = htonl(sum_hdr->net_mask);
    sum_link = &(tmp->sum_link);
    for(sum=sum_hdr->sum_link;sum;sum=sum->next) {
	if(age >= MAX_LS_AGE || state == LSDB_STATE_DOWN)
	  sum_link->tos_metric = htonl(MAX_LS_COST);
	else
	  sum_link->tos_metric = htonl(sum->tos_metric);
	sum_link++;
    }

    encodecc(*buff,sum_hdr->hdr.length,17);
    
    if(age > MAX_LS_AGE)
      sum_hdr->hdr.ls_age = MAX_LS_AGE;
    else
      sum_hdr->hdr.ls_age = age;

    lsh->ls_age = htons(sum_hdr->hdr.ls_age);

    return sum_hdr->hdr.length;
}

/*

  get_adv_sum_list

*/
int get_adv_sum_list(sum_list,buff,nbr,lsdb_sum,trans_delay,len)
struct LS_SUM_HDR_LIST *sum_list;
char **buff;
u_long nbr;
struct LSDB_SUM_LIST *lsdb_sum;
time_t trans_delay;
int len;
{
    struct LS_SUM_HDR_LIST *sum_hdr;
    int adv_num;
    struct LSDB_SUM_LIST *ls_sum_list;
    time_t currnt_time;
    u_short diff_age;

    if(!sum_list || !nbr || !lsdb_sum) {
	log_trace(stderr,"invalid argment <sum_list=%x, nbr = %d, lsdb_sum = %x > in get_adv_rt_list\n",sum_list,nbr,lsdb_sum);
	return 0;
    }

    adv_num = 0;
    currnt_time = get_currnt_time() - make_lsdb_time;    
    for(sum_hdr=sum_list;sum_hdr;sum_hdr=sum_hdr->next) {
	
	if(sum_hdr->hdr.adv_rt == nbr) continue;

	for(ls_sum_list=lsdb_sum;ls_sum_list;ls_sum_list=ls_sum_list->next) {
	    if(ls_sum_list->state == LSDB_STATE_DELETE)
	      continue;
	    
	    if(ls_sum_list->lsh == &sum_hdr->hdr) break;
	}
	
	if(ls_sum_list->state == LSDB_STATE_DOWN) {
	    diff_age = MAX_LS_AGE;
	    ls_sum_list->state = LSDB_STATE_DELETE;
	    sum_hdr->sum_link->tos_metric = MAX_LS_COST;
	}
	else {
	    diff_age = currnt_time - ls_sum_list->age + trans_delay;
	}

	if(len + sum_hdr->hdr.length > INTF_MTU) break;
	
	get_lsdb_sum(sum_hdr,buff,diff_age);
	adv_num++;
	*buff = (*buff + sum_hdr->hdr.length);
    }

    return adv_num;
}

/*

  get_lsdb_ase

*/
int get_lsdb_ase(ase_hdr,buff,diff_age,state)
struct LS_ASE_HDR_LIST *ase_hdr;
char **buff;
u_short diff_age;
int state;
{
    struct LS_ASE_LIST *ase;
    struct LS_ASE *ase_link;
    struct LS_HDR *lsh;
    struct LS_ASE_HDR *tmp;
    short age;

    if(!ase_hdr || !buff) {
	log_trace(stderr,"invalid argment <ase_hdr = %x, buf = %x > in get_lsdb_ase \n",ase_hdr,buff);
	return 0;
    }

    tmp = (struct LS_ASE_HDR *)*buff;
    lsh = &(tmp->hdr);
    LSHDR_COPY(lsh,ase_hdr);
    age = lsh->ls_age + diff_age;
    lsh->ls_age = 0;
    
    tmp->net_mask = htonl(ase_hdr->net_mask);
    ase_link = &(tmp->ase_link);
    for(ase=ase_hdr->ase_link;ase;ase=ase->next) {
	if(age >= MAX_LS_AGE || state == LSDB_STATE_DOWN)
	  ase_link->tos_metric = htonl(MAX_LS_COST);
	else
	  ase_link->tos_metric = htonl(ase->tos_metric);
	ase_link->forward_addr = htonl(ase->forward_addr);
	ase_link->ext_rt_tag = htonl(ase->ext_rt_tag);
	ase_link++;
    }

    encodecc(*buff,ase_hdr->hdr.length,17);
    
    if(age > MAX_LS_AGE)
      ase_hdr->hdr.ls_age = MAX_LS_AGE;
    else
      ase_hdr->hdr.ls_age = age;

    lsh->ls_age = htons(ase_hdr->hdr.ls_age);

    return ase_hdr->hdr.length;
}

/*

  get_adv_ase_list

*/
int get_adv_ase_list(ase_list,buff,nbr,lsdb_sum,trans_delay,len)
struct LS_ASE_HDR_LIST *ase_list;
char **buff;
u_long nbr;
struct LSDB_SUM_LIST *lsdb_sum;
time_t trans_delay;
int len;
{
    struct LS_ASE_HDR_LIST *ase_hdr;
    int adv_num;
    struct LSDB_SUM_LIST *sum_list;
    time_t currnt_time;
    u_short diff_age;

    if(!ase_list || !nbr || !lsdb_sum) {
	log_trace(stderr,"invalid argment <ase_list = %x, nbr = %d, lsdb_sum = %x > in get_adv_rt_list\n",ase_list,nbr,lsdb_sum);
	return 0;
    }

    adv_num = 0;
    currnt_time = get_currnt_time() - make_lsdb_time;    
    for(ase_hdr=ase_list;ase_hdr;ase_hdr=ase_hdr->next) {
	
	if(ase_hdr->hdr.adv_rt == nbr) continue;

	for(sum_list=lsdb_sum;sum_list;sum_list=sum_list->next) {
	    if(sum_list->state == LSDB_STATE_DELETE)
	      continue;
	    
	    if(sum_list->lsh == &ase_hdr->hdr) break;
	}
	
	if(sum_list->state == LSDB_STATE_DOWN) {
	    diff_age = MAX_LS_AGE;
	    sum_list->state = LSDB_STATE_DELETE;
	}
	else {
	    diff_age = currnt_time - sum_list->age + trans_delay;
	}

	if(len + ase_hdr->hdr.length > INTF_MTU) break;
	
	get_lsdb_ase(ase_hdr,buff,diff_age);
	adv_num++;
	*buff = (*buff + ase_hdr->hdr.length);
    }

    return adv_num;
}

/*

  get_lsdb_entry

*/
int get_lsdb_entry(type,lsdb_sum,buff,trans_delay)
u_char type;
struct LSDB_SUM_LIST *lsdb_sum;
char **buff;
time_t trans_delay;
{
    int len;
    
    if(!lsdb_sum || !buff) {
	log_trace(stderr,"invalid argment <lsdb = %x, buff = %x > in get_lsdb_entry\n",lsdb_sum,buff);
	return 0;
    }

    switch(lsdb_sum->lsh->ls_type) {
    case LS_TYPE_RT : len = get_lsdb_rt((struct LS_RT_HDR_LIST *)lsdb_sum->list,buff,trans_delay,lsdb_sum->state);
	break;
    case LS_TYPE_NET : len = get_lsdb_net((struct LS_NET_HDR_LIST *)lsdb_sum->list,buff,trans_delay,lsdb_sum->state);
	break;
    case LS_TYPE_SUM_NET : 
    case LS_TYPE_SUM_ASBR : len = get_lsdb_sum((struct LS_SUM_HDR_LIST *)lsdb_sum->list,buff,trans_delay,lsdb_sum->state);
	break;
    case LS_TYPE_ASE : len = get_lsdb_ase((struct LS_ASE_HDR_LIST *)lsdb_sum->list,buff,trans_delay,lsdb_sum->state);
	break;
    }

    if(lsdb_sum->change == LSDB_CHANGE) {
	lsdb_sum->change = LSDB_NOCHANGE;
    }
    return len;
}

/*

  lsdb_intra_unrachable

*/
int lsdb_intra_unreachable(sum_list,area)
struct LSDB_SUM_LIST *sum_list;
struct AREA_TBL *area;
{
    struct LS_NET_HDR_LIST *net_hdr;
    struct LS_NET_LIST *net_link;
    struct LS_RT_HDR_LIST *rt_hdr;
    struct LS_RT_LIST *rt_list,*next_list;
    struct INDEX *index;
    int cnct_rt;
    struct RT_TBL *rt;
    struct RT_INTF *rtif;
    struct NET_TBL *net;
    struct LSDB_SUM_LIST *sum;
    u_long net_addr;
    int link_num;
    int send_flag;

    /*    printf(" lsdb_intra_unreachable \n");*/
    send_flag = 0;
    for(sum=sum_list;sum;sum=sum->next) {
	if(sum->lsh->ls_type == LS_TYPE_NET) {
	    net_hdr = (struct LS_NET_HDR_LIST *)(sum->list);
	    net=get_net_list((sum->lsh->ls_id & net_hdr->net_mask));
	    if(!net) {
		log_trace(stderr," not exit %s on net_list\n");
		return ;
	    }
	    /*	    log_trace(stderr,"%s \n",inetaddr_to_char(net->addr));*/
    
	    if((cnct_rt = net->cnct_num) < 2)
	      return;
	    for(index=net->cnct_rt;index;index=index->next) {
		rt = (struct RT_TBL *)(index->dst);
		/*		log_trace(stderr," connect rt %s \n",inetaddr_to_char(rt->id));*/
		for(rtif=rt->ilist;rtif;rtif=rtif->next) {
		    if((rtif->ifaddr & net_hdr->net_mask) == net->addr
		    && rtif->state == INTF_DOWN) {
			cnct_rt--;
			/*			log_trace(stderr," down interface %s \n",inetaddr_to_char(rtif->ifaddr));*/
		    }
		}
	    }
    
	    if(cnct_rt < 2) {
		sum->state = LSDB_STATE_DOWN;
		sum->lsh->ls_seq = ls_seq_num;
		sum->change = LSDB_CHANGE;
		if(!send_flag) send_flag = 1;
		/*		log_trace(stderr, "LS_NET %s DOWN\n", inetaddr_to_char(sum->lsh->ls_id));*/
	    }
	}
	else if(sum->lsh->ls_type == LS_TYPE_RT) {
	    rt_hdr = (struct LS_RT_HDR_LIST *)(sum->list);
	    rt = get_rt_list(sum->lsh->adv_rt);
	    /*	    log_trace(stderr,"%s \n",inetaddr_to_char(rt->id));*/
	    for(rt_list=rt_hdr->rt_link;rt_list;) {
		next_list = rt_list->next;
		free((char *)rt_list);
		rt_list = next_list;
	    }
	    rt_hdr->rt_link = NULL;
	    link_num = rt_link(&(rt_hdr->rt_link),rt,area);
	    if(rt_hdr->link != link_num) {
	      /*		log_trace(stderr," area %s \n",inetaddr_to_char(area->number));
		log_trace(stderr," LS RTR %s \n",inetaddr_to_char(rt->id));
		*/		rt_hdr->link = link_num;
		rt_hdr->hdr.length = LS_RT_HDR_SIZE + link_num * LS_RT_SIZE;
		sum->change = LSDB_CHANGE;
		sum->state = LSDB_STATE_DOWN;
		sum->lsh->ls_seq = ls_seq_num;
		if(!send_flag) send_flag = 1;
	    }
	}
    }

    return send_flag;
}

/*

  lsdb_state_unreachable

*/
int lsdb_state_unreachable(sum_list, as_num, ls_type)
struct LSDB_SUM_LIST *sum_list;
int as_num;
u_char ls_type;
{
    struct LSDB_SUM_LIST *list;
    struct INDEX *index;
    struct AS_TBL *as;
    struct NET_TBL *net;
    int send_flag;

    send_flag=0;
    as = get_as_list(as_num);
    for(index=as->nlist;index;index=index->next) {
	net = (struct NET_TBL *)index->dst;

	for(list=sum_list;list;list=list->next) {
	    if(list->lsh->ls_type == ls_type 
	    && list->lsh->ls_id == net->addr) {
                    list->state = LSDB_STATE_DOWN;
		    list->lsh->ls_seq = ls_seq_num;
		    list->change = LSDB_CHANGE;
		    if(!send_flag) send_flag=1;
		}
	}
    }

    return send_flag;
}

/*

  lsdb_ase_unreachable

*/
int lsdb_ase_unreachable(rt_id,sum_list, as_num)
u_long rt_id;
struct LSDB_SUM_LIST *sum_list;
int as_num;
{
    struct LSDB_SUM_LIST *list;
    struct INDEX *index;
    struct AS_TBL *as;
    struct NET_TBL *net;
    int send_flag;
    /*
    printf("lsdb_ase_unrechable:rt_id = %s, as_num = %d\n",
	   inetaddr_to_char(rt_id),as_num);*/
    send_flag=0;
    as = get_as_list(as_num);
    for(index=as->nlist;index;index=index->next) {
	net = (struct NET_TBL *)index->dst;
	/*	printf(" Net %s cost %d\n", 
	       inetaddr_to_char(net->addr),get_net_cost(rt_id,net));*/
	if(get_net_cost(rt_id,net) != -1)
	   continue;
	
	for(list=sum_list;list;list=list->next) {
	    if(list->lsh->ls_type == LS_TYPE_ASE
	    && list->lsh->ls_id == net->addr) {
                    list->state = LSDB_STATE_DOWN;
		    list->lsh->ls_seq = ls_seq_num;
		    list->change = LSDB_CHANGE;
		    if(!send_flag) send_flag=1;
		}
	}
    }

    return send_flag;
}


/*

  lsdb_unreachable

*/
int lsdb_unreachable(id,lsa,area_num)
u_long id;
byte *lsa;
u_long area_num;
{
    u_long as_num;
    u_long my_as_br;
    struct AS_TBL *as;
    struct AREA_TBL *area,*lsdb_area;
    struct INDEX *index;
    struct NET_TBL *net;
    struct LSDB_SUM_LIST *sum_list;
    struct RT_TBL *rt;
    struct LSDB_SUM_LIST *my_lsdb;
    u_long next_hop;
    struct LSDB_LIST *lsdb_list;
    int send_flag;

    if(!id || !lsa) {
	log_trace(stderr,"invalid argment <id = %d, lsdb = %x> in lsdb_unreachable\n",id,lsa);
	return ;
    }
    /*    log_trace(stderr," lsdb_unrechable %s, lsdb %x \n",
	      inetaddr_to_char(id),lsdb);*/
    as_num = get_as_num(id);
    as = get_as_list(as_num);

    if(!as)
      return ;
    
    for(area=as->alist;area;area=area->next) {
	if(area->number == area_num) break;
    }

    need_remake_lsdb=1;
    my_lsdb = ((struct LSA_LIST *)lsa)->my_lsdb;
    lsdb_list = ((struct LSA_LIST *)lsa)->lsdb;
    send_flag = 0;

    if(!area)
      goto ase_unreachable;
    
    get_min_path(id);

    if(area == (struct AREA_TBL *)(lsdb_list->area)) {
	send_flag = lsdb_intra_unreachable(my_lsdb,area) ;
    }

    lsdb_area = (struct AREA_TBL *)(lsdb_list->area);
    /*
    log_trace(stderr," area %s ",inetaddr_to_char(area_num));
    log_trace(stderr," (%s, %x->%x) \n",
	      inetaddr_to_char(lsdb_area->number),lsdb,my_lsdb);*/
    for(index=area->nlist;index;index=index->next) {
	net = (struct NET_TBL *)index->dst;
/*
	log_trace(stderr,"net %s is reachable ?\n",inetaddr_to_char(net->addr));
*/	if(next_hop=path_net_area(area,net))  {
/*	    log_trace(stderr,"next hop is %s \n",inetaddr_to_char(next_hop));
	    log_trace(stderr,"to %s cost %d \n",
		      inetaddr_to_char(id),path_rt_cost(next_hop,id));
*/	    if(path_rt_cost(next_hop,id) != -1)
	      continue;	   /* net is reachable */
	}
/*	log_trace(stderr,"net %s is unreachable \n",inetaddr_to_char(net->addr)); 
 */	for(sum_list=my_lsdb;sum_list;sum_list=sum_list->next) {
	    if(sum_list->lsh->ls_type != LS_TYPE_SUM_NET) {
	        continue;
	    }

	    if(sum_list->lsh->ls_id == net->addr) {
/*		log_trace(stderr,"LSDB state down\n");*/
		sum_list->state = LSDB_STATE_DOWN;
		sum_list->lsh->ls_seq = ls_seq_num ;
		sum_list->change = LSDB_CHANGE;
		if(!send_flag) send_flag=1;
	    }

	}
    }

ase_unreachable:

    get_min_path(id);
    my_as_br = get_asbr_id(as_num);
    for(as=get_as_list(LIST_HEAD);as;as=as->next) {
	if(as->number == as_num) continue;
	for(index=as->brlist;index;index=index->next) {
	    rt = (struct RT_TBL *)index->dst;
	    if(path_rt_cost(rt->id,id) != -1) {
		send_flag |= lsdb_ase_unreachable(rt->id,my_lsdb,as->number);
		continue;
	    }
/*	    log_trace(stderr,"AS %d (ASBR : %s)is unreachable \n",
		      as->number,inetaddr_to_char(rt->id));
*/
	    send_flag |= lsdb_state_unreachable(my_lsdb,as->number,LS_TYPE_ASE);
	
	}
    }

    ls_seq_num++;
    return send_flag;
}

/*

  lsdb_change_ack

*/
int lsdb_change_ack(lsdb, ack)
byte *lsdb;
struct LS_HDR *ack;
{
    struct LSDB_SUM_LIST *sum_list;
    int bad;

    bad = 1;
    for(sum_list=((struct LSDB_LIST *)lsdb)->my_lsdb;sum_list;sum_list=sum_list->next) {
	if(sum_list->state == LSDB_STATE_DOWN) {
	    if(LS_COMPARE(ack, sum_list->lsh)) {
		sum_list->state = LSDB_STATE_DELETE;
		sum_list->change = LSDB_NOCHANGE;
		return 1;
	    }
	    else if(sum_list->change == LSDB_NOCHANGE) {
		sum_list->change = LSDB_CHANGE;
	    }
	    bad = 0;
	}
    }

    return bad;
}
       
		 
/*

  lsdb_aging

*/
void lsdb_aging(id,lsdb)
u_long id;
byte *lsdb;
{
    u_long as_num;
    struct AS_TBL *as;
    struct AREA_TBL *area;
    struct INDEX *index;
    struct NET_TBL *net;
    struct LSDB_SUM_LIST *sum_list;
    struct LS_HDR *lsh;
    
    if(!id || !lsdb) {
	log_trace(stderr,"invalid argment <id = %d, lsdb = %x> in lsdb_aging\n",id,lsdb);
	return ;
    }

    for(sum_list=((struct LSDB_LIST *)lsdb)->my_lsdb;sum_list;sum_list=sum_list->next) {
	sum_list->state = LSDB_STATE_DOWN;
	sum_list->lsh->ls_seq++;
    }

}

/*

  lsdb_flooding

*/
void lsdb_flooding(id,lsa)
u_long id;
byte *lsa;
{
    u_long as_num;
    struct AS_TBL *as;
    struct AREA_TBL *area;
    struct INDEX *index;
    struct NET_TBL *net;
    struct LSDB_SUM_LIST *sum_list;
    struct LS_HDR *lsh;
    
    if(!id || !lsa) {
	log_trace(stderr,"invalid argment <id = %d, lsa = %x> in lsdb_flooding\n",id,lsa);
	return ;
    }

    for(sum_list=((struct LSA_LIST *)lsa)->my_lsdb;sum_list;sum_list=sum_list->next) {
	if(sum_list->state == LSDB_STATE_ACTIVE) {
	    sum_list->lsh->ls_seq = ls_seq_num;
	    sum_list->change = LSDB_CHANGE;
	}
    }

    ls_seq_num++;
}


/*

  lsdb_list_dump

*/
void lsdb_list_dump()
{
    struct LSDB_LIST *lsdb;
    struct AREA_TBL *area;
    struct LSDB_SUM_LIST *sum;
    
    for(lsdb=lsdb_list;lsdb;lsdb=lsdb->next) {
	area = (struct AREA_TBL *)lsdb->area;
	printf("  < AREA %s >\n",inetaddr_to_char(area->number));
	rt_link_dump(stderr,lsdb->rt);
	net_link_dump(stderr,lsdb->net);
	sum_net_link_dump(stderr,lsdb->sum_net);
	sum_asbr_link_dump(stderr,lsdb->sum_asbr);
	ase_link_dump(stderr,lsdb->ase);
    }
}

void LS_rt_dump()
{
    struct LSDB_LIST *lsdb;
    struct AREA_TBL *area;
    
    for(lsdb=lsdb_list;lsdb;lsdb=lsdb->next) {
	area = (struct AREA_TBL *)lsdb->area;
	printf("AREA %s\n",inetaddr_to_char(area->number));
	rt_link_dump(stderr,lsdb->rt);
    }
}

void LS_net_dump()
{
    struct LSDB_LIST *lsdb;
    struct AREA_TBL *area;
    
    for(lsdb=lsdb_list;lsdb;lsdb=lsdb->next) {
	area = (struct AREA_TBL *)lsdb->area;
	printf("AREA %s\n",inetaddr_to_char(area->number));
	net_link_dump(stderr,lsdb->net);
    }
}

void LS_sum_net_dump()
{
    struct LSDB_LIST *lsdb;
    struct AREA_TBL *area;
    
    for(lsdb=lsdb_list;lsdb;lsdb=lsdb->next) {
	area = (struct AREA_TBL *)lsdb->area;
	printf("AREA %s\n",inetaddr_to_char(area->number));
	sum_net_link_dump(stderr,lsdb->sum_net);
    }
}

void LS_sum_asbr_dump()
{
    struct LSDB_LIST *lsdb;
    struct AREA_TBL *area;
    
    for(lsdb=lsdb_list;lsdb;lsdb=lsdb->next) {
	area = (struct AREA_TBL *)lsdb->area;
	printf("AREA %s\n",inetaddr_to_char(area->number));
	sum_asbr_link_dump(stderr,lsdb->sum_asbr);
    }
}

void LS_ase_dump(lsdb_rt)
struct LS_RT_HDR_LIST *lsdb_rt;
{
    struct LSDB_LIST *lsdb;
    struct AREA_TBL *area;
    
    for(lsdb=lsdb_list;lsdb;lsdb=lsdb->next) {
	area = (struct AREA_TBL *)lsdb->area;
	printf("AREA %s\n",inetaddr_to_char(area->number));
	ase_link_dump(stderr,lsdb->ase);
    }
}

/*

  rt_link_dump

*/
void rt_link_dump(fp,lsdb_rt)
FILE *fp;
struct LS_RT_HDR_LIST *lsdb_rt;
{
    struct LS_RT_HDR_LIST *rt_hdr;
    struct LS_HDR lsh;

    if(fp == NULL) fp = stderr;
    
    for(rt_hdr = lsdb_rt;rt_hdr;rt_hdr=rt_hdr->next) {
	log_trace(fp,"\n");
	bcopy(&(rt_hdr->hdr),&lsh,sizeof(struct LS_HDR));
	lsh.ls_age = ntohs(lsh.ls_age);
	lsh.ls_id = ntohl(lsh.ls_id);
	lsh.adv_rt = ntohl(lsh.adv_rt);
	lsh.ls_seq = ntohl(lsh.ls_seq);
	lsh.ls_chksum = ntohs(lsh.ls_chksum);
	lsh.length = ntohs(lsh.length);
	ls_hdr_dump(fp,&lsh);
	if(rt_hdr->bits & BORDER_BIT)
	  log_trace(fp,"	Area Border Router \n");
	if(rt_hdr->bits & EXTERNAL_BIT)
	  log_trace(fp,"	AS Border Router\n");
	ls_link_dump(fp,rt_hdr->rt_link);
    }
}

/*

  rt_link_bin_dump

*/
void rt_link_bin_dump(fp,lsdb_rt)
FILE *fp;
struct LS_RT_HDR_LIST *lsdb_rt;
{
    struct LS_RT_HDR_LIST *rt_hdr;
    struct LS_RT_LIST *link;
    struct LS_RT *ls_rt;
    short part=LSA_DATA_END;
    
    if(fp == NULL) fp = stderr;
    
    for(rt_hdr = lsdb_rt;rt_hdr;rt_hdr=rt_hdr->next) {
	fwrite((char *)&(rt_hdr->hdr),sizeof(struct LS_HDR),1,fp);
	fwrite((char *)&rt_hdr->bits,sizeof(u_short),1,fp);
	fwrite((char *)&rt_hdr->link,sizeof(u_short),1,fp);
	for(link=rt_hdr->rt_link;link;link=link->next) {
	    ls_rt = (struct LS_RT *)&(link->id);
	    fwrite((char *)ls_rt,sizeof(struct LS_RT),1,fp);
	}
	fwrite((char *)&part,sizeof(short),1,fp);
    }
}

/*

  ls_link_dump

*/
void ls_link_dump(fp,rt_link)
FILE *fp;
struct LS_RT_LIST *rt_link;
{
    struct LS_RT_LIST *link;

    if(fp == NULL) fp = stderr;    

    for(link=rt_link;link;link=link->next) {
	/*ls_rt_dump((struct LS_RT *)link->id);*/
	log_trace(fp,"	link type : %s\n",link_type[(int)link->type]);
	log_trace(fp,"	link id   : %s\n",inetaddr_to_char(ntohl(link->id)));
	log_trace(fp,"	link data : %s\n",inetaddr_to_char(ntohl(link->data)));
	log_trace(fp,"	cost      : %d\n",link->tos0_metric);
	log_trace(fp,"\n");
    }
}

/*

  ls_rt_dump

*/
void ls_rt_dump(fp,rt_hdr)
FILE *fp;
struct LS_RT_HDR *rt_hdr;
{
    int ls_len,len;
    struct LS_RT *ls_rt;

    if(fp == NULL) fp = stderr;    
    
    ls_hdr_dump(fp,&rt_hdr->hdr);

    if(rt_hdr->bits & BORDER_BIT)
	  log_trace(fp,"	Area Border Router \n");
    if(rt_hdr->bits & EXTERNAL_BIT)
	  log_trace(fp,"	AS Border Router\n");

    ls_len=ntohs(rt_hdr->hdr.length) - LS_HDR_SIZE - sizeof(long);

    ls_rt = &rt_hdr->rt_link;
    for(len=0;len<ls_len;len+=LS_RT_SIZE) {
	log_trace(fp,"	link type : %s\n",link_type[(int)ls_rt->type]);
	log_trace(fp,"	link id   : %s\n",inetaddr_to_char(ls_rt->id));
	log_trace(fp,"	link data : %s\n",inetaddr_to_char(ls_rt->data));
	log_trace(fp,"	cost      : %d\n",ntohs(ls_rt->tos0_metric));
	ls_rt++;
    }    
}

/*

  net_link_dump

*/
void net_link_dump(fp,lsdb_net)
FILE *fp;
struct LS_NET_HDR_LIST *lsdb_net;
{
    struct LS_NET_HDR_LIST *net_hdr;
    struct LS_NET_LIST *link;
    struct LS_HDR lsh;

    if(fp == NULL) fp = stderr;    
    
    for(net_hdr = lsdb_net;net_hdr;net_hdr=net_hdr->next) {
	log_trace(fp,"\n");
	bcopy(&(net_hdr->hdr),&lsh,sizeof(struct LS_HDR));
	lsh.ls_age = ntohs(lsh.ls_age);
	lsh.ls_id = ntohl(lsh.ls_id);
	lsh.adv_rt = ntohl(lsh.adv_rt);
	lsh.ls_seq = ntohl(lsh.ls_seq);
	lsh.ls_chksum = ntohs(lsh.ls_chksum);
	lsh.length = ntohs(lsh.length);
	ls_hdr_dump(fp,&lsh);
	log_trace(fp,"	MASK   : %s\n",inetaddr_to_char(ntohl(net_hdr->net_mask)));
	for(link=net_hdr->net_link;link!=NULL;link=link->next) {
	    log_trace(fp,"	Router : %s\n",	inetaddr_to_char(ntohl(link->cnct_rt)));
	}
	log_trace(fp,"\n");
    }

}

/*

  net_link_bin_dump

*/
void net_link_bin_dump(fp,lsdb_net)
FILE *fp;
struct LS_NET_HDR_LIST *lsdb_net;
{
    struct LS_NET_HDR_LIST *net_hdr;
    struct LS_NET_LIST *link;
    struct LS_NET *ls_net;
    short part=LSA_DATA_END;
    
    if(fp == NULL) fp = stderr;
    
    for(net_hdr = lsdb_net;net_hdr;net_hdr=net_hdr->next) {
	fwrite((char *)&(net_hdr->hdr),sizeof(struct LS_HDR),1,fp);
	fwrite((char *)&net_hdr->net_mask,sizeof(u_long),1,fp);
	for(link=net_hdr->net_link;link;link=link->next) {
	    ls_net = (struct LS_NET *)&(link->cnct_rt);
	    fwrite((char *)ls_net,sizeof(u_long),1,fp);
	}
	fwrite((char *)&part,sizeof(short),1,fp);
    }
}

/*

  ls_net_dump

*/
void ls_net_dump(fp,net_hdr)
FILE *fp;
struct LS_NET_HDR *net_hdr;
{
    struct LS_NET *net_link;
    int ls_len,len;

    if(fp == NULL) fp = stderr;    

    ls_hdr_dump(fp,&net_hdr->hdr);

    log_trace(fp,"	net_mask  = %s\n",inetaddr_to_char(net_hdr->net_mask));
    ls_len = ntohs(net_hdr->hdr.length) - LS_HDR_SIZE - sizeof(long);
    net_link = &net_hdr->net_link;
    for(len=0;len<ls_len;len+=LS_NET_SIZE) {
	log_trace(fp,"	router =  %s\n",inetaddr_to_char(net_link->cnct_rt));
	net_link++;
    }
}


/*

  sum_net_link_dump

*/
void sum_net_link_dump(fp,lsdb_sum)
FILE *fp;
struct LS_SUM_HDR_LIST *lsdb_sum;
{
    struct LS_SUM_HDR_LIST *sum_hdr;
    struct LS_SUM_LIST *link;
    struct LS_HDR lsh;

    if(fp == NULL) fp = stderr;    

    for(sum_hdr=lsdb_sum;sum_hdr;sum_hdr=sum_hdr->next) {
	log_trace(fp,"\n");
	bcopy(&(sum_hdr->hdr),&lsh,sizeof(struct LS_HDR));
	lsh.ls_age = ntohs(lsh.ls_age);
	lsh.ls_id = ntohl(lsh.ls_id);
	lsh.adv_rt = ntohl(lsh.adv_rt);
	lsh.ls_seq = ntohl(lsh.ls_seq);
	lsh.ls_chksum = ntohs(lsh.ls_chksum);
	lsh.length = ntohs(lsh.length);
	ls_hdr_dump(fp,&lsh);
	log_trace(fp,"	MASK   : %s\n",inetaddr_to_char(ntohl(sum_hdr->net_mask)));
	for(link=sum_hdr->sum_link;link!=NULL;link=link->next) {
	    log_trace(fp,"	metric : %d\n",link->tos_metric);
	}
	log_trace(fp,"\n");
    }
}

/*

  sum_net_link_bin_dump

*/
void sum_net_link_bin_dump(fp,lsdb_sum)
FILE *fp;
struct LS_SUM_HDR_LIST *lsdb_sum;
{
    struct LS_SUM_HDR_LIST *sum_hdr;
    struct LS_SUM_LIST *link;
    struct LS_SUM *ls_sum;
    short part=LSA_DATA_END;
    
    if(fp == NULL) fp = stderr;
    
    for(sum_hdr = lsdb_sum;sum_hdr;sum_hdr=sum_hdr->next) {
	fwrite((char *)&(sum_hdr->hdr),sizeof(struct LS_HDR),1,fp);
	fwrite((char *)&sum_hdr->net_mask,sizeof(u_long),1,fp);
	for(link=sum_hdr->sum_link;link;link=link->next) {
	    ls_sum = (struct LS_SUM *)&(link->tos_metric);
	    fwrite((char *)ls_sum,sizeof(struct LS_SUM),1,fp);
	}
	fwrite((char *)&part,sizeof(short),1,fp);
    }
}

/*

  ls_sum_dump

*/
void ls_sum_dump(fp,sum_hdr)
FILE *fp;
struct LS_SUM_HDR *sum_hdr;
{
    struct LS_SUM *sum_link;
    int ls_len,len;

    if(fp == NULL) fp = stderr;    

    ls_hdr_dump(fp,&sum_hdr->hdr);

    log_trace(fp,"	net_mask  = %s\n",inetaddr_to_char(sum_hdr->net_mask));
    ls_len = ntohs(sum_hdr->hdr.length) - LS_HDR_SIZE - sizeof(long);
    sum_link = &sum_hdr->sum_link;
    for(len=0;len<ls_len;len+=LS_SUM_SIZE) {
	log_trace(fp,"	metric =  %d\n",ntohl(sum_link->tos_metric));
	sum_link++;
    }
}

/*

  sum_asbr_link_dump

*/
void sum_asbr_link_dump(fp,lsdb_sum)
FILE *fp;
struct LS_SUM_HDR_LIST *lsdb_sum;
{
    struct LS_SUM_HDR_LIST *sum_hdr;
    struct LS_SUM_LIST *link;
    struct LS_HDR lsh;

    if(fp == NULL) fp = stderr;    

    for(sum_hdr=lsdb_sum;sum_hdr;sum_hdr=sum_hdr->next) {
	log_trace(fp,"\n");
	bcopy(&(sum_hdr->hdr),&lsh,sizeof(struct LS_HDR));
	lsh.ls_age = ntohs(lsh.ls_age);
	lsh.ls_id = ntohl(lsh.ls_id);
	lsh.adv_rt = ntohl(lsh.adv_rt);
	lsh.ls_seq = ntohl(lsh.ls_seq);
	lsh.ls_chksum = ntohs(lsh.ls_chksum);
	lsh.length = ntohs(lsh.length);
	ls_hdr_dump(fp,&lsh);

	for(link=sum_hdr->sum_link;link!=NULL;link=link->next) {
	    log_trace(fp,"	metric : %d\n",link->tos_metric);
	}
	log_trace(fp,"\n");
    }
}

/*

  sum_asbr_link_bin_dump

*/
void sum_asbr_link_bin_dump(fp,lsdb_sum)
FILE *fp;
struct LS_SUM_HDR_LIST *lsdb_sum;
{
    struct LS_SUM_HDR_LIST *sum_hdr;
    struct LS_SUM_LIST *link;
    struct LS_SUM *ls_sum;
    short part=LSA_DATA_END;
    
    if(fp == NULL) fp = stderr;
    
    for(sum_hdr = lsdb_sum;sum_hdr;sum_hdr=sum_hdr->next) {
	fwrite((char *)&(sum_hdr->hdr),sizeof(struct LS_HDR),1,fp);
	fwrite((char *)&sum_hdr->net_mask,sizeof(u_long),1,fp);
	for(link=sum_hdr->sum_link;link;link=link->next) {
	    ls_sum = (struct LS_SUM *)&(link->tos_metric);
	    fwrite((char *)ls_sum,sizeof(struct LS_SUM),1,fp);
	}
	fwrite((char *)&part,sizeof(short),1,fp);
    }
}

/*

  ls_ase_dump

*/
void ls_ase_dump(fp,ase_hdr)
FILE *fp;
struct LS_ASE_HDR *ase_hdr;
{
    struct LS_ASE *ase_link;
    int ls_len,len;

    if(fp == NULL) fp = stderr;    

    ls_hdr_dump(fp,&ase_hdr->hdr);

    log_trace(fp,"	net_mask  = %s\n",inetaddr_to_char(ase_hdr->net_mask));
    ls_len = ntohs(ase_hdr->hdr.length) - LS_HDR_SIZE - sizeof(long);
    ase_link = &ase_hdr->ase_link;
    for(len=0;len<ls_len;len+=LS_ASE_SIZE) {
	if(ntohl(ase_link->tos_metric) & 0xffffffff)
	       log_trace(fp,"	Type 2 : metric %u\n",ntohl(ase_link->tos_metric) & 0x7fffffff);
	    else
	       log_trace(fp,"	Type 1 : metric %u\n",ntohl(ase_link->tos_metric));
	    log_trace(fp,"	Forward Addr : %s\n",inetaddr_to_char(ase_link->forward_addr));
	    log_trace(fp,"	Tag : %x\n",ntohl(ase_link->ext_rt_tag));
	ase_link++;
    }
}


/*

  ase_link_dump

*/
void ase_link_dump(fp,lsdb_ase)
FILE *fp;
struct LS_ASE_HDR_LIST *lsdb_ase;
{
    struct LS_ASE_HDR_LIST *ase_hdr;
    struct LS_ASE_LIST *link;
    struct LS_HDR lsh;

    if(fp == NULL) fp = stderr;    

    for(ase_hdr=lsdb_ase;ase_hdr;ase_hdr=ase_hdr->next) {
	log_trace(fp,"\n");
	bcopy(&(ase_hdr->hdr),&lsh,sizeof(struct LS_HDR));
	lsh.ls_age = ntohs(lsh.ls_age);
	lsh.ls_id = ntohl(lsh.ls_id);
	lsh.adv_rt = ntohl(lsh.adv_rt);
	lsh.ls_seq = ntohl(lsh.ls_seq);
	lsh.ls_chksum = ntohs(lsh.ls_chksum);
	lsh.length = ntohs(lsh.length);
	ls_hdr_dump(fp,&lsh);
	log_trace(fp,"	MASK   : %s\n",inetaddr_to_char(ntohl(ase_hdr->net_mask)));
	for(link=ase_hdr->ase_link;link!=NULL;link=link->next) {
	    if(link->tos_metric & ASE_E_bit)
	       log_trace(fp,"	Type 2 : metric %u\n",link->tos_metric & 0x7fffffff);
	    else
	       log_trace(fp,"	Type 1 : metric %u\n",link->tos_metric);
	    log_trace(fp,"	Forward Addr : %s\n",inetaddr_to_char(ntohl(link->forward_addr)));
	    log_trace(fp,"	Tag : %x\n",link->ext_rt_tag);
	}
    }
    log_trace(fp,"\n");
}

/*

  ase_link_bin_dump

*/
void ase_link_bin_dump(fp,lsdb_ase)
FILE *fp;
struct LS_ASE_HDR_LIST *lsdb_ase;
{
    struct LS_ASE_HDR_LIST *ase_hdr;
    struct LS_ASE_LIST *link;
    struct LS_ASE *ls_ase;
    short part=LSA_DATA_END;
    
    if(fp == NULL) fp = stderr;
    
    for(ase_hdr = lsdb_ase;ase_hdr;ase_hdr=ase_hdr->next) {
	fwrite((char *)&(ase_hdr->hdr),sizeof(struct LS_HDR),1,fp);
	fwrite((char *)&ase_hdr->net_mask,sizeof(u_long),1,fp);
	for(link=ase_hdr->ase_link;link;link=link->next) {
	    ls_ase = (struct LS_ASE *)&(link->tos_metric);
	    fwrite((char *)ls_ase,sizeof(struct LS_ASE),1,fp);
	}
	fwrite((char *)&part,sizeof(short),1,fp);
    }
}

/*

  ls_hdr_dump

*/
void ls_hdr_dump(fp,hdr)
FILE *fp;
struct LS_HDR *hdr;
{
    int age;

    if(fp == NULL) fp = stderr;    

    age = (int)hdr->ls_age;
    
    log_trace(fp,"  LS_TYPE: %-9s",ls_type[hdr->ls_type]);
    log_trace(fp,"  LS_ID  : %-15s	",inetaddr_to_char(hdr->ls_id));
    log_trace(fp,"  ADV_RT : %-15s\n",inetaddr_to_char(hdr->adv_rt));
    if(hdr->length != 0) {
      log_trace(fp,"  LEN    : %-9d",ntohs(hdr->length));
      log_trace(fp,"  SEQ    : %-15x	",ntohl(hdr->ls_seq));
      log_trace(fp,"  AGE    : %-15x\n",ntohs(age));
  }
}
      
void lsdb_dump(fp,rt_tbl)
FILE *fp;
char *rt_tbl;
{
    struct LSDB_LIST *lsdb;
    struct AREA_TBL *area;

    if(fp == NULL) fp = stderr;
    
    if(rt_tbl == NULL) {
	log_trace(fp," \n Routing table is not generated\n");
	return;
    }
    else {
	lsdb = (struct LSDB_LIST *)rt_tbl;
    }
    
/*    for(lsdb = (struct LSDB_LIST *)rt_tbl;lsdb;lsdb=lsdb->next) {*/
    area = (struct AREA_TBL *)lsdb->area;
    log_trace(fp,"\n  < AREA %s >\n",inetaddr_to_char(area->number));
    
    rt_link_dump(fp,lsdb->rt);
    net_link_dump(fp,lsdb->net);
    sum_net_link_dump(fp,lsdb->sum_net);
    sum_asbr_link_dump(fp,lsdb->sum_asbr);
    ase_link_dump(fp,lsdb->ase);

/*    }*/
}

void lsa_dump(fp,rt_tbl)
FILE *fp;
char *rt_tbl;
{
    struct LSA_LIST *lsa;
    struct LSDB_SUM_LIST *list;
    struct AREA_TBL *area;

    if(fp == NULL) fp = stderr;
    
    if(rt_tbl == NULL) {
	log_trace(fp," \n Routing table is not generated\n");
	return;
    }
    else {
        lsa = (struct LSA_LIST *)rt_tbl;	
    }
    
    log_trace(fp,"\n  <adv lsa list >\n");

    for(list=lsa->my_lsdb;list;list=list->next) {
        ls_hdr_dump(fp, list->lsh);
    }
}

void lsdb_bin_dump(fp,rt_tbl)
FILE *fp;
char *rt_tbl;
{
    struct LSDB_LIST *lsdb;
    struct AREA_TBL *area;
    short part=AREA_DATA_END;
    
    if(fp == NULL) fp = stderr;
    
    if(rt_tbl == NULL) {
	log_trace(fp," \n Routing table is not generated\n");
	return;
    }
    else {
	lsdb = (struct LSDB_LIST *)rt_tbl;
    }
    
    area = (struct AREA_TBL *)lsdb->area;
    fwrite((char *)&area->number,sizeof(long),1,fp);
    
    rt_link_bin_dump(fp,lsdb->rt);
    net_link_bin_dump(fp,lsdb->net);
    sum_net_link_bin_dump(fp,lsdb->sum_net);
    sum_asbr_link_bin_dump(fp,lsdb->sum_asbr);
    ase_link_bin_dump(fp,lsdb->ase);
    fwrite((char *)&part,sizeof(short),1,fp);
    
/*    }*/
}

/*

  lsdb_free

*/
void lsdb_free(lsdb)
struct LSDB_LIST *lsdb;
{
    struct LS_RT_HDR_LIST *rt_hdr,*nrt_hdr;
    struct LS_RT_LIST *rt,*nrt;
    struct LS_NET_HDR_LIST *net_hdr,*nnet_hdr;
    struct LS_NET_LIST *net,*nnet;
    struct LS_SUM_HDR_LIST *sum_hdr,*nsum_hdr;
    struct LS_SUM_LIST *sum,*nsum;
    struct LS_SUM_HDR_LIST *sum_asbr,*nex_sum_asbr;
    struct LS_ASE_HDR_LIST *ase_hdr,*nase_hdr;
    struct LS_ASE_LIST *ase,*nase;

    for(rt_hdr=lsdb->rt;rt_hdr;) {
	for(rt=rt_hdr->rt_link;rt;) {
	    nrt = rt->next;
	    free((char *)rt);
	    rt = nrt;
	}
	nrt_hdr = rt_hdr->next;
	free((char *)rt_hdr);
	rt_hdr = nrt_hdr;
    }

    for(net_hdr=lsdb->net;net_hdr;) {
	for(net=net_hdr->net_link;net;) {
	    nnet = net->next;
	    free((char *)net);
	    net = nnet;
	}
	nnet_hdr = net_hdr->next;
	free((char *)net_hdr);
	net_hdr = nnet_hdr;
    }

    for(sum_hdr=lsdb->sum_net;sum_hdr;) {
	for(sum=sum_hdr->sum_link;sum;) {
	    nsum = sum->next;
	    free((char *)sum);
	    sum = nsum;
	}
	nsum_hdr = sum_hdr->next;
	free((char *)sum_hdr);
	sum_hdr = nsum_hdr;
    }

    for(sum_hdr=lsdb->sum_asbr;sum_hdr;) {
	for(sum=sum_hdr->sum_link;sum;) {
	    nsum = sum->next;
	    free((char *)sum);
	    sum = nsum;
	}
	nsum_hdr = sum_hdr->next;
	free((char *)sum_hdr);
	sum_hdr = nsum_hdr;
    }

    for(ase_hdr=lsdb->ase;ase_hdr;) {
	for(ase=ase_hdr->ase_link;ase;) {
	    nase = ase->next;
	    free((char *)ase);
	    ase = nase;
	}
	nase_hdr = ase_hdr->next;
	free((char *)ase_hdr);
	ase_hdr = nase_hdr;
    }

    if((sum_hdr=lsdb->default_sum) != NULL) {
	free((char *)sum_hdr->sum_link);
	free((char *)sum_hdr);
    }
    
    free((char *)lsdb);
}

print_lsdb_list(fp)
FILE *fp;
{
    struct LSDB_LIST *lsdb;

    for(lsdb=lsdb_list;lsdb;lsdb=lsdb->next) {
	log_trace(stderr,"lsdb = %x\n",lsdb);
    }
}

/*

  lsdb_load

*/
byte *lsdb_load(fp,id,intf,type,arg)
FILE *fp;
u_long id;
u_long intf;
int type;
int arg;
{
    struct AS_TBL *as;
    struct AREA_TBL *area;
    struct RT_TBL *rt;
    u_long area_num;
    u_long as_num;
    struct LSDB_LIST *lsdb;
    struct LSDB_LIST *list;
    long ldata;
    short sdata;
    char  cdata; 
    struct LS_HDR hdr;
    struct LS_RT_HDR_LIST *rt_list,*rt_tmp;
    struct LS_NET_HDR_LIST *net_list,*net_tmp;
    struct LS_SUM_HDR_LIST *sumnet_list,*sumasbr_list,*sumnet_tmp,*sumasbr_tmp;
    struct LS_ASE_HDR_LIST *ase_list,*ase_tmp;
    
    as_num = get_as_num(id);
    fread((char *)&ldata,sizeof(long),1,fp);  /* read area number */
    as = get_as_list((u_long)as_num);
    for(area=as->alist;area;area=area->next)
      if(area->number == (u_long)ldata) break;

    MALLOC(lsdb,LSDB_LIST);
    lsdb->area = (char *)area;    

    if(!area) {
	log_trace(stderr,"not exit area <%s> data\n",inetaddr_to_char(area_num));
	return NULL;
    }

    while(fread((char *)&sdata,sizeof(short),1,fp),sdata != AREA_DATA_END) {
	fseek(fp,-2L,1);
	fread((char *)&hdr,sizeof(struct LS_HDR),1,fp);
	switch(hdr.ls_type) {
	case LS_TYPE_RT : rt_list = rt_link_load(fp,area,&hdr);
	    if(lsdb->rt) { rt_tmp->next=rt_list; rt_tmp=rt_list; }
	    else {lsdb->rt=rt_list; rt_tmp=rt_list;}
	    break;
	case LS_TYPE_NET : net_list = net_link_load(fp,area,&hdr);
	    if(lsdb->net) { net_tmp->next=net_list; net_tmp=net_list; }
	    else {lsdb->net=net_list; net_tmp=net_list;}
	    break; 
	case LS_TYPE_SUM_NET : sumnet_list = sum_net_link_load(fp,area,&hdr);
	    if(lsdb->sum_net) { sumnet_tmp->next=sumnet_list; sumnet_tmp=sumnet_list; }
	    else {lsdb->sum_net=sumnet_list; sumnet_tmp=sumnet_list;}
            break;
	case LS_TYPE_SUM_ASBR : lsdb->sum_asbr = sum_asbr_link_load(fp,area,&hdr);
	    if(lsdb->sum_asbr) { sumasbr_tmp->next=sumasbr_list; sumasbr_tmp=sumasbr_list; }
	    else {lsdb->sum_asbr=sumasbr_list; sumasbr_tmp=sumasbr_list;}
	                        break;
	case LS_TYPE_ASE : ase_list = ase_link_load(fp,area,&hdr);
	    if(lsdb->ase) { ase_tmp->next=ase_list; ase_tmp=ase_list; }
	    else {lsdb->ase=ase_list;ase_tmp=ase_list;}
	                   break;
	default : break;
	}
    }
    
    make_lsdb_time = get_currnt_time();
    
    if(lsdb_list == NULL) {
	lsdb_list = lsdb;
    }
    else {
	for(list=lsdb_list;list->next;list=list->next);
	list->next = lsdb;
    }

    ls_seq_num++;

    return (byte *)lsdb;
}

/*

  rt_link_load

*/
struct LS_RT_HDR_LIST *rt_link_load(fp,area,hdr)
FILE *fp;
struct AREA_TBL *area;
struct LS_HDR *hdr;
{
    struct LS_RT_HDR_LIST *ls_rt_list;
    u_short rt_link_num;
    struct LS_RT_HDR_LIST *rt_hdr;
    struct LS_RT_LIST *ls_rtp,*tmp;
    struct LS_RT data;
    short part;
    
    ls_rt_list = NULL;
    MALLOC(rt_hdr,LS_RT_HDR_LIST);

    rt_hdr->hdr.ls_type = hdr->ls_type;
    rt_hdr->hdr.ls_id = hdr->ls_id;
    rt_hdr->hdr.adv_rt = hdr->adv_rt;
    rt_hdr->hdr.ls_seq = hdr->ls_seq;
    rt_hdr->hdr.length = hdr->length;
    
    fread((char *)&rt_hdr->bits,sizeof(short),1,fp); /* read bits */
    fread((char *)&rt_hdr->link,sizeof(short),1,fp); /* read link num */
    
    for(rt_link_num=0;rt_link_num<rt_hdr->link;rt_link_num++) {
	MALLOC(ls_rtp,LS_RT_LIST);
	fread((char *)&data,sizeof(struct LS_RT),1,fp);
	ls_rtp->type = data.type;
	ls_rtp->id = data.id;
	ls_rtp->data = data.data;
	ls_rtp->tos_num = data.tos_num;
	ls_rtp->tos0_metric = data.tos0_metric;

	if(rt_hdr->rt_link == NULL) {
	    rt_hdr->rt_link = ls_rtp;
	    tmp = ls_rtp;
	}
	else {
	    tmp->next = ls_rtp;
	    tmp = ls_rtp;
	}
    }

    fread((char *)&part,sizeof(short),1,fp); /* read LSA_DATA_END */

    if(part == LSA_DATA_END) {
	return rt_hdr;
    }
    else {
	log_trace(stderr,"\n data read error \n");
	return NULL;
    }

}

/*

  net_link_load

*/
struct LS_NET_HDR_LIST *net_link_load(fp,area,hdr)
FILE *fp;
struct AREA_TBL *area;
struct LS_HDR *hdr;
{
    struct LS_NET_HDR_LIST *ls_net_list;
    u_short rt_link_num;
    struct LS_NET_HDR_LIST *net_hdr;
    struct LS_NET_LIST *ls_netp,*tmp;
    struct LS_NET data;
    short part;
    
    ls_net_list = NULL;
    MALLOC(net_hdr,LS_NET_HDR_LIST);

    net_hdr->hdr.ls_type = hdr->ls_type;
    net_hdr->hdr.ls_id = hdr->ls_id;
    net_hdr->hdr.adv_rt = hdr->adv_rt;
    net_hdr->hdr.ls_seq = hdr->ls_seq;
    net_hdr->hdr.length = hdr->length;
    
    fread((char *)&net_hdr->net_mask,sizeof(long),1,fp); /* read netmask */

    while(fread((char *)&part,sizeof(short),1,fp),part != LSA_DATA_END) {
	fseek(fp,-2L,1);
	MALLOC(ls_netp,LS_NET_LIST);
	fread((char *)&data,sizeof(struct LS_NET),1,fp);
	ls_netp->cnct_rt = data.cnct_rt;

	if(net_hdr->net_link == NULL) {
	    net_hdr->net_link = ls_netp;
	    tmp = ls_netp;
	}
	else {
	    tmp->next = ls_netp;
	    tmp = ls_netp;
	}
    }

    if(part == LSA_DATA_END) {
	return net_hdr;
    }
    else {
	log_trace(stderr,"\n data read error \n");
	return NULL;
    }

}

/*

  sum_link_load

*/
struct LS_SUM_HDR_LIST *sum_net_link_load(fp,area,hdr)
FILE *fp;
struct AREA_TBL *area;
struct LS_HDR *hdr;
{
    struct LS_SUM_HDR_LIST *ls_sum_list;
    u_short rt_link_num;
    struct LS_SUM_HDR_LIST *sum_hdr;
    struct LS_SUM_LIST *ls_sump,*tmp;
    struct LS_SUM data;
    short part;
    
    ls_sum_list = NULL;
    MALLOC(sum_hdr,LS_SUM_HDR_LIST);

    sum_hdr->hdr.ls_type = hdr->ls_type;
    sum_hdr->hdr.ls_id = hdr->ls_id;
    sum_hdr->hdr.adv_rt = hdr->adv_rt;
    sum_hdr->hdr.ls_seq = hdr->ls_seq;
    sum_hdr->hdr.length = hdr->length;
    
    fread((char *)&sum_hdr->net_mask,sizeof(long),1,fp); /* read netmask */

    while(fread((char *)&part,sizeof(short),1,fp),part != LSA_DATA_END) {
	fseek(fp,-2L,1);
	MALLOC(ls_sump,LS_SUM_LIST);
	fread((char *)&data,sizeof(struct LS_SUM),1,fp);
	ls_sump->tos_metric = data.tos_metric;

	if(sum_hdr->sum_link == NULL) {
	    sum_hdr->sum_link = ls_sump;
	    tmp = ls_sump;
	}
	else {
	    tmp->next = ls_sump;
	    tmp = ls_sump;
	}
    }

    if(part == LSA_DATA_END) {
	return sum_hdr;
    }
    else {
	log_trace(stderr,"\n data read error \n");
	return NULL;
    }

}

/*

  sum_asbr_link_load

*/
struct LS_SUM_HDR_LIST *sum_asbr_link_load(fp,area,hdr)
FILE *fp;
struct AREA_TBL *area;
struct LS_HDR *hdr;
{
    struct LS_SUM_HDR_LIST *ls_sum_list;
    u_short rt_link_num;
    struct LS_SUM_HDR_LIST *sum_hdr;
    struct LS_SUM_LIST *ls_sump,*tmp;
    struct LS_SUM data;
    short part;
    
    ls_sum_list = NULL;
    MALLOC(sum_hdr,LS_SUM_HDR_LIST);

    sum_hdr->hdr.ls_type = hdr->ls_type;
    sum_hdr->hdr.ls_id = hdr->ls_id;
    sum_hdr->hdr.adv_rt = hdr->adv_rt;
    sum_hdr->hdr.ls_seq = hdr->ls_seq;
    sum_hdr->hdr.length = hdr->length;
    
    fread((char *)&sum_hdr->net_mask,sizeof(long),1,fp); /* read netmask */

    while(fread((char *)&part,sizeof(short),1,fp),part != LSA_DATA_END) {
	fseek(fp,-2L,1);
	MALLOC(ls_sump,LS_SUM_LIST);
	fread((char *)&data,sizeof(struct LS_SUM),1,fp);
	ls_sump->tos_metric = data.tos_metric;

	if(sum_hdr->sum_link == NULL) {
	    sum_hdr->sum_link = ls_sump;
	    tmp = ls_sump;
	}
	else {
	    tmp->next = ls_sump;
	    tmp = ls_sump;
	}
    }

    if(part == LSA_DATA_END) {
	return sum_hdr;
    }
    else {
	log_trace(stderr,"\n data read error \n");
	return NULL;
    }

}

/*

  ase_link_load

*/
struct LS_ASE_HDR_LIST *ase_link_load(fp,area,hdr)
FILE *fp;
struct AREA_TBL *area;
struct LS_HDR *hdr;
{
    struct LS_ASE_HDR_LIST *ls_ase_list;
    u_short rt_link_num;
    struct LS_ASE_HDR_LIST *ase_hdr;
    struct LS_ASE_LIST *ls_asep,*tmp;
    struct LS_ASE data;
    short part;
    
    ls_ase_list = NULL;
    MALLOC(ase_hdr,LS_ASE_HDR_LIST);

    ase_hdr->hdr.ls_type = hdr->ls_type;
    ase_hdr->hdr.ls_id = hdr->ls_id;
    ase_hdr->hdr.adv_rt = hdr->adv_rt;
    ase_hdr->hdr.ls_seq = hdr->ls_seq;
    ase_hdr->hdr.length = hdr->length;
    
    fread((char *)&ase_hdr->net_mask,sizeof(long),1,fp); /* read netmask */

    while(fread((char *)&part,sizeof(short),1,fp),part != LSA_DATA_END) {
	fseek(fp,-2L,1);
	MALLOC(ls_asep,LS_ASE_LIST);
	fread((char *)&data,sizeof(struct LS_ASE),1,fp);
	ls_asep->tos_metric = data.tos_metric;
	ls_asep->forward_addr = data.forward_addr;
	ls_asep->ext_rt_tag = data.ext_rt_tag;
	
	if(ase_hdr->ase_link == NULL) {
	    ase_hdr->ase_link = ls_asep;
	    tmp = ls_asep;
	}
	else {
	    tmp->next = ls_asep;
	    tmp = ls_asep;
	}
    }

    if(part == LSA_DATA_END) {
	return ase_hdr;
    }
    else {
	log_trace(stderr,"\n data read error \n");
	return NULL;
    }

}



