/* 
 * $Id: idrp_init_parse.c,v 1.11 1995/10/08 17:04:49 skh Exp $
 * Merit IDRP release 1.1 (gated 3.5.4).  Copyright (c) 1994 by Merit Network, Inc. 
 */

/* idrp_parse_init.c
 * 
 * routines that handle the parsing and configuration
 * set-up for idrp  
 *
 *  John Scudder, Susan Hares Merit/NSFNET. 
 *
 * idrp_find_peer - find the peer structure
 * idrp_link_peer  - link the peer structure
 * idrp_small_blk_alloc - allocate small block out of allocated memory (not with a task)
 * idrp_med_blk_alloc - allocate medium block out of allocated memory (not with a task)
 * idrp_small_blk_free - free small block of allocated memory (not within a task)
 * idrp_med_blk_fred - free small block of allocated memory (not within a task)
 * idrp_big_blk_free - free peer size block of allocated memory (not within a task)
 * idrp_local_peer_init - initialize the this nodes (local) peer during configuration
 * idrp_local_config_def - initialize the this nodes configuration defaults prior to parsing
 *			   gated.conf file 
 * idrp_peer_preconfig_init - initialize the peer structures before parsing information
 * idrp_timer_copy(peer1, peer2) - copy parameters
 * void idrp_params_copy(peer1,peer2) - copy parameters
 * idrp_delete - delete the peer structure  and relink peer list
 *		      other routines have already turned peer down logically
 * idrp_peer_config_init(peer) - initialize peer configuration values to preset limits 
 * idrp_peer_update(old_peer,peer) - update peer structure from new peer  
 */

#include "include.h"
#include "iso.h"
#include "idrp.h"
#include "inet.h"



/* find the idrp peer among the
 * idrp peer list
 */

idrpPeer *
idrp_find_peer(p_new_peer)
idrpPeer	*p_new_peer;
{
idrpPeer	*peer;
	
	IDRP_LIST(peer, idrp_peers)
		{
		/* if new peer has iso address - look for duplicate ISO address */

		if (p_new_peer->neighbor.isoa_len)
			{
			if (!isoaddrcmp(&peer->neighbor,&p_new_peer->neighbor))
				{
				/* ISO address compare - check RDIs */

				if (!isoaddrcmp(&peer->rdi,&p_new_peer->rdi))
					{
					/* NET and RDI match -  call matched */ 

					if (peer->type == p_new_peer->type)
						{
#ifdef IDRP_QOS	
						if ((peer->nrib_supp == p_new_peer->nrib_supp) 
							&& (compare_peer_ribs(peer,p_new_peer))) 
							{
							return (peer);
							}
#else
						return(peer);
#endif
						}
					}
				}
			}
		
		/* if new peer has ip address - look for duplicate ip address */
	
		if (p_new_peer->ip_neighbor)
			{
			if (!sockaddrcmp2(peer->ip_neighbor,p_new_peer->ip_neighbor))
				{
				/* ip sockaddr address match - try RDI */ 
				if (!isoaddrcmp(&peer->rdi,&p_new_peer->rdi))
					{
					if (peer->type == p_new_peer->type)
						{
#ifdef IDRP_QOS
						if ((peer->nrib_supp == p_new_peer->nrib_supp) 
							&& (compare_peer_ribs(peer,p_new_peer))) 
							{
							return (peer);
							}
#else
						return(peer);
#endif
						}
					}
				}
			}
		} IDRP_LIST_END;

	/* no match for peer */
	peer = (idrpPeer *) 0;
	return(peer);
}


/* link the new idrp peer to the idrp peer
 * list.  List has order of internal peers and
 * test peers first, and then external peers at
 * end. The internal peer peer list is walked 
 * each time we send external changes to
 * internal neighbors.
 */


