/************************************************************************/
/*	Routing Protocol Simulator	Relese 1.0	1994/3/17	*/
/*									*/
/*		module 	: router management				*/
/*		file	: rps_config.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 "router.h"
#include "netmng.h"
#include "rps_bgp.h"
#include "rps_ospf.h"

struct token config_token[] =
{
	{T_CONFIG_UNKNOWN,		"unknown-command"},
	{T_CONFIG_ROUTER,		"router"},
	{T_CONFIG_PROTOCOL, 		"protocol"},
	{T_CONFIG_INTERFACE,		"interface"},
	{T_CONFIG_NEIGHBOR,		"neighbor"},
	{T_CONFIG_HOLDTIME,		"holdtime"},
	{T_CONFIG_VERSION,		"version"},
	{T_CONFIG_HELLO,		"hellointerval"},
	{T_CONFIG_ROUTERDEAD,		"routerdeadinterval"},
	{T_CONFIG_PRIORITY,		"priority"},
	{T_CONFIG_STUB,			"stub"},
	{T_CONFIG_STUB_COST,		"cost"},
	{T_CONFIG_VIRTUAL,		"virtuallink"},
	{T_CONFIG_ROUTERTYPE,		"routertype"},
	{T_CONFIG_AUTHTYPE,		"authtype"},
	{T_CONFIG_AUTHKEY,		"key"},
	{T_CONFIG_MULTICAST,		"multicast"},
	{NULL}
};

struct token protocol_token[] =
{
    {T_PROTO_UNKNOWN,	"unknown"},
    {T_PROTO_BGP,	"bgp"},
    {T_PROTO_OSPF,	"ospf"},
    {NULL}
};

struct token config_error[] = 
{
    {T_ERRCONF_UNKNOWN,		"unknown parameter" },
    {T_ERRCONF_ROUTER,		"not exist router_id in network file"},
    {T_ERRCONF_PROTOCOL,	"unknown protocol" },
    {T_ERRCONF_INTERFACE,	"not match interface_addr"},
    {T_ERRCONF_VALUE,		"invalid value" },
    {T_ERRCONF_MISSING,		"missing value" }
};

struct token authtype_token[] =
{
    {T_AUTHTYPE_NONE,	"0"},
    {T_AUTHTYPE_NONE,	"none"},
    {T_AUTHTYPE_SIMPLE,	"1"},
    {T_AUTHTYPE_SIMPLE,	"simple"},
    {NULL}
};
    
extern struct RT_CONF *router_alloc();
extern struct RT_IFCONF *router_if_alloc();
extern struct in_addr *if_inetaddr();
extern u_long get_area_num();
extern struct RT_TBL *get_rt_list();
extern struct NET_TBL *get_net_with_ifaddr();

void make_if_mngid();
void ospf_area_dump();
void ospf_area_free();

extern struct token common_error[];

/*
#define	ERR_SYNTAX		T_ERROR_SYNTAX,common_error
#define	ERR_BEGIN_CLAUSE	T_ERROR_BEGIN_CLAUSE,common_error
#define	ERR_END_CLAUSE		T_ERROR_END_CLAUSE,common_error
#define	ERR_END_STATEMENT	T_ERROR_END_STATEMENT,common_error
#define	ERR_END_OF_FILE		T_ERROR_END_OF_FILE ,common_error
*/

#define ERRCONF_ROUTER		T_ERRCONF_ROUTER , config_error
#define ERRCONF_PROTOCOL       	T_ERRCONF_PROTOCOL , config_error
#define ERRCONF_INTERFACE	T_ERRCONF_INTERFACE, config_error
#define ERRCONF_VALUE		T_ERRCONF_VALUE , config_error
#define ERRCONF_MISSING		T_ERRCONF_MISSING , config_error


