/************************************************************************/
/*	Routing Protocol Simulator	Relese 1.0	1994/3/17	*/
/*									*/
/*		module 	: network management				*/
/*		file	: rps_net.c	       				*/
/*									*/
/*   Copyright (c) 1994 by Systems Development Laboratory Hitachi,Ltd.	*/
/*   All rights reserved.						*/
/*----------------------------------------------------------------------*/
/*	UPDATE HISTORY							*/
/*									*/
/************************************************************************/
static char copyright[]=
  "@(#)Copyright (c) 1994 by Systems Development Laboratory Hitachi,Ltd.\n All rights researved.\n";

#include "rps.h"
#include "rps_token.h"
#include "netmng.h"

extern u_long char_to_inetaddr();
extern long asc_to_long();
extern struct NET_TBL *net_search();
extern struct RT_TBL *rt_search();
extern struct RT_TBL *get_rt_list();
extern struct AS_TBL *get_router_as();
extern struct LINK_TBL *get_link_list();
extern struct NET_TBL *get_net_list();
extern struct NET_TBL *get_link_net();

void make_abr_list();
void make_asbr_list();

struct token case_token[] =
{
    {T_CASE_UNKNOWN,		"unknown-case" },
    {T_CASE_AS,			"as" },
    {T_CASE_AREA ,		"area" },
    {T_CASE_NETWORK ,		"network" },
    {T_CASE_MASK ,		"mask" },
    {T_CASE_ROUTER ,		"router" },
    {T_CASE_INTERFACE ,		"interface" },
    {T_CASE_COST ,		"cost" },
    {NULL}
};

struct token case_error[] =
{
    {T_ERRCASE_UNKNOWN ,	"unknown parameter" },
    {T_ERRCASE_ROUTER ,		"invalid router parameter"},
    {T_ERRCASE_MISSING ,	"missing parameter"}
};

extern struct token common_error[];

#define ERRCASE_ROUTER        T_ERRCASE_ROUTER , case_error
#define ERRCASE_MISSING       T_ERRCONF_MISSING , case_error

/*

  case_load - read network case file

*/
int case_load(file)
char *file;
{
    FILE *fp;
    char token[MAX_NUM_CASE_CHARACTER];
    int rt;
    
    if((fp = fopen(file,"r")) == NULL) {
	printf("network case file (%s) open error!\n",file);
	return -1;
    }

    log_trace(stderr,"\n\n Network-case file (%s) loading...\n",file);

    init_token();
    while(!GET_TOKEN_EOF(fp,token)) {
	if(token_type(case_token,token) == T_CASE_AS) {
	    if(!make_as_table(fp)) {
		fclose(fp);
		exit(1);
	    }
	}
    }
    
    make_abr_list();
    dr_selection();
    make_link_table();
    make_asbr_list();

    fclose(fp);

    net_info_dump(stderr);
    printf(" loading... Done \n");

    return 1;
}

/*

  make_as_table - make as management table

*/
int make_as_table(fp)
FILE *fp;
{
    char token[MAX_NUM_CASE_CHARACTER];
    struct AS_TBL *as;
    struct INDEX *index,*ilist;
    u_short area_num,net_num;

    GET_TOKEN(fp,token,ERR_END_OF_FILE);

    MALLOC(as,AS_TBL);
    as->number = (u_long)asc_to_int(token);
    
    BEGIN_CLAUSE(fp,token,ERR_BEGIN_CLAUSE);
    area_num = net_num = 0;
    ilist = NULL;
    while(!GET_CLAUSE_END(fp,token)) {
        switch(token_type(case_token,token)) {
	case T_CASE_AREA	: if(!make_area_table(fp,as)) return 0;
	    			  area_num++;
	    			  break;
	case T_CASE_NETWORK	: MALLOC(index,INDEX);
				  index->src_type = ITYPE_AS;
	    			  index->src = (byte *)as;
	    			  if(!make_network_table(fp,index)) return 0;
	    			  add_index_list(&ilist,index);
				  net_num++;
	    			  break;
	default			: error_print(T_ERROR_SYNTAX,common_error);
				  return 0;
	    			  break;
        }
    }

    as->area_num = area_num;
    as->net_num = net_num;
    add_astbl_list(as);
    as->nlist = ilist;
    
    return 1;
}