void
idrp_link_peer(p_peer)
idrpPeer	*p_peer;
{
idrpPeer	*peer;
idrpPeer	*p_last = NULL;
idrpPeer	*p_last_int = NULL;

	if (idrp_peers == NULL)
		{
		/*
		 * nothing on the peer list -initialize it
		 */

		/* list putter and taker 
		 * counts
		 */

		idrp_peers = p_peer;
		idrp_peers_end = p_peer;
		idrp_neighbors = 1;
		idrp_n_established = 0;
		idrp_n_disabled = 0;

		/* now set-up internal portions of lists
		 */

		if (p_peer->type == IDRP_PEER_EXTERNAL)
			{
			idrp_ext_peers = p_peer;
			idrp_ext_neighbors = 1;
			idrp_int_neighbors = 0; 
			idrp_last_int_peer = NULL; 
			}
		else
			{
			idrp_int_neighbors = 1; 
			idrp_last_int_peer = p_peer; 
			idrp_ext_peers = (idrpPeer *) 0;
			idrp_ext_neighbors = 0;
			}
		p_peer->id = idrp_neighbors - 1;
		return;
		}
			
	/*
	 * if we run over the neighbors - stop 
	 * the process
	 */
 
	if (idrp_neighbors > IDRP_MAX_PEERS)
		{
		trace_log_tf(idrp_trace_options, 0, LOG_ERR, ("over maximum number of peers we won't add more")); 
		task_quit(0);	
		}

	if (idrp_int_neighbors && idrp_last_int_peer == NULL )
		{		
		trace_log_tf(idrp_trace_options, 0, LOG_ERR, ("internal error - internal neighbors idrp_link_peer %d %x",
				idrp_int_neighbors,idrp_last_int_peer)); 
		task_quit(0);
		}	


	switch (p_peer->type)
		{
		case IDRP_PEER_INTERNAL:
		case IDRP_PEER_TEST:
			if (idrp_int_neighbors == 0 )
				{
				idrp_last_int_peer = p_peer;
				if (idrp_ext_neighbors)
					{
					p_peer->p_next = idrp_peers;
					idrp_peers->p_prev = p_peer; 
					}
				else
					{ 
					assert(idrp_peers == NULL);
				  	idrp_peers_end = p_peer; 	
					}
				idrp_peers = p_peer;
				}
			else
				{ 
				/* insert prior to external peers
				 */
		
				if (idrp_ext_neighbors == 0)
					{
					/* make sure pointers are OK
					 */
					assert(idrp_peers_end == idrp_last_int_peer);
				  	idrp_peers_end = p_peer; 	
					}	
				
				p_peer->p_next = idrp_last_int_peer->p_next;
				p_peer->p_prev = idrp_last_int_peer;
				idrp_last_int_peer->p_next = p_peer;
				idrp_last_int_peer = p_peer;
				}

			idrp_int_neighbors++;
			idrp_neighbors++;

			break;
	
		case IDRP_PEER_EXTERNAL:
			assert(idrp_peers_end!= NULL); 
			idrp_peers_end->p_next = p_peer;
			p_peer->p_prev = idrp_peers_end;  
			idrp_peers_end = p_peer;	
			p_peer->p_next = (idrpPeer *) 0;
			if (!idrp_ext_peers)
				{
				idrp_ext_peers = p_peer;
				}
			idrp_ext_neighbors++;
			idrp_neighbors++;
			break;
		}

	p_peer->id = idrp_neighbors-1;
}
	
				
u_char *
idrp_big_blk_alloc()
{
u_char *p;
	
	if (!idrp_big_block_index) {
		idrp_big_block_index = task_block_init(IDRP_BIG_BLOCK_SIZE, "BIG_BLOCK");
	}

        if (idrp_big_block_index == NULL)
	  trace_log_tf (idrp_trace_options, 0, LOG_ERR, ("*********** IDRP BIG BLK ALLOC FAILED *******"));

	p = task_block_alloc(idrp_big_block_index);

return (p);
}

/* allocate a small idrp task block structure 
 * (alias baby bear idrp allocate)
 * These blocks are created by the parsing routines
 * in the configuration to store local route information
 * that does not have a task to look after it.
 * This is the small size used for:
 *  - idrpRoutes for local routes
 *  - rd_path structure
 *  - route_list_entry structure   
 */

u_char *
idrp_small_blk_alloc()
{
u_char	*p_baby_bear;
	if (!idrp_small_blk_index) {
		idrp_small_blk_index = task_block_init(IDRP_SMALL_BLOCK_SIZE, "IDRP_SMALL_BLOCK");
		}

        if (idrp_small_blk_index == NULL)
	  trace_log_tf (idrp_trace_options, 0, LOG_ERR, ("*********** IDRP SMALL BLK ALLOC FAILED *******"));

        p_baby_bear = task_block_alloc(idrp_small_blk_index);

return(p_baby_bear);
}