/*

  load_config - read configuraion file

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

    init_token();

    log_trace(stderr," Configuration file (%s) loading... \n",file);

    while(!GET_TOKEN_EOF(fp,token)) {
	if(token_type(config_token, token) == T_CONFIG_ROUTER) {
	    if(!router_config(fp)) {
		fclose(fp);
		exit(1);
	    }
	}

    }

    fclose(fp);

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

    return 1;
}

/*

  router_config - make router configuration mangement table

*/
int router_config(fp)
FILE *fp;
{
    char token[MAX_NUM_CONFIG_CHARACTER];
    struct RT_CONF *rtp;
    u_long conf_id;
    
    GET_TOKEN(fp,token,ERR_END_OF_FILE);

    conf_id = char_to_inetaddr(token);
    if(!get_rt_list(conf_id)) {
	error_print(T_ERRCONF_ROUTER,config_error);
	return 0;
    }
    
    MALLOC(rtp,RT_CONF);

    rtp->router_id = conf_id;
    strcpy(rtp->mng_id,token);
    rtp->trace_flag = OFF;
    BEGIN_CLAUSE(fp,token,ERR_BEGIN_CLAUSE) ;
	
    while(!GET_CLAUSE_END(fp,token)) {
        if(token_type(config_token,token) == T_CONFIG_PROTOCOL) {
	    if(!protocol_config(fp,rtp))
	      return 0;
	}
	else {
	    error_print(T_ERROR_SYNTAX,common_error);
	    return 0;
	}
    }

    add_router_list(rtp);
    return 1;
}

/*

  protocol_config - make protocol configiration management table

*/
int protocol_config(fp,rtp)
FILE *fp;
struct RT_CONF *rtp;
{
    char protocol[MAX_NUM_CONFIG_CHARACTER];
    u_short if_num;

    if_num = 0;
    GET_TOKEN(fp,protocol,ERR_END_OF_FILE);
      
    switch(token_type(protocol_token,protocol)) {
    case T_PROTO_BGP : if(!(if_num=proto_bgp_config(fp,rtp)))
      			return 0;
		       break;
    case T_PROTO_OSPF : if(!(if_num=proto_ospf_config(fp,rtp)))
				return 0;
	    		    break;
    default		: error_print(T_ERRCONF_PROTOCOL,config_error);
	    		    return 0;
    }
    
    rtp->if_num = if_num;

    return 1;
}

/*

  proto_bgp_config

*/
int proto_bgp_config(fp,rtp)
FILE *fp;
struct RT_CONF *rtp;
{
    char token[MAX_NUM_CONFIG_CHARACTER];
    struct RT_IFCONF *rt_ifp;
    u_short if_num;
    int rt;
    
    BEGIN_CLAUSE(fp,token,ERR_BEGIN_CLAUSE);

    if_num = 0;
    while(!GET_CLAUSE_END(fp,token)) {
	if(token_type(config_token,token) == T_CONFIG_INTERFACE) {
	    MALLOC(rt_ifp,RT_IFCONF);
	    
	    if(!interface_config(fp,rtp,rt_ifp))
	      return 0;

	    if(!bgp_config(fp,rt_ifp))
	      return 0;
	    
	    rt_ifp->protocol = T_PROTO_BGP;
	    add_router_if_list(rtp,rt_ifp);
	    make_if_mngid(rt_ifp);
	    rt_ifp->self = rtp;
	    if_num++;
	}
	else {
	    error_print(T_ERROR_SYNTAX,common_error);
	    return 0;
	}

    }

    return if_num;
}

/*

  proto_ospf_config

*/
int proto_ospf_config(fp,rtp)
FILE *fp;
struct RT_CONF *rtp;
{
    char token[MAX_NUM_CONFIG_CHARACTER];
    struct RT_IFCONF *rt_ifp;
    u_short if_num;
    
    BEGIN_CLAUSE(fp,token,ERR_BEGIN_CLAUSE);