/*

  make_area_table - make area management table

*/
int make_area_table(fp,as)
FILE *fp;
struct AS_TBL *as;
{
    char token[MAX_NUM_CASE_CHARACTER];
    struct AREA_TBL *area;
    struct INDEX *index,*ilist;
    u_short net_num;
    
    GET_TOKEN(fp,token,ERR_END_OF_FILE);

    MALLOC(area,AREA_TBL);
    area->number = char_to_inetaddr(token);

    BEGIN_CLAUSE(fp,token,ERR_BEGIN_CLAUSE);
    net_num=0;
    ilist = NULL;
    while(!GET_CLAUSE_END(fp,token)) {
	if(token_type(case_token,token) == T_CASE_NETWORK) {
	    MALLOC(index,INDEX);
	    index->src_type = ITYPE_AREA;
	    index->src = (byte *)area;
	    if(!make_network_table(fp,index)) return 0;
	    add_index_list(&ilist,index);
	    net_num++;
	}
	else {
	    error_print(T_ERROR_SYNTAX,common_error);
	    return 0;
	}
    }

    area->as_idx = as;
    area->net_num = net_num;
    add_area_list(as,area);
    area->nlist = ilist;
    
    return 1;
}

/*

  make_network_table - make network management table

*/
int make_network_table(fp,net_idx)
FILE *fp;
struct INDEX *net_idx;
{
    char token[MAX_NUM_CASE_CHARACTER];
    struct NET_TBL *net;
    struct INDEX *ilist,*rt_idx;
    int rt;
    u_short rt_num;
    u_long net_addr,net_mask;
    
    GET_TOKEN(fp,token,ERR_END_OF_FILE);
    net_addr = char_to_inetaddr(token);
      
    GET_TOKEN(fp,token,ERR_END_OF_FILE);
    if(token_type(case_token,token) == T_CASE_MASK) {
	GET_TOKEN(fp,token,ERR_END_OF_FILE);
	net_mask = char_to_inetaddr(token);
    }
    else {
	error_print(T_ERROR_SYNTAX,common_error);
	return 0;
    }

    if((net = net_search(net_addr,net_mask)) == NULL) {
	MALLOC(net,NET_TBL);

	net->addr = net_addr;
	net->mask = net_mask;

	add_net_list(net);
    }
#ifdef DEBUG
    else {
	printf(" already exit network %s \n",inetaddr_to_char(net_addr));
    }
#endif
    
    BEGIN_CLAUSE(fp,token,ERR_BEGIN_CLAUSE);

    rt_num = 0;
    ilist = NULL;
    while(!GET_CLAUSE_END(fp,token)) {
	if(token_type(case_token,token) == T_CASE_ROUTER) {
	    MALLOC(rt_idx,INDEX);
	    rt_idx->src_type = ITYPE_NETWORK;
	    rt_idx->src = (byte *)net;
	    if(!make_router_table(fp,rt_idx)) return 0;
	    add_index_list(&(net->cnct_rt),rt_idx);
	    rt_num++;
	}
	else {
	    error_print(T_ERROR_SYNTAX,common_error);
	    return 0;
	}
    }

    net->cnct_num = rt_num;
    
/*    net->cnct_rt = ilist;*/
    if(net_idx->src_type == ITYPE_AS) {
	if(net->domain_type == ITYPE_AS && net->domain != NULL) {
	    net->domain_type = ITYPE_INTER_AS;
	}
	else {
	    net->domain_type = ITYPE_AS;
	    net->domain = net_idx->src;
	}
    }
    else if(net_idx->src_type == ITYPE_AREA) {
	net->domain_type = ITYPE_AREA;
	net->domain = net_idx->src;
    }

    net_idx->dst_type = ITYPE_NETWORK;
    net_idx->dst = (byte *)net;
    return 1;
}