u_char *
idrp_huge_blk_alloc()
{
u_char	*p_block;
	if (!idrp_huge_blk_index) {
		idrp_huge_blk_index = task_block_init(IDRP_HUGE_BLOCK_SIZE, "IDRP_HUGE_BLOCK");
		}

        if (idrp_huge_blk_index == NULL)
	  trace_log_tf (idrp_trace_options, 0, LOG_ERR, ("*********** IDRP HUGE BLK ALLOC FAILED *******"));

        p_block = task_block_alloc(idrp_huge_blk_index);

return(p_block);
}

/* free a small idrp task block structure 
 *
 * - free the small block
 */
void 
idrp_small_blk_free(p)
u_char *p;
{
	task_block_free(idrp_small_blk_index,p); 
}


/* allocate a medium size task block 
 * (alias mama bear)
 * 
 * This blocks are medium size used by parsing routines 
 * - only attribute block uses this size right now
 */
 
u_char *
idrp_med_blk_alloc()
{
u_char	*p_mama_bear;

	if (!idrp_med_blk_index) {
		idrp_med_blk_index = task_block_init(IDRP_MEDIUM_BLOCK_SIZE, "IDRP_MEDIUM_BLOCK");
		}

        if (idrp_med_blk_index == NULL)
	  trace_log_tf (idrp_trace_options, 0, LOG_ERR, ("*********** IDRP MED BLK ALLOC FAILED *******"));

	p_mama_bear = (u_char *) task_block_alloc(idrp_med_blk_index);

return(p_mama_bear);
}	
			
/* free a medium idrp task block structure 
 *
 * - free the medium block
 */
void 
idrp_med_blk_free(p)
u_char *p;
{
	task_block_free(idrp_med_blk_index,p); 
}


/* free the big block set for peer 
 *
 */
 

void 
idrp_big_blk_free(p)
u_char *p;
{
	task_block_free(idrp_big_block_index,p);
}


/* free the huge block set 
 *
 */

void 
idrp_huge_blk_free(p)
u_char *p;
{
	task_block_free(idrp_huge_blk_index,p);
}


/* initialize variables at idrp_init time 
 * idrp_local_config_init - configures the default
 * values for parameters prior to conf file parsing
 */