    if_num = 0;
    while(!GET_CLAUSE_END(fp,token)) {
	rt_ifp = NULL;
	switch(token_type(config_token,token)) {
	case T_CONFIG_INTERFACE  : MALLOC(rt_ifp,RT_IFCONF);
	      			   if(!interface_config(fp,rtp,rt_ifp))
	      				return 0;
	    
			  	   rt_ifp->self = rtp;
				   rt_ifp->protocol = T_PROTO_OSPF;
				   make_if_mngid(rt_ifp);
			    	   if(!ospf_config(fp,rt_ifp))
	  				return 0;
	      			   break;
	case T_CONFIG_VIRTUAL :	   /*MALLOC(rt_ifp,RT_IFCONF);*/
	      			   if(!virtual_config(fp,rtp,&rt_ifp))
	      				return 0;
	    
			  	/*   rt_ifp->self = rtp;
				   rt_ifp->protocol = T_PROTO_OSPF;
				   make_if_mngid(rt_ifp); */
			    	   if(!ospf_virtual_config(fp,rt_ifp))
	  				return 0;
	    			   rt_ifp = NULL;
	      			   break;
	default :	           error_print(T_ERROR_SYNTAX,common_error);
	    			   return 0;
	}
	
	if(rt_ifp != NULL)
	  add_router_if_list(rtp,rt_ifp);
	if_num++;

    }

    return if_num;
}


/*

  interface_config - make bgp configuration management table

*/
int interface_config(fp,rtp,rt_ifp)
FILE *fp;
struct RT_CONF *rtp;
struct RT_IFCONF *rt_ifp;
{
    char token[MAX_NUM_CONFIG_CHARACTER];
    struct if_addr *lcl_addr,*rmt_addr;
    u_long conf_ifaddr;
    
    GET_TOKEN(fp,token,ERR_END_OF_FILE);
    conf_ifaddr = convert_inetaddr(token);
    if(!get_net_with_ifaddr(rtp->router_id,conf_ifaddr)) {
	error_print(T_ERRCONF_INTERFACE,config_error);	
	return 0;
    }
    
    MALLOC(lcl_addr,if_addr);
    
    lcl_addr->addr = if_inetaddr(token);
    
    while(!GET_TOKEN_EOF(fp,token)) {
	switch(token_type(config_token,token)) {
	case T_CONFIG_NEIGHBOR	: GET_TOKEN(fp,token,ERRCONF_VALUE);
	    			  MALLOC(rmt_addr,if_addr);
				  rmt_addr->addr = if_inetaddr(token);
				  rt_ifp->local_addr = lcl_addr;
				  rt_ifp->remote_addr = rmt_addr;
	    			  return 1;
/*	case T_CONFIG_MULTICAST	: GET_TOKEN(fp,token,ERRCONF_VALUE);
	    			  MALLOC(rmt_addr,if_addr);
	    			  rmt_addr->addr = if_inetaddr(token);
	    			  rt_ifp->local_addr = lcl_addr;
	    			  rt_ifp->remote_addr = rmt_addr;
	    			  return 1;*/
	    default 		: error_print(T_ERRCONF_UNKNOWN,config_error);
  				  return 0;
        }
    }

    return 0;

}

/*

  virtual_config - make bgp configuration management table

*/
int virtual_config(fp,rtp,rt_ifp)
FILE *fp;
struct RT_CONF *rtp;
struct RT_IFCONF **rt_ifp;
{
    char token[MAX_NUM_CONFIG_CHARACTER];
/*    struct if_addr *lcl_addr,*rmt_addr;*/
    struct RT_IFCONF *rtif;
    
    GET_TOKEN(fp,token,ERR_END_OF_FILE);

    for(rtif=rtp->rt_ifp;rtif;rtif=rtif->next)
      if(RT_IF_ADDR(rtif) == char_to_inetaddr(token)) break;

/*    MALLOC(lcl_addr,if_addr);
    
    lcl_addr->addr = if_inetaddr(token);*/
    