/*

  make_router_table - make router management table

*/
int make_router_table(fp,index)
FILE *fp;
struct INDEX *index;
{
    char token[MAX_NUM_CASE_CHARACTER];
    struct RT_TBL *rt;
    struct NET_TBL *net;
    struct RT_INTF *cnet;
    u_long router_id;
    
    GET_TOKEN(fp,token,ERR_END_OF_FILE);
    router_id = char_to_inetaddr(token);

    net = (struct NET_TBL *)index->src;
    
    if((rt = rt_search(router_id)) == NULL) {
	MALLOC(rt,RT_TBL);
	rt->cnct_num = 1;
	rt->id = router_id;
	add_rt_list(rt);
    }
    else {
#ifdef DEBUG
/*	log_trace(stderr," already exit router %s \n",inetaddr_to_char(router_id)); */
#endif
	rt->cnct_num++;
    }

    MALLOC(cnet,RT_INTF);
    cnet->net = net;
    cnet->state = INTF_UP;
    
    while(!GET_STATEMENT_END(fp,token)) {
	switch(token_type(case_token, token)) {
	case T_CASE_INTERFACE 	: GET_TOKEN(fp,token,ERR_END_OF_FILE)
	    			  cnet->ifaddr = convert_inetaddr(token);
	    			  break;
	case T_CASE_COST 	: GET_TOKEN(fp,token,ERR_END_OF_FILE)
	  			  cnet->cost = asc_to_long(token);
 				  break;
        default			: error_print(T_ERRCASE_ROUTER, case_error);
	    			  return 0;
	    			  break;
        }
    }

    if(cnet->ifaddr == 0) {
	assign_if_addr(cnet);
    }
    add_cnct_net(rt,cnet);
    index->dst_type = ITYPE_ROUTER;
    index->dst = (byte *)rt;
    return 1;
}

/*

  make_abr_list

*/
void make_abr_list()
{
    struct RT_TBL *rt;
    struct INDEX *area_idx,*index;
    u_short area_num;
    struct AREA_TBL *area;
    
    for(rt=get_rt_list(LIST_HEAD);rt!=NULL;rt=rt->next) {
	area_num = get_router_area(rt,&area_idx);
	rt->domain_num = area_num;
	rt->domain = area_idx;
	if(area_num > 1) {
	    for(index=area_idx;index!=NULL;index=index->next) {
		area = (struct AREA_TBL *)index->dst;
		add_abr_list(area,rt);
	    }
	}
    }
}
		  
		
/*

  make_link_table

*/
int make_link_table()
{
    struct RT_TBL *rt,*cnct_rt;
    struct NET_TBL *net;
    struct LINK_TBL *link;
    struct RT_INTF *cnct;
    struct INDEX *index;
    int id;

    id = 1;
    for(rt=get_rt_list(LIST_HEAD);rt!=NULL;rt=rt->next) {
	for(cnct=rt->ilist;cnct!=NULL;cnct=cnct->next) {
	    net = cnct->net;
	    for(index=net->cnct_rt;index!=NULL;index=index->next) {
		cnct_rt = (struct RT_TBL *)index->dst;
		if(rt == cnct_rt) continue;
		MALLOC(link,LINK_TBL);
		link->id = id++;
		link->org = rt;
		link->cnct = cnct_rt;
		link->link_net = get_link_net(rt->id,cnct_rt->id);
		link->cost = cnct->cost;
		add_link_list(link);
	    }
        }
    }

}
	
/*

  make_asbr_list

*/
void make_asbr_list()
{
    struct LINK_TBL *link;
    struct RT_TBL *asbr;
    struct AS_TBL *org_as,*cnct_as;
    
    for(link=get_link_list(LIST_HEAD,LIST_HEAD);link!=NULL;link=link->next) {
	org_as = get_router_as(link->org);
	cnct_as = get_router_as(link->cnct);
	if(org_as == cnct_as)
	    continue;

	add_asbr_list(org_as,link->org);
    }
}
	    