void 
idrp_local_peer_init()
{
static char local_name [] = "local_node";
u_short hold;
int	len = 0;
idrp_attribute_record 	*p_att;
idrpPeer		*peer;
rdpath_list *p_rd_pl;
int	rib_id = 0;
int	rdpath_changed = 0; 

	/* set-up the peer structure */

	idrp_this_node.p_next = (idrpPeer *) 0;
	idrp_this_node.type = IDRP_PEER_LOCAL;
	bcopy(&local_name,&idrp_this_node.name,sizeof(local_name));

	/* set-up the gateway entry for this peer */
	/* sockaddr for interface will need to wait until idrp_init time */

	idrp_this_node.gw.gw_proto =  RTPROTO_IDRP;
	idrp_this_node.iso_gw.gw_proto = RTPROTO_IDRP;
	idrp_this_node.iso_gw.gw_addr = (sockaddr_un *) &idrp_this_node.iso_intf_addr;
	idrp_this_node.idrp_import = control_exterior_locate_rdi(idrp_import_list,&rt_rdi);

#ifdef	IDRP_QOS
	idrp_this_node.qos_poll_time = IDRP_QOS_POLL_TIME; 
#endif	/* IDRP_QOS  */

	/*  
	 * set the Maximum send pdu size for the local peer
	 * out of the maximum pdu receive size for all peers
	 *
	 */

	IDRP_LIST (peer, idrp_peers)
		{
		if (peer->pdu_maxrcvsize > len)
			{
			len = peer->pdu_maxrcvsize;
			}
		} IDRP_LIST_END;

	idrp_this_node.pdu_maxsendsize = len;

	/* if rt_ip_net is not set, pick up a net's 
	 * from the local interface addresses
	 */

	if (rt_ip_net_cnt == 0)
		{ 
		IDRP_LIST(peer,idrp_peers)	
                      {
                        /* find the first iso interface and use
                         * - as NET for next hop
                         */

                        if (peer->ip_intf_addr != (sockaddr_un *) NULL)
				{
				int len_1;
				len_1 = rt_ip_net[0].in.sin_len = peer->ip_intf_addr->in.sin_len;
				rt_ip_net[0].in.sin_family = peer->ip_intf_addr->in.sin_family;
				rt_ip_net[0].in.sin_port = peer->ip_intf_addr->in.sin_port;
				bcopy(&peer->ip_intf_addr->in.sin_addr,&rt_ip_net[0].in.sin_addr,len_1);
				break;
				}
			} IDRP_LIST_END;
                }

		
	
	/* set the inteface address for the iso node */
	
	idrp_set_local_iso_intf_addr();	

	/* set up neighbor clause for tie break compares
	 * - we are using first of the local node NETs for
	 * - tie breaking comparisons
	 * 
	 */

	bcopy(&rt_net[0],&idrp_this_node.neighbor,sizeof(struct iso_net_addr));
	
       /* set-up local rd_path for local routes
	* total segement = segement path header length (3 bytes)
	*      + rdi length + 1 byte for RDI length 
	* - segement path = length + length of RDI 
 	* - segment type - sequence
	*/

        len = rt_rdi.isoa_len + (sizeof(idrp_path_segment_header)) + RDI_LENGTH_BYTE_LEN;

	/* here's the local Segment path length - RDI plus one length byte
	 */
 
	local_rd_path.rd_header.path_seg_type = IDRP_PATH_SEGMENT_SEQ;
	hold = rt_rdi.isoa_len + RDI_LENGTH_BYTE_LEN;	
	hold = htons(hold);
       	bcopy(&hold,&local_rd_path.rd_header.path_seg_len,sizeof(local_rd_path.rd_header.path_seg_len));
	trace_tf (idrp_trace_options, TR_NORMAL,0, ("local_rd_path length = %d  = %x",hold,local_rd_path.rd_header.path_seg_len));
	bcopy(rt_rdi.isoa_genaddr,local_rd_path.rdi.isoa_genaddr,rt_rdi.isoa_len);
	local_rd_path.rdi.isoa_len = rt_rdi.isoa_len;

	/* we set everything to into attribute except the length for
	 * the local rd path without knowing the RDI.  So 
	 * set it now that the parsing has finished
	 */
 	/* set-up the rdi in the global rdi list 
	 */
 
	if (p_rt_rdi == NULL)
		{
		p_rt_rdi =(rdi *) idrp_local_mem_fit(sizeof(rdi));
		bcopy(&rt_rdi,&p_rt_rdi->rdi,sizeof(struct iso_net_addr));
		p_rt_rdi->refcnt = 1;
		p_rt_rdi = idrp_insert_global_rdi(&p_rt_rdi); 
		}
	else if (isoaddrcmp(&p_rt_rdi->rdi,&rt_rdi))
		{
		/* if non-zero - then the global rdi
		 * has changed
		 */

		idrp_free_global_rdi(p_rt_rdi);
		p_rt_rdi =(rdi *) idrp_local_mem_fit(sizeof(rdi));
		bcopy(&rt_rdi,&p_rt_rdi->rdi,sizeof(struct iso_net_addr));
		p_rt_rdi->refcnt = 1;
		p_rt_rdi = idrp_insert_global_rdi(&p_rt_rdi); 
		}   
		

	/* set-up my local rdi path in global rdi pathway
	 * - if it is not created, create it
	 * - it will remain the same since the pointer to
	 *   the local rdi will remain the same
	 *   fixed at p_rt_rdi value 1st assign.
	 *   
 	 *   The rdi value within will change
	 *   and the order within the rdis will change too! 
	 */

	if (p_my_rdpath == (rdpath_list *) NULL)
		{
		flag_t	segtype = IDRP_PATH_SEGMENT_SEQ;
		p_rd_pl = idrp_create_rdpath_list(segtype,p_rt_rdi); 
		p_my_rdpath = idrp_insert_global_rdpaths(p_rd_pl);
		rdpath_changed = TRUE;
		}
	else if (p_my_rdpath->p_start->rdi_list.p_rdi_array[0] != p_rt_rdi)
		{
		/* reconfiguring and my rdi has changed in the path
		 */
 
		flag_t	segtype = IDRP_PATH_SEGMENT_SEQ;
		idrp_free_rdpath(p_my_rdpath);
		p_rd_pl = idrp_create_rdpath_list(segtype,p_rt_rdi); 
		p_my_rdpath = idrp_insert_global_rdpaths(p_rd_pl);
		rdpath_changed = TRUE;
		}
	

	/* we set everything to into attribute except the length for
	 * the local rd path without knowing the RDI.  So 
	 * set it now that the parsing has finished
	 */
 

	QOS_RIB_LIST(rib_id)
	{
	  ATTR_LIST(p_att,rib_id)
		{
		if (p_att->local_mask & IDRP_LOCAL_RDPATH_RESET_LENGTH)  
			{
			p_att->attrib[IDRP_ATTR_RD_PATH].length = len;
			if (rdpath_changed)
				{
				p_my_rdpath->refcnt++;
				}
			p_att->p_rd_opath = p_my_rdpath;
			}
		} ATTR_LIST_END;
	}
	QOS_RIB_LIST_END;

	/* one more local attribute thing - set the local hop count to zero */
	local_hop_count = 0;	
}     