    while(!GET_TOKEN_EOF(fp,token)) {
	switch(token_type(config_token,token)) {
	case T_CONFIG_NEIGHBOR	: GET_TOKEN(fp,token,ERRCONF_VALUE);
	    			  /*MALLOC(rmt_addr,if_addr);*/
	    			  if(IF_ADDR(rtif->remote_addr) == char_to_inetaddr(token)) {
				      *rt_ifp = rtif;
				      return 1;
				  }
	    			  else {
		/*		  rmt_addr->addr = if_inetaddr(token);
				  rt_ifp->local_addr = lcl_addr;
				  rt_ifp->remote_addr = rmt_addr;*/
				      return 0;
				  }
	    	/*		  return 1; */
	default 		: error_print(T_ERRCONF_UNKNOWN,config_error);
  				  return 0;
        }
    }

    return 0;

}

/*

  bgp_config

*/
int bgp_config(fp,rtifp)
FILE *fp;
struct RT_IFCONF *rtifp;
{
    char token[MAX_NUM_CONFIG_CHARACTER];
    struct proto_bgp *bgp_conf;

    MALLOC(bgp_conf,proto_bgp);
    
    rtifp->proto_info = (char *)bgp_conf;
    strcpy(bgp_conf->mng_id,rtifp->mng_id);
    bgp_conf->router_id = rtifp->self->router_id;
    bgp_conf->myaddr = rtifp->local_addr;
    bgp_conf->peeraddr = rtifp->remote_addr;
    
    bgp_conf->holdtime = BGP_HOLDTIME;
    bgp_conf->version = BGP_VERSION_3;
    
	
    if(!GET_CLAUSE_BEGIN(fp,token)) {
	if(strcmp(token,T_STATEMENT_END)) {
	    error_print(T_ERROR_END_STATEMENT,common_error);	    
	    return 0;
	}
	else {
	    return 1;
	}
    }

    while(!GET_CLAUSE_END(fp,token)) {
	switch(token_type(config_token,token)) {
	case T_CONFIG_HOLDTIME : GET_TOKEN(fp,token,ERRCONF_VALUE)
	  			 bgp_conf->holdtime = asc_to_int(token);
	    			 break;
	case T_CONFIG_VERSION  : GET_TOKEN(fp,token,ERRCONF_VALUE)
				 bgp_conf->version = asc_to_int(token);
	    			 break;
	defatul		       : return 0;
	}
	END_STATEMENT(fp,token,ERR_END_STATEMENT);
    }

    if(!GET_STATEMENT_END(fp,token)) {
	error_print(T_ERROR_END_STATEMENT,common_error);
	return 0;
    }
    
    return 1;
}

/*

  ospf_config

*/
int ospf_config(fp,rtifp)
FILE *fp;
struct RT_IFCONF *rtifp;
{
    char token[MAX_NUM_CONFIG_CHARACTER];
/*    char value[MAX_NUM_CONFIG_CHARACTER];*/
    struct PROTO_OSPF *ospf_conf;
    struct OSPF_AREA *area;
    struct OSPF_IF *ifp;
    struct OSPF_NBR *nbr;

    MALLOC(ospf_conf,PROTO_OSPF);

    rtifp->proto_info = (char *)ospf_conf;
    strcpy(ospf_conf->mng_id,rtifp->mng_id);
    ospf_conf->router_id = rtifp->self->router_id;    
    ospf_conf->hello_display = OFF;
    ospf_conf->db_display = OFF;
    ospf_conf->req_display = OFF;
    ospf_conf->up_display = OFF;
    ospf_conf->ack_display = OFF;

    MALLOC(area,OSPF_AREA);
    
    ospf_conf->myarea = area;

    MALLOC(ifp,OSPF_IF);
    
    area->intf = ifp;
    ifp->ifaddr = rtifp->local_addr;
    ifp->area = area;
    ifp->type = NONBROADCAST;
    ifp->state = IFS_DOWN;
    area->id = get_area_num(ospf_conf->router_id,IF_ADDR(ifp->ifaddr));
    area->authtype = OSPF_AUTHTYPE_NONE;
    area->type = AREA_TYPE_TRANSIT;
    area->default_cost = OSPF_DEFAULT_COST;
    
    MALLOC(nbr,OSPF_NBR);
    
    ifp->nbr = nbr;
    nbr->intf = ifp;
    nbr->nbr_addr = rtifp->remote_addr;
    
    ifp->hello_timer = OSPF_HELLOTIMER;
    ifp->dead_timer = OSPF_ROUTERDEAD;
    ifp->trans_timer = OSPF_TRANSDELAY;
    ifp->poll_timer = OSPF_POLL;
    ifp->retrans_timer = OSPF_RETRANS;
    
    if(!GET_CLAUSE_BEGIN(fp,token)) {
	if(strcmp(token,T_STATEMENT_END)) {
	    error_print(T_ERROR_END_STATEMENT,common_error);	    
	    return 0;
	}
	else {
	    return 1;
	}
    }

    while(!GET_CLAUSE_END(fp,token)) {
	switch(token_type(config_token,token)) {
	case T_CONFIG_HELLO : GET_TOKEN(fp,token,ERRCONF_VALUE);
	  		      ifp->hello_timer = asc_to_int(token);
	    			 break;
	case T_CONFIG_ROUTERDEAD  : GET_TOKEN(fp,token,ERRCONF_VALUE);
				ifp->dead_timer = asc_to_int(token);
	  			break;
	case T_CONFIG_PRIORITY : GET_TOKEN(fp,token,ERRCONF_VALUE);
				ifp->priority = asc_to_int(token);
	  			break;
	case T_CONFIG_MULTICAST : ifp->type = BROADCAST;
				    break;
	case T_CONFIG_STUB : area->type = AREA_TYPE_STUB;
				GET_TOKEN(fp,token,ERRCONF_VALUE);
	    			if(token_type(config_token,token) == T_CONFIG_STUB_COST) {
				    GET_TOKEN(fp,token,ERRCONF_VALUE);
				    area->default_cost = asc_to_int(token);
				}
	    			else {
				    GET_TOKEN(fp,token,ERRCONF_VALUE);
				}
	    			break;
	case T_CONFIG_ROUTERTYPE : GET_TOKEN(fp,token,ERRCONF_VALUE);
	    			 break;
	case T_CONFIG_AUTHTYPE : GET_TOKEN(fp,token,ERRCONF_VALUE);
				area->authtype=token_type(authtype_token,token);
				 GET_TOKEN(fp,token,ERRCONF_VALUE);
	    			if(token_type(config_token,token) == T_CONFIG_AUTHKEY) {
				    GET_TOKEN(fp,token,ERRCONF_VALUE);
	    strcpy((char *)ifp->authkey,token);
				}
	    else {
				    GET_TOKEN(fp,token,ERRCONF_VALUE);
				}
	    break;
	    default		       : return 0;
	}
	END_STATEMENT(fp,token,ERR_END_STATEMENT);
    }

    if(!GET_STATEMENT_END(fp,token)) {
	error_print(T_ERROR_END_STATEMENT,common_error);
	return 0;
    }

    return 1;

}

/*

  ospf_virtual_config

*/
int ospf_virtual_config(fp,rtifp)
FILE *fp;
struct RT_IFCONF *rtifp;
{
    char token[MAX_NUM_CONFIG_CHARACTER];
/*    char value[MAX_NUM_CONFIG_CHARACTER];*/
    struct PROTO_OSPF *ospf,*ospf_conf;
    struct OSPF_AREA *area,*n_area;
    struct OSPF_IF *ifp;
    struct OSPF_NBR *nbr;