/* initialize local peer variables
 */

void 
idrp_local_config_def()
{

	/* hack for now - until I get parser working  */ 
	idrp_this_node.nlri_supp[IDRP_NLRI_IP] = TRUE;
	idrp_this_node.nlri_supp[IDRP_NLRI_ISO] = TRUE;
	idrp_this_node.type = IDRP_PEER_LOCAL;

	/* default to IP socket in  configuration */
	idrp_this_node.proto_sock = IDRP_PDU_PROTO_IP_RAW;
	idrp_this_node.Capacity = IDRP_CAPACITY_VALUE_MIN;
	idrp_this_node.config_options = IDRP_CNF_OPT_DEFAULT; 
	idrp_this_node.listen_for_open = TRUE;

	/* set timers to default values */

	idrp_this_node.max_rib_integ_check = IDRP_RIB_CHECK_TIME_DEF;
	idrp_this_node.hold_time = IDRP_HOLD_TIME;
	idrp_this_node.close_wait = IDRP_CLOSE_WAIT_TIME;
	idrp_this_node.rexmit_time = IDRP_REXMIT_TIME;
	idrp_this_node.closestay = IDRP_CLOSE_STAY_TIME;
	
}

/*
 *      Delete a peer and all associated structures
 */

void 
idrp_delete(peer)
idrpPeer *peer;
{
idrpPeer *peer2,*peer3;
idrpAdvRt	*p_adv,*p_adv_next;


   /* find out who tries to delete an empty peer */

	assert(peer != NULL);

    /* move relink idrp_peers chain */

	switch(peer->type)
		{
		case IDRP_PEER_INTERNAL:
		case IDRP_PEER_TEST:
			{
			if (peer == idrp_last_int_peer)
				{
				idrp_last_int_peer = peer->p_prev;
    				}
			idrp_int_neighbors--;
			}
			break;

		case IDRP_PEER_EXTERNAL:
			{
			/* fix internal peer & external */
			idrp_ext_neighbors--;
			if (idrp_ext_peers == peer)
				{
				idrp_ext_peers = peer->p_next;
				}		
			}
			break;
		}

	if (peer == idrp_peers)
		{
		idrp_peers = peer->p_next;
		idrp_peers->p_prev = NULL;
		}
	else 	
		{ 
		if (peer->p_prev)
			{	 	
			peer->p_prev->p_next = peer->p_next;
			}
		if (peer->p_next)
			{
			peer->p_next->p_prev = peer->p_prev; 
       		     	}
		}

	if (peer == idrp_peers_end)
		{
		idrp_peers_end = peer->p_prev;
		}	 

        idrp_neighbors--;

	/* free up any SNPA lists that might be there */

	idrp_free_snpa_list(&peer->snpa);

	/* free up any ext_info information for external routes for a peer */

	if (peer->p_ext_info)
		{
		idrp_free_opts(peer->p_ext_info);	
		}

	/* free up any local_info information for external routes for a peer */

	if (peer->p_ext_info)
		{
		idrp_free_opts(peer->p_local_info);	
		}

	/* free ip and iso gw sockaddr structures
	 */

	if (peer->gw.gw_addr != (sockaddr_un *) NULL)
		{
		sockfree(peer->gw.gw_addr);
		}


	if (peer->p_local_iso_gw)
		{
		IDRP_MEM_FIT_FREE(peer->p_local_iso_gw);
		}

	if (peer->p_minadvRD_head)
 		{
 		/* 
 		 */
 
 		for (p_adv = peer->p_minadvRD_head; p_adv; p_adv = p_adv_next)
 			{
 			p_adv_next = p_adv->p_next;
 			IDRP_MEM_FIT_FREE(p_adv);
 			}  
 		}

	/* free the min_adv structure */  
 
	if (peer->p_minadv_head)	
 		{
 
 		for (p_adv = peer->p_minadvRD_head; p_adv; p_adv = p_adv_next)
 			{
 			p_adv_next = p_adv->p_next;
 			IDRP_MEM_FIT_FREE(p_adv);
 			}  
 		}
 
 
 	/* at last free the idrp peer structure
 	 */	

	IDRP_MEM_FIT_FREE(peer);
}

void
idrp_peer_config_reinit(peer)
idrpPeer	*peer;
{
	/* reinit the policy strutures
	 */

	/* SJR fix on 1 June 95 */
	peer->idrp_import = control_exterior_locate_rdi(idrp_import_list,
		&peer->rdi);
	
	peer->idrp_export = control_exterior_locate_rdi(idrp_export_list,
		&peer->rdi);
}

void
idrp_peer_config_init(peer)
idrpPeer *peer;
{
	/* configuration default setting on peer
	 * parsing sets up - peer list, type of peer, address of neighbor,
	 */ 

	peer->version = 1;
	peer->AuthType = IDRP_AUTH_CODE_CLEAR;
	peer->nlri_supp[IDRP_NLRI_ISO] = AF_ISO;	/* osi support */
	peer->nlri_supp[IDRP_NLRI_IP] = AF_INET;	/* ip support */

	if (peer->pdu_maxrcvsize ==0 || peer->pdu_maxrcvsize > IDRP_PKTSIZE )
		{
		/* set to global default */

		peer->pdu_maxrcvsize = IDRP_PKTSIZE;
		}

        /* the following values are set to zero by peer structure clear
         * and that is the default
         * snpa, expense, maxcpu (cpu_overload_time), min_adv_time,
         * min_advRD_time
         * multi-exit - set to default of no by parser
         * priority - set to zero
         * rdlre - set to zero
         *  hold, rexmit_time, closewait, closestay timers set below
         * route-server - defaults to no
         * as_rdi - set to zero as default
         * listen open - defaults to TRUE, but set in config_preinit
         */

	/* default timers */

        if (peer->hold_time == 0)
                {
                peer->hold_time = IDRP_HOLD_TIME;
                }
        if (peer->rexmit_time == 0)
                {
                peer->rexmit_time = IDRP_REXMIT_TIME;
                }
        if (peer->closestay == 0)
                {
                peer->closestay = IDRP_CLOSE_STAY_TIME;
                }
        if (peer->close_wait == 0)
                {
                peer->close_wait = IDRP_CLOSE_WAIT_TIME;
                }


	/* set up the gated gateways so that we can configure the
	 * tasks
	 * - set up an IP gateway and an ISO based gateway
	 * so I can get the deletes through gated
	 */

	peer->gw.gw_proto = peer->iso_gw.gw_proto = RTPROTO_IDRP;
	if (peer->proto_sock == IDRP_PDU_PROTO_IP_RAW)
		{
		peer->gw.gw_addr->in.sin_port = 0;
		}
	else
		{
		peer->gw.gw_addr->in.sin_port = IDRP_PORT;
		}
	/* temporary hack until we get neighbor aligned */

	peer->iso_gw_addr = peer->neighbor;
	peer->iso_gw_addr.isoa_len += 2; 
	
	/* skh fix 8/1/93 *************/
	peer->iso_gw.gw_addr = (sockaddr_un *) &peer->iso_gw_addr;
	
	/* SJR fix on 1 June 95 */
	peer->idrp_import = control_exterior_locate_rdi(idrp_import_list,
		&peer->rdi);
	
	peer->idrp_export = control_exterior_locate_rdi(idrp_export_list,
		&peer->rdi);

	/* chl addition 6/6/94 *********/
	peer->gw.gw_rtq.rtq_forw = peer->gw.gw_rtq.rtq_back
	  = &(peer->gw.gw_rtq);

	peer->iso_gw.gw_rtq.rtq_forw = peer->iso_gw.gw_rtq.rtq_back
	  = &(peer->iso_gw.gw_rtq);

	peer->listen_for_open = TRUE;
}


void 
idrp_peer_preconfig_init(peer)
idrpPeer	*peer;
{
	/* we must pre-set multi-exit to negative
	 * - since zero is a legal value
	 */
 

	/* set TRUE values as default 
	 */

	peer->listen_for_open = TRUE; 
}