    ospf = (struct PROTO_OSPF *)rtifp->proto_info ;
    ospf->vlink++;
    ospf->hello_display = OFF;
    ospf->db_display = OFF;
    ospf->req_display = OFF;
    ospf->up_display = OFF;
    ospf->ack_display = OFF;
    
    for(n_area=ospf->myarea;n_area->next;n_area=n_area->next);
    
    MALLOC(area,OSPF_AREA);
    
    n_area->next = area;

    MALLOC(ifp,OSPF_IF);
    
    area->intf = ifp;
    ifp->ifaddr = rtifp->local_addr;
    ifp->area = area;
    ifp->type = VIRTUAL_LINK;
    ifp->state = IFS_DOWN;
    area->id = BACKBONE_AREA;
    area->authtype = OSPF_AUTHTYPE_NONE;
    area->type = AREA_TYPE_VIRTUAL;
    area->default_cost = OSPF_DEFAULT_COST;
    
    MALLOC(nbr,OSPF_NBR);
    
    ifp->nbr = nbr;
    nbr->intf = ifp;
    nbr->nbr_addr = rtifp->remote_addr;
    
    ifp->hello_timer = OSPF_HELLOTIMER;
    ifp->dead_timer = OSPF_ROUTERDEAD;
    ifp->trans_timer = OSPF_TRANSDELAY;
    ifp->poll_timer = OSPF_POLL;
    ifp->retrans_timer = OSPF_RETRANS;
    
    if(!GET_CLAUSE_BEGIN(fp,token)) {
	if(strcmp(token,T_STATEMENT_END)) {
	    error_print(T_ERROR_END_STATEMENT,common_error);	    
	    return 0;
	}
	else {
	    return 1;
	}
    }

    while(!GET_CLAUSE_END(fp,token)) {
	switch(token_type(config_token,token)) {
	case T_CONFIG_HELLO : GET_TOKEN(fp,token,ERRCONF_VALUE);
	  		      ifp->hello_timer = asc_to_int(token);
	    			 break;
	case T_CONFIG_ROUTERDEAD  : GET_TOKEN(fp,token,ERRCONF_VALUE);
				ifp->dead_timer = asc_to_int(token);
	  			break;
	case T_CONFIG_PRIORITY : GET_TOKEN(fp,token,ERRCONF_VALUE);
				ifp->priority = asc_to_int(token);
	  			break;
	case T_CONFIG_ROUTERTYPE : GET_TOKEN(fp,token,ERRCONF_VALUE);
	    			 break;
	case T_CONFIG_AUTHTYPE : GET_TOKEN(fp,token,ERRCONF_VALUE);
				area->authtype=token_type(authtype_token,token);
				 GET_TOKEN(fp,token,ERRCONF_VALUE);
	    			if(token_type(config_token,token) == T_CONFIG_AUTHKEY) {
				    GET_TOKEN(fp,token,ERRCONF_VALUE);
	    strcpy((char *)ifp->authkey,token);
				}
	    else {
				    GET_TOKEN(fp,token,ERRCONF_VALUE);
				}
	    break;
	    default		       : return 0;
	}
	END_STATEMENT(fp,token,ERR_END_STATEMENT);
    }

    if(!GET_STATEMENT_END(fp,token)) {
	error_print(T_ERROR_END_STATEMENT,common_error);
	return 0;
    }

    return 1;

}

/*

  make_if_mngid

*/
void make_if_mngid(rtifp)
struct RT_IFCONF *rtifp;
{
    struct in_addr tmpaddr;

    bcopy(rtifp->local_addr->addr,&tmpaddr,sizeof(struct in_addr));

    switch(rtifp->protocol) {
    case T_PROTO_BGP :	(void)sprintf(rtifp->mng_id,"BGP_%s",
		      		inet_ntoa(tmpaddr));
    			break;
    case T_PROTO_OSPF : (void)sprintf(rtifp->mng_id,"OSPF_%s",
		      		inet_ntoa(tmpaddr));
    			break;
    default 	      : break;
    }
}


/*

  proto_bgp_dump

*/
void proto_bgp_dump(fp,info)
FILE *fp;
struct proto_bgp *info;
{

    if(fp == NULL) fp = stderr;
    
    log_trace(fp,"	proto mngid = %s\n",info->mng_id);
    log_trace(fp,"	router_id = %s\n",inetaddr_to_char(info->router_id));
    log_trace(fp,"	verions = %d\n",info->version);
    log_trace(fp,"	holdtime = %d\n",info->holdtime);
    log_trace(fp,"	interface = ");
    if_addr_dump(fp,info->myaddr);
    log_trace(fp,"\n	peer = ");
    if_addr_dump(fp,info->peeraddr);
    log_trace(fp,"\n");
}
	    
/*

  proto_ospf_dump

*/
void proto_ospf_dump(fp,info)
FILE *fp;
struct PROTO_OSPF *info;
{

    struct PROTO_OSPF *ospf;
    struct OSPF_AREA *area;
    
    if(fp == NULL) fp = stderr;
    
    for(ospf=info;ospf;ospf=ospf->next) {
	log_trace(fp,"	proto mngid = %s\n",ospf->mng_id);
	log_trace(fp,"	router_id = %s\n",inetaddr_to_char(ntohl(ospf->router_id)));

	for(area=ospf->myarea;area;area=area->next) {
	    log_trace(fp,"	<area>\n");
	    ospf_area_dump(fp,area);
	}
    }
}

/*

  ospf_area_dump

*/
void ospf_area_dump(fp,area)
FILE *fp;
struct OSPF_AREA *area;
{
    struct OSPF_IF *intf;
    struct OSPF_NBR *nbr;
    struct in_addr tmpaddr;

    intf = area->intf;
    nbr = intf->nbr;
    
    bcopy(intf->ifaddr->addr,&tmpaddr,sizeof(struct in_addr));
    
    if(fp == NULL) fp = stderr;
    
    log_trace(fp,"	  area_id = %s\n",inetaddr_to_char(ntohl(area->id)));
    if(area->type == AREA_TYPE_TRANSIT) {
	log_trace(fp,"	  type = Transit \n");
    }
    else if(area->type == AREA_TYPE_STUB) {
	log_trace(fp,"	  type = Stub : cost = %d \n",area->default_cost);
    }
    else if(area->type == AREA_TYPE_VIRTUAL) {
	log_trace(fp,"	  type = Virtual \n");
    }
    log_trace(fp,"	  < interface >\n");
    log_trace(fp,"		addr = %s\n",inetaddr_to_char(ntohl(IF_ADDR(intf->ifaddr))));
    log_trace(fp,"		hello = %d\n",intf->hello_timer);
    log_trace(fp,"		dead = %d\n",intf->dead_timer);
    log_trace(fp,"		trans = %d\n",intf->trans_timer);
    log_trace(fp,"		poll = %d\n",intf->poll_timer);
    log_trace(fp,"	  < neighbor >\n");
    log_trace(fp,"		addr = %s\n",inetaddr_to_char(ntohl(IF_ADDR(nbr->nbr_addr))));
}

/*

  ospf_config_free

*/
void ospf_config_free(proto_info)
byte *proto_info;
{
    struct PROTO_OSPF *ospf;

    ospf=(struct PROTO_OSPF *)proto_info;
    if(ospf->myarea)
	ospf_area_free(ospf->myarea) ;
    if(ospf->backbone)
      ospf_area_free(ospf->backbone);
    free((char *)ospf);
}

/*

  ospf_area_free

*/
void ospf_area_free(area)
struct OSPF_AREA *area;
{
    struct OSPF_IF *intf;
    struct OSPF_NBR *nbr;

    intf = area->intf;
    nbr = intf->nbr;
    
    free((char *)nbr);
    free((char *)intf);
}