void 
idrp_peer_update(peer_old,peer)
idrpPeer	*peer_old;
idrpPeer	*peer;
{

	/* copy in the current peer NET and status from
	 * the new structure to the old
	 * - copy in the whole structure of the iso NET 
	 * - copy in the pointer to the IP address
	 * - copy in the whole RDI structure
	 */
 
	
	bcopy(&peer->neighbor,&peer_old->neighbor,sizeof(struct iso_net_addr));
	peer_old->ip_neighbor = peer->ip_neighbor;
	bcopy(&peer->rdi,&peer_old->rdi,sizeof(struct iso_net_addr));


	/* The flags and protocol socket need special handlign
	 *  1) status of neighbor (idrp_flags)
	 *	Unconfigured: should be illegal
	 *
	 * 	DELETED  - set in idrp_cleanup,
	 *		use the new flags
	 *		re-use peer session
	 *	TRY_CONNECT - set in parser.y 
	 *		use the new flags
	 * 	CONNECT - peer is still connected??
	 *		  set as connected to remote peer before re-config
	 *		  try to keep it going if
	 *		  Or in the new flags 
	 *		  
	 *	WRITEFAILED - peer failed on socket write 
	 *		Use the new flags
	 *
	 *	IDLE - set to disable peer in last config 
	 *		use new flags
	 *
	 * if connect flag set, or in the protocol socket
	 */ 
 
	if (peer_old->idrp_flags & IDRPF_CONNECT)
		{
		/* or in the connect flags */
		peer_old->idrp_flags = IDRPF_CONNECT | peer->idrp_flags;
		idrp_n_established++;
		}
	else
		{
		/* if not connected, just use new flags */
	 
		peer_old->idrp_flags = peer->idrp_flags;
		}

	/* copy last protocol socket open to old_proto_sock 
	 * get new configured one in proto_sock 
	 */ 

	peer_old->last_proto_sock = peer_old->proto_sock;
	peer_old->proto_sock = peer->proto_sock;
	peer_old->refresh_flags = peer->refresh_flags;
}

void
idrp_is_new_rdi(p_str,len)
u_char *p_str;
int	len;
{
struct	iso_net_addr test_addr;

		 
	bcopy(p_str,&test_addr.isoa_genaddr[0],len);
	test_addr.isoa_len = len; 	

	if (rt_rdi.isoa_len != 0 && (isoaddrcmp(&rt_rdi,&test_addr) != 0)) 
		{
		/* this rdi change - so we will need to drop the 
		 * all the connections and reset all rdi paths
		 */
 
		idrp_rdi_change = TRUE;
		}
	else
		{
		idrp_rdi_change = FALSE;
		} 
	
	bcopy(p_str,&rt_rdi.isoa_genaddr, len);
	rt_rdi.isoa_len = len;
	trace_tf (idrp_trace_options, TR_NORMAL, 0, ("rdi xxxx configured for idrp %A ", 
      		sockbuild_iso((byte *) rt_rdi.isoa_genaddr, rt_rdi.isoa_len)));
	rt_as_rdi.isoa_len = len - 2;
       	bcopy(p_str,&rt_as_rdi.isoa_genaddr,rt_as_rdi.isoa_len);
       	rt_as_rdi.isoa_family = AF_ISO;
        trace_tf (idrp_trace_options, TR_NORMAL,0, ("idrp finished call to rdi in parser.y"));
}


void
idrp_route_cleanup()
{
#ifdef IDRP_QOS

	idrp_rib_cleanup();

#else
	idrp_free_attr_list(idrp_attr_list);
	idrp_free_oatt_list(idrp_oatt_list);	
#endif



}

int
idrp_rib_set(p_opt)
idrpRoute_options *p_opt;
{

/* check to see if the route option have no ribs --
 *  -- if so set the default rib
 */

 
	if (p_opt->p_qos == NULL)
		{
		p_opt->rib_id = RIB_ID_DEFAULT;
		return(TRUE);
               	}
	else
		{
		/* qos values set in the distinguished attributes
		 */
	
#ifdef  IDRP_QOS
		p_opt->rib_id = rib_supported(p_opt->p_qos);
		if (p_opt->rib_id == 0)
			{
			return(FALSE);
			}
				
		/* if QOS rib 
		 */

		p_opt->p_qos->rib_id = p_opt->rib_id;
		return(TRUE);
#else
		return(FALSE);
#endif /* IDRP_QOS */

		}
}	


