/* 
 * $Id: idrp_rt_local.c,v 1.14 1995/10/31 17:13:42 skh Exp $ 
 * Merit IDRP release 1.1 (gated 3.5.4).  Copyright (c) 1994 by Merit Network, Inc. 
 */

#include "include.h"
#include "parse.h"
#include "iso.h"
#include "idrp.h"

/* 
 *  local routes configured by IDRP
 *
 * %% local routes set-up routines
 *
 * idrp_add_local_rt_gated(p_idrp_rt) - add local route to gated
 *
 * idrp_local_rt(nlri,family) -
 *      add new local route to peer and gated
 *              1.) att_record created non exists this_node
 *              2.) create idrpRoute
 *              3.) fill idrpRoute structure
 *              4.) link to att_record route list
 *
 *
 * idrp_find_local_dest- find local route with same destination and options
 * local_gw_match - match the local gateway 
 *
 *
 * find_local_att_rec - find a local attribute record with attributes
 *			for task level attribute,  
 * 			parsed routes are check in create_local_attr_record	
 *			as attribute record is created
 *
 * idrp_fill_local_man_attrib(p_atts) - fill attribute array with local mandatory attributes
 * idrp_fill_local_opt_attrib (p_att) - fill attribute array with local optional attributes
 * fill_next_hop - fill next hop portion of attribute array
 * fill_DIST_LIST - fill DIST_LIST portion of attribute array
 * (fill * functions are only for local attributes which lack a pdu)
 * create_local_rd_path - create local RD_PATH attribute for local route
 * create_local_snpa_entry - create local 
 * 
 * fill_next_hop(p_atts,p_opts)
 * fill_DIST_LIST(p_atts,p_rd,type)
 * create_local_rd_path - create a local pathway
 * idrp_create_local_gw(p_gw_str,gw_byte_cnt,family)
 * create_local_snpa_entry(p_snpa_list,len,ptr) - create local snpa_entry for list
 *
 *  
 * idrp_local_route_reset - reset all local routes prior to re-parsing
 * idrp_flag_local_att - flag routes associated for one attribute  
 * idrp_local_route_clean - cleanup routes after reparsing to 
 *			    get of any local routes not reconfigured 
 * idrp_local_clear_reconfig - clear reconfig flag after initialization  
 * 
 * idrp_free_local_att - free local attribute record 
 * idrp_flag_local_att - flag routes under local attribute for reconfiguration
 * idrp_clean_local_att(p_att) - clean up one attribute after reparsing
 * clean_local_route_chain(p_rte) - clean up a local route chain after
 *					 reconfiguration 
 *   
 * idrp_free_local_idrpRoute_ent(p_rte)
 * idrp_free_local_rt(p_idrp_rt)
 * idrp_free_local_route_chain(p_idrp_rtl) -
 *      free the local route chain associated with
 *      this route id;

 * 
 * idrp_local_free_rdi_path - free local memory rdi_canon list
 * idrp_local_mem_fit - allocate memory out of the righ
 *			local memory size(small, medium, large
 *			just like the 3 bears)
 * 
 * rdi_canon_length - length of turning rdi chain to DIST_LIST_INCL
 */

/* %% local RD routines */

/* idrp_add_local_rt_gated(p_idrp_rt
 * - add local route to gated table during initialization
 *   or re-init
 */

extern int 
idrp_add_local_rt_gated(p_idrp_rt)
idrpRoute	*p_idrp_rt;
{
struct iso_net_addr	dest;                   /* destination address for gated Route search */
struct iso_net_addr	mask;                   /* mask for gated table Route search */
idrp_rt_chain_walk      gateway;                /* chain for route locate search for gateway */
idrp_rt_chain_walk      preference;             /* chain for route locate serach for perference */
idrpRoute		*p_best_ext = 0;
sockaddr_un		*p_dest;
sockaddr_un		*p_mask;


	
	trace_tf (idrp_trace_options, TR_NORMAL,0, ("nlri %s local route should not be added this way!!! idrp_add_local_rt_gated ",
		iso_ptoa(&p_idrp_rt->nlri)));

	return(FALSE);


/* 
 * SJR--the above two lines [trace_tf, return] are tracing lines 
 * added per SKH.
 */
        /* add the route - warn if another route from gateway is there
         * calculates idrp preference in the routine
         */

	p_dest = (sockaddr_un *) &dest;
        idrp_add_route_locate(p_dest,p_idrp_rt,&gateway,&preference,&p_best_ext);

        if (gateway.p_rt)
                {
                /* problem - gateway has same value */
                return (FALSE);
                }
        if (preference.p_rt)
               {
                /* preference matches */
                /* add one to this node */
                p_idrp_rt->pref_cal++;
                }

	/* Now we add the route to the best external routes chain.  We do this even though
	 * static/local is not actually an external route, because we want the locally 
	 * configured routes to prevent _real_ BERs from being injected into IIDRP.  This
	 * is basically a kludge -- the problem we're kludging around is that 10747 doesn't
	 * expect local routes to be injected into IIDRP (ever) because IIDRP is just for
	 * hauling _external_ routing around.  Oh well.
	 */

	insert_in_pref_order(p_idrp_rt, p_best_ext);
	
	return(idrp_add_rt_to_gated(p_idrp_rt,p_dest));
}



/* 
 * idrp_local_rt - set up local routes into
 *  		   appropriate routing structures
 */

int 
idrp_local_rt __PF8(p_nlri_str, u_char *, 
		    byte_cnt, int,
		    bit_cnt, int,
		    family, int,
		    p_gw_str, u_char *,
		    gw_byte_cnt, int,
		    opts, int,
		    p_in_opts, idrpRoute_options *)
{
rt_entry	*p_rt;				/* gated route entry */
rt_entry	*p_rt2;				/* gated route entry */
idrpRoute	*p_idrp_rt_old;			/* pointer to old route */
int		pref;				/* preference for gated */
idrpRoute	*p_idrp_rt,*p_irt;
idrpRoute_entry	*p_rtl = (idrpRoute_entry *) NULL; 
sockaddr_un	*p_next_hop;
idrp_attribute_record	*p_atts,*p_atts_old;
int			nlri_id;
idrpRoute_options	*p_opts;

	if (idrp_local_route_cnt > IDRP_MAX_LOCAL_ROUTES)
		{
		return(FALSE);
		}

	/* right now the options will either be
	 * - zero - to be local info
	 * - set p_opts to set the exterior flag
	 * 
	 * The p_opts structure pointer has been left set to
	 * -   
	 */

	switch(opts) {
		case (IDRP_LOCAL_EXTERIOR_OSISTATIC):
			p_opts = idrp_this_node.p_ext_info;
			break;

		case (IDRP_LOCAL_STATIC):
			p_opts = idrp_this_node.p_local_info;
			break;

		case (IDRP_LOCAL_SPECIAL_STATIC):
			if (!p_in_opts) {
        			trace_tf(trace_global,
                			TR_PARSE,
                			0,
                			("No idrpRoute_options passed to idrp_local_rt()!"));
				exit(-1);
			}
			p_opts = p_in_opts;
			break;

		default:
        		trace_tf(trace_global,
               	 		TR_PARSE,
                		0,
                		("Unrecognized value of 'opts' of idrp_local_rt():  %d", opts));
			exit(-1);
	}

	/* see if this location was configured once before
	 * - if the p_ext_info or p_local_info have
	 *   been reconfigure - then the match will
	 *   not occur, since the pointer to the options will have changed
	 * 
	 * - if the gateway fails - it has changed and we need a new attribute     
	 */

	p_idrp_rt = idrp_find_local_dest(p_nlri_str,byte_cnt,bit_cnt,family,p_gw_str,gw_byte_cnt,p_opts);	

	/* we got a match - so we are reconfiguring an existing route
	 */
 
	if (p_idrp_rt)
		{
		IDRP_STATUS_BIT_CLEAR(p_idrp_rt,IDRP_STATUS_RECONFIGURE);
		IDRP_STATUS_BIT_TEST(p_idrp_rt,IDRP_STATUS_LOCAL_DAMP_DEL)
			{
			trace_tf (idrp_trace_options, TR_NORMAL,0, ("nlri %s local route is damped and deleting - awaiting min adv",
				iso_ptoa(&p_idrp_rt->nlri)));

			IDRP_STATUS_BIT_SET(p_idrp_rt,(IDRP_STATUS_LOCAL_PH3_NEW_ROUTE | IDRP_STATUS_MIN_ADV_CHG));
			}  	
		return;
		}	
	
	/* No, so go off to try to create the locate attribute record or
	 * gateway 
	 */ 

	p_next_hop = idrp_create_local_gw(p_gw_str,gw_byte_cnt+2,family);

	p_atts = create_local_att(p_opts,p_next_hop,(IDRP_LOCAL_RDPATH_RESET_LENGTH | IDRP_LOCAL_NO_PDU),RIB_ID_DEFAULT); 	
	p_atts_old = find_attr_rec(p_atts);
	if (p_atts_old)
		{
		idrp_free_local_att(p_atts);
		p_atts = p_atts_old;
		}
	else
		{
		link_att_list(p_atts);
		}

		
	/* set-up idrpRoute structure */ 

	p_idrp_rt = (idrpRoute *) idrp_local_mem_fit(sizeof(idrpRoute)); 
	idrp_local_route_cnt++;
	bzero(p_idrp_rt,sizeof(idrpRoute));

	/* set the local variables 
	 * type of memory this is allocated from 
	 * nlri, route_id, links to next route, peer structure 
  	 * calculate the idrp preference
	 */ 

	bcopy(p_nlri_str,&p_idrp_rt->nlri.pfx,byte_cnt);
	p_idrp_rt->nlri.pfx_len = bit_cnt;	
	p_idrp_rt->p_attr = p_atts;
	p_idrp_rt->route_id_in = IDRP_LOCAL_ROUTE_ID;
	p_idrp_rt->p_next_nlri = (idrpRoute *) 0;
	p_idrp_rt->peer = &idrp_this_node;
	p_idrp_rt->pref_rcvd = 0;
	p_idrp_rt->family = family;
	p_idrp_rt->status =  IDRP_STATUS_LOCAL_NEW_ROUTE;
	p_idrp_rt->p_loc_rt_peer = (sockaddr_un *) idrp_local_mem_fit(sizeof(sockaddr_un));
	bcopy(p_gw_str,&p_idrp_rt->p_loc_rt_peer->iso.siso_addr,gw_byte_cnt);	 
	p_idrp_rt->p_loc_rt_peer->iso.siso_len = gw_byte_cnt + 2 ;	
	p_idrp_rt->p_loc_rt_peer->iso.siso_family = AF_ISO;
	
	/* set-up link between attribute and route structure */  
				
	nlri_id = family_to_nlri_id(family);
	p_atts->ref_cnt++;

	/* link into nlri chain off this route id for
	 * this attribute record
	 * - if head, add to tail
	 */

	if (p_atts->route_id_list->p_route[nlri_id])
		{
		p_atts->route_id_list->p_route_tail[nlri_id]->p_next_nlri = p_idrp_rt;
		p_atts->route_id_list->p_route_tail[nlri_id] = p_idrp_rt;
		p_atts->route_id_list->status |= IDRP_ATTR_ROUTE_ID_OSILOCAL;
		}
	else
		{
		/* set up the head and tail */

		p_atts->route_id_list->p_route[nlri_id] = p_idrp_rt;
		p_atts->route_id_list->p_route_tail[nlri_id] = p_idrp_rt;
		}

return(TRUE);
}

idrpRoute *
idrp_find_local_dest(p_nlri_str,byte_cnt,bit_cnt,family,p_gw_str,gw_byte_cnt,p_opts)	
u_char	*p_nlri_str;
int	byte_cnt;
int	bit_cnt;
int family;
u_char	*p_gw_str;
int	gw_byte_cnt;
idrpRoute_options	*p_opts;
{
 /* walk the idrp_attr_list until the end of the local attribute
  * to find the idrp_route structure
  */
int			i;
idrp_attribute_record	*p_att;
struct iso_prefix	dest;
idrpRoute		*p_irt;
idrpRoute_entry		*p_rte;
int			rib_id = p_opts->rib_id;

	bcopy(p_nlri_str,&dest.pfx,byte_cnt);
	dest.pfx_len = bit_cnt;

	ATTR_LIST(p_att,rib_id)
		{
		/* test to see if this peer is my local node
		 * if not, skip this attribute
		 */
 
		if (p_att->peer_alloc != &idrp_this_node)
			continue;

		for (p_rte = p_att->route_id_list;p_rte; p_rte = p_rte->p_next)
			{
			NLRI_FAMILY_LOOP(i)
				{
				for (p_irt = p_rte->p_route[i]; p_irt; p_irt = p_irt->p_next_nlri)
					{
					if (!isopfxcompare(&dest,&p_irt->nlri))
						{

						/* destination matches - do the options
						 * length the same
						 * family the same
						 * options the same
						 * NET/IP address the same
						 */
     
						if ((p_irt->p_loc_rt_peer->iso.siso_len == (byte_cnt+2)) && 
						    (p_irt->p_loc_rt_peer->a.sa_family == family) &&  
							(p_irt->p_attr->p_opts->p_local_opts == p_opts) && 
							(bcmp(p_irt->p_loc_rt_peer->iso.siso_addr,p_gw_str,byte_cnt) == 0))
							{
							return(p_irt);
							}
						}
					}
				} NLRI_FAMILY_LOOP_END;
			}
		} ATTR_LIST_END;

	return(0);
					
}


idrp_attribute_record *
create_local_att(p_opts,p_next_hop,local_flags,rib_id)
idrpRoute_options	*p_opts;
sockaddr_un		*p_next_hop;
int	local_flags;	
int	rib_id;
{
idrp_attribute_record *p_atts;

	p_atts = (idrp_attribute_record *) idrp_local_mem_fit(sizeof(idrp_attribute_record));
	p_atts->peer_alloc= &idrp_this_node;
	p_atts->local_mask =  local_flags; 
	p_atts->rib_id = rib_id;

	/* allocate the options block for the next hop
	 * attribute
	 */

	p_atts->p_opts = (idrpRoute_options *) idrp_local_mem_fit(sizeof(idrpRoute_options));
	idrp_copy_opts(p_opts,p_atts->p_opts,rib_id);
	
	/* create next_hop in options and point to this gw within
	 * the idrp attribute record
	 * - this is the next_hop for current installation
	 * 
	 *  In the future, if we want we can do the multi-path 
	 *  attribute.  
	 */

	p_atts->next_hop = idrp_copy_opts_nexthop(p_atts->p_opts,p_next_hop);
	
	/* allocate the route_id_list
	 * 
	 */

	p_atts->route_id_list = (idrpRoute_entry *) idrp_local_mem_fit(sizeof(idrpRoute_entry ));
	p_atts->route_id_list->route_id = IDRP_LOCAL_ROUTE_ID;  
	
	IDRP_STATUS_BIT_TEST(p_atts->p_opts,IDRP_OPTS_EXT_INFO)
		{
		p_atts->route_id_list->route_id = IDRP_EXT_INFO_ROUTE_ID; 
		}

	/* 
	 * Allocate the canonical RD path
	 * set-up the global ordered rdpath list 
	 */

	p_atts->rd_path = (idrp_canon_rdpath *) idrp_local_mem_fit(sizeof(idrp_canon_rdpath));
	  
	p_atts->p_rd_opath = p_my_rdpath;	


	/* fill local attributes and link to attribute list */


	idrp_fill_local_man_attrib(p_atts);
	idrp_fill_local_opt_attrib(p_atts);

#ifdef	IDRP_QOS
	idrp_fill_local_qos_attrib(p_atts);
#endif
	return(p_atts);
}



idrp_attribute_record *
find_local_att_rec(p_next_hop,p_opts,rib_id)
sockaddr_un	*p_next_hop;
idrpRoute_options	*p_opts;
int			rib_id;
{
idrp_attribute_record	*p_att;
int	idrp_mask;

	idrp_mask = idrp_opts_to_mask(p_opts,p_next_hop,rib_id);

	ATTR_LIST(p_att,rib_id)
		{
		/* test to see if it is my node,
		 * - local route w/out a pdu
		 * and non-external info
		 */
		if ((p_att->peer_alloc == &idrp_this_node) 
			&& (BIT_TEST(p_att->local_mask, IDRP_LOCAL_NO_PDU))
			&& (p_opts == p_att->p_opts->p_local_opts))
			{	
			/* if the next hop is the same
			 * - and the options match
			 *  we've got a match 
			 */

			if (sockaddrcmp(p_next_hop,p_att->next_hop))
				{
				return(p_att);
				}
			}
		} ATTR_LIST_END;

	/* create an idrp attribute record */ 


	p_att = create_local_att(p_opts,p_next_hop,(IDRP_LOCAL_NO_PDU),rib_id);

	/* link on the general attribute list */
	
	link_att_list(p_att);
	return (p_att);
}	
			 
 

/* fill in the local_mandatory attributes */


void
idrp_fill_local_man_attrib(p_atts)
idrp_attribute_record *p_atts;
{
idrp_attribute_record	*att;
idrp_attribute_record	*p_last;

	/* set ups the route_id list to local route_id */
 
	p_atts->route_id_list->route_id = IDRP_LOCAL_ROUTE_ID;
	p_atts->route_id_list->peer = &idrp_this_node;
	p_atts->route_id_list->status = IDRP_ATTR_ROUTE_ID_NORM;

	/* set local route_id and pref to zero - should
	 * never go out
	 */

	bzero(&idrp_local_route_id.id,sizeof(route_id));
	idrp_local_route_id.loc_pref = 0;
	

	/* set up attribute mask 
	 * hopcount, route_id, rd path
	 */	

	p_atts->idrp_mask = IDRP_ATTBT_MANDATORY;
	p_atts->attrib[IDRP_ATTR_ROUTE_SEPARATOR].present = TRUE;
	p_atts->attrib[IDRP_ATTR_ROUTE_SEPARATOR].flags = IDRP_ATTRFLG_ROUTE_SEPARATOR;
	p_atts->attrib[IDRP_ATTR_ROUTE_SEPARATOR].data = (u_char *) &idrp_local_route_id; 
	p_atts->attrib[IDRP_ATTR_ROUTE_SEPARATOR].length = IDRP_ROUTE_SEPARATOR_LENGTH;


	p_atts->attrib[IDRP_ATTR_RD_PATH].present = TRUE;
	p_atts->attrib[IDRP_ATTR_RD_PATH].flags = IDRP_ATTRFLG_RD_PATH;
	p_atts->attrib[IDRP_ATTR_RD_PATH].data = (u_char *) &local_rd_path;
	p_atts->attrib[IDRP_ATTR_RD_PATH].length = rt_rdi.isoa_len + sizeof(idrp_path_segment_header) + RDI_LENGTH_BYTE_LEN; 	

	/* note this must be filled in by the init code after the 
	 * the rdi for this box is read in
 	 */
	p_atts->rd_path->p_next = (idrp_canon_rdpath *) 0;
	p_atts->rd_path->p_prev = (idrp_canon_rdpath *) 0;
	p_atts->rd_path->p_rdi = p_rt_rdi;

	/* set the hop count up */

	p_atts->attrib[IDRP_ATTR_HOP_COUNT].present = TRUE;
	p_atts->attrib[IDRP_ATTR_HOP_COUNT].flags = IDRP_ATTRFLG_HOP_COUNT;
	p_atts->attrib[IDRP_ATTR_HOP_COUNT].data = (u_char *) &local_hop_count;  
	p_atts->attrib[IDRP_ATTR_HOP_COUNT].length =IDRP_RD_HOP_COUNT_LENGTH; 

	/* set length in the attribute mandatory length
	 * withtout the rdi length
	 * - that will have to be adjusted 
	 *   after all configurations are done
	 */

	p_atts->attr_len = IDRP_LOCAL_MAN_ATT_LEN; 
	p_atts->p_attr_pdu = (u_char *) 0; 

	if (p_atts->p_opts)
		{
		p_atts->p_opts->capacity.value = idrp_this_node.Capacity;
		} 
	p_atts->attrib[IDRP_ATTR_CAPACITY].present = TRUE;
	p_atts->attrib[IDRP_ATTR_CAPACITY].flags = IDRP_ATTRFLG_CAPACITY;
	p_atts->attrib[IDRP_ATTR_CAPACITY].data = (u_char *) &idrp_this_node.Capacity;  
	p_atts->attrib[IDRP_ATTR_CAPACITY].length =IDRP_CAPACITY_LENGTH; 
}



void
idrp_fill_local_opt_attrib(p_atts)
idrp_attribute_record	*p_atts;
{
int	len = 0;
int	len2 = 0;

	/* fill in next hop */

	if (p_atts->next_hop)
		{
		len2 = fill_next_hop(p_atts);
		if (p_atts->local_mask & IDRP_LOCAL_ROUTE_SERVER_FLAG)
			{
			len += len2;
			}
		}

	/* make sure that we have non-zero options field
	 */

	assert(p_atts->p_opts);

	IDRP_STATUS_BIT_TEST(p_atts->p_opts,IDRP_OPTS_EXT_INFO)
		{
		p_atts->local_mask |= IDRP_LOCAL_EXT_INFO;
		p_atts->idrp_mask |= IDRP_ATTBT_EXT_INFO;
		p_atts->attrib[IDRP_ATTR_EXT_INFO].present = TRUE;
		p_atts->attrib[IDRP_ATTR_EXT_INFO].flags = IDRP_ATTRFLG_EXT_INFO;
		p_atts->attrib[IDRP_ATTR_EXT_INFO].length = 0;
		p_atts->attrib[IDRP_ATTR_EXT_INFO].data = (u_char *) 0;
		len += IDRP_EXT_INFO_LENGTH + sizeof(idrp_path_attr_hdr); 
		}

	/* fill in the DIST_LIST_INCL and DIST_LIST_EXCL parameters
	 * only one of the DIST_LISTs can be active at a time
	 * use include for first try
	 */

	if (p_atts->p_opts->p_DIST_LIST_INCL)
		{
		len += fill_DIST_LIST(p_atts,p_atts->p_opts->p_DIST_LIST_INCL,IDRP_ATTR_DIST_LIST_INCL);
		
		if (p_atts->p_opts->p_DIST_LIST_EXCL)
		  trace_tf(idrp_trace_options, TR_NORMAL, 0, ("DIST INCL AND EXCL both active -- using INCL!"));
		}
	else 
		{	
	 	if (p_atts->p_opts->p_DIST_LIST_EXCL)
			{
			len += fill_DIST_LIST(p_atts,p_atts->p_opts->p_DIST_LIST_EXCL,IDRP_ATTR_DIST_LIST_EXCL);
			}
		}

	IDRP_STATUS_BIT_TEST(p_atts->p_opts, IDRP_OPTS_MULTI_EXIT) 
		{
		len += fill_MULTI_EXIT(p_atts);
		}
	
	p_atts->attr_len += len;
}	

int
fill_next_hop(p_atts)
idrp_attribute_record	*p_atts;
{
int	mem_need = 0;
u_short	hold;
u_char	*cp;
int	i;
int	j;
int	k;
int	family;
int	size;
int	cnt;
snpa_entry	*p_snpa;
idrp_next_hop *p_net;
	

	/* fill in the idrp next_hop feature if there is a gateway
	 */  

	if (p_atts->next_hop == NULL)
		{
		return(0);
		}

	/* set the flags and that NEXT_HOP is prsent */

	p_atts->idrp_mask |= IDRP_ATTBT_NEXT_HOP;
	p_atts->attrib[IDRP_ATTR_NEXT_HOP].present = TRUE;
	p_atts->attrib[IDRP_ATTR_NEXT_HOP].flags = IDRP_ATTRFLG_NEXT_HOP;

	/* default is not to send the next hop */ 


	NLRI_FAMILY_LOOP(i)
		{
		mem_need += p_atts->p_opts->next_hop[i].next_hop_snpas.pdu_len;
		cnt = i;	
		} NLRI_FAMILY_LOOP_END;


	/* length need - NET length, plus header bytes
	 * SNPA lengths plus count bytes
	 * + one for Route server byte
	 */

	mem_need += (cnt * IDRP_NEXT_HOP_ADDRESS_SPACE) + IDRP_NEXT_HOP_SPACE_FUDGE; 
        cp = idrp_local_mem_fit(mem_need);
        p_atts->attrib[IDRP_ATTR_NEXT_HOP].data = cp; 

	/* copy in the Route Server flag into the record
	 * - default to IDRP_SERVER_ALLOWED for now
	 */

	IDRP_STATUS_BIT_TEST(p_atts->p_opts,IDRP_OPTS_ROUTE_SERVER)
		{				
		p_atts->local_mask |= IDRP_LOCAL_ROUTE_SERVER_FLAG;
		*cp++ = IDRP_SERVER_ALLOWED;
		}	
	else
		{
		p_atts->local_mask |= IDRP_LOCAL_DONT_SEND_NEXT_HOP;
		*cp++ = IDRP_SERVER_NOT_ALLOWED;
		}


	NLRI_FAMILY_LOOP(i)
		{
		p_net = (idrp_next_hop *) &p_atts->p_opts->next_hop[i];
		for (j = 0; j < p_atts->p_opts->next_hop[i].cnt; j++)
			{
			/* Make sure we are not having a null next hop 
			 * next hop
		 	 */

			assert(p_net != (idrp_next_hop *) NULL); 

			/* generate the protocol type for this NET */
	
			bcopy (&idrp_nlri_proto_id[i].proto_type,cp,1);
			cp++;
			bcopy (&idrp_nlri_proto_id[i].proto_len,cp,1);
			cp++;
			bcopy(&idrp_nlri_proto_id[i].proto_val,cp,idrp_nlri_proto_id[i].proto_len);
			hold = (u_int)idrp_nlri_proto_id[i].proto_len;
			cp += hold;

			/* copy in the NETs now
			 * - check for one per protocol for now 
			 * copy out each NET' snpa-sequence one at at time 
			 */
			switch(i)
				{
				case IDRP_NLRI_ISO:
					if (IDRP_LOCAL_CNF_TEST(IDRP_CNF_OPT_EXPAND_NEXT_HOP))
						{
						size = p_net->p_net->iso.siso_len - 2;
						*cp++ = size;
						bcopy (&p_net->p_net->iso.siso_addr[0],cp,size);
						}
					else
						{
						/* copy in this node's NET as the NEXT HOP
						 */

						size = rt_net[0].isoa_len;
						*cp++ = size;
						bcopy(&rt_net[0].isoa_genaddr[0],cp,size);
						}
					cp += size;
					break;	
					 
				case IDRP_NLRI_IP:
					{
					sockaddr_un *p_ip = (sockaddr_un *) p_net->p_net;
					size = sizeof(p_ip->in.sin_addr); 
					*cp++ = size;

					if (IDRP_LOCAL_CNF_TEST(IDRP_CNF_OPT_EXPAND_NEXT_HOP) ||
						(rt_ip_net[0].in.sin_len == 0))
						{
						bcopy ((caddr_t) &p_ip->in.sin_addr,cp,size);
						}
					else
						{
						bcopy ((caddr_t) &rt_ip_net[0].in.sin_addr,cp,size);
						}	
					cp += size;
					}
					break;
				}

			/* if there is a options record count of SNPAs
			 * if snpa cnt is zero, this will still work
			 */
	 
			hold = p_net->next_hop_snpas.cnt;
			*cp++ = hold;

			if (hold)
				{
				p_snpa = (snpa_entry *) &p_net->next_hop_snpas.snpa1;
				for (k = 0; k < hold; k++)
					{
					/* copy in all the snpa octets */

					*cp++ = p_snpa->len;
					bcopy(p_snpa->snpa,cp,p_snpa->len);
					cp += p_snpa->len;
					p_snpa = p_snpa->p_next;
					}
				}
			/* set up this to the next NET for this NLRI) 
			 */
 
			p_net = p_net->p_next;
			}
		} NLRI_FAMILY_LOOP_END; 

	p_atts->attrib[IDRP_ATTR_NEXT_HOP].length = (cp - p_atts->attrib[IDRP_ATTR_NEXT_HOP].data);
	
	return (mem_need);
}


int
fill_DIST_LIST(p_atts,p_rd,type)
idrp_attribute_record	*p_atts;
idrp_canon_rdpath	*p_rd;
int			type;
{
idrp_canon_rdpath	*p_rd2;
idrp_rdi_mem		req;	
int			len = 0;
int			mem_need = 0; 
u_char			*cp,*cp_begin;

	/* calculate statistics on rd path 
	 * - the amount of rdis in sequence
	 * and the memory need for DIST_LIST attribute
	 */ 
	

	/* add one to the memory for the count of rdis */

	mem_need = rdi_canon_length(p_rd,&req) + 1;
	cp = cp_begin = (u_char *) idrp_local_mem_fit(mem_need);


	/* copy in the count of rdis in the
	 * pdus	 
	 */

	*cp = req.cnt;
	cp++;

	/* now put length, value in the pdus */

	p_rd2 = p_rd;
	while (p_rd2) /*@@@@@@ */
		{
		register int rdi_len;
		rdi_len = p_rd2->p_rdi->rdi.isoa_len;	
		*cp = rdi_len;
		cp++;
		bcopy(&p_rd2->p_rdi->rdi.isoa_genaddr,cp,rdi_len);
		cp += rdi_len; 
		p_rd2 = p_rd2->p_next;
		}

	if (type == IDRP_ATTR_DIST_LIST_INCL)
		{
		/* distribution list include */

		p_atts->idrp_mask |= IDRP_ATTBT_DIST_LIST_INCL;
		p_atts->attrib[IDRP_ATTR_DIST_LIST_INCL].present = TRUE;
		p_atts->attrib[IDRP_ATTR_DIST_LIST_INCL].flags = IDRP_ATTRFLG_DIST_LIST_INCL;
		p_atts->attrib[IDRP_ATTR_DIST_LIST_INCL].length = mem_need;
		p_atts->attrib[IDRP_ATTR_DIST_LIST_INCL].data = (u_char *) cp_begin;
		}
	if (type == IDRP_ATTR_DIST_LIST_EXCL)
		{
		/* distribution list exclude */

		p_atts->idrp_mask |= IDRP_ATTBT_DIST_LIST_EXCL;
		p_atts->attrib[IDRP_ATTR_DIST_LIST_EXCL].present = TRUE;
		p_atts->attrib[IDRP_ATTR_DIST_LIST_EXCL].flags = IDRP_ATTRFLG_DIST_LIST_EXCL;
		p_atts->attrib[IDRP_ATTR_DIST_LIST_EXCL].length = mem_need;
		p_atts->attrib[IDRP_ATTR_DIST_LIST_EXCL].data = (u_char *) cp_begin;
		}

	return (mem_need);

}


int fill_MULTI_EXIT(p_atts)
idrp_attribute_record	*p_atts;
{
	/* default to the multi_exit value for the first sent
	 * - should this be multi_exit_rcvd - skh 5/1/95
	 */

        assert(p_atts->p_opts);
        p_atts->idrp_mask |= IDRP_ATTBT_MULTI_EXIT_DISC;
        p_atts->attrib[IDRP_ATTR_MULTI_EXIT_DISC].present = TRUE;
        p_atts->attrib[IDRP_ATTR_MULTI_EXIT_DISC].flags = IDRP_ATTRFLG_MULTI_EXIT_DISC;
        p_atts->attrib[IDRP_ATTR_MULTI_EXIT_DISC].length = IDRP_MULTI_EXIT_DISC_LENGTH;
        p_atts->attrib[IDRP_ATTR_MULTI_EXIT_DISC].data = (u_char *)&p_atts->p_opts->multi_exit[0];
}

#ifdef IDRP_QOS
void
idrp_fill_local_qos_attrib(p_atts)
idrp_attribute_record	*p_atts;
{
int	len = 0;
idrp_distinguish_att	*p_qos;
u_char	*cp;
	
	assert(p_atts->p_opts);
	p_qos = p_atts->p_opts->p_qos;

	if (p_qos == NULL)
		{
		return;
		}

/* set lengths and values from the
 * pre-set qos rib
 */

	p_atts->attr_len += qos_rib[p_qos->rib_id]->update_pdu_len;
 
	if (IDRP_IDRP_MASK_TEST(p_qos,IDRP_ATTBT_TRANSIT_DELAY))
		{
		p_atts->idrp_mask |= IDRP_ATTBT_TRANSIT_DELAY;
		p_atts->attrib[IDRP_ATTR_TRANSIT_DELAY].present = TRUE;
		p_atts->attrib[IDRP_ATTR_TRANSIT_DELAY].flags = IDRP_ATTRFLG_TRANSIT_DELAY;
		p_atts->attrib[IDRP_ATTR_TRANSIT_DELAY].length = IDRP_TRANSIT_DELAY_LENGTH;
		p_atts->attrib[IDRP_ATTR_TRANSIT_DELAY].data = qos_rib[p_qos->rib_id]->p_delay;
		}

	if (IDRP_IDRP_MASK_TEST(p_qos,IDRP_ATTBT_RESIDUAL_ERROR))
		{	
		p_atts->idrp_mask |= IDRP_ATTBT_RESIDUAL_ERROR;
		p_atts->attrib[IDRP_ATTR_RESIDUAL_ERROR].present = TRUE;
		p_atts->attrib[IDRP_ATTR_RESIDUAL_ERROR].flags = IDRP_ATTRFLG_RESIDUAL_ERROR;
		p_atts->attrib[IDRP_ATTR_RESIDUAL_ERROR].length = IDRP_RESIDUAL_ERROR_LENGTH;
		p_atts->attrib[IDRP_ATTR_RESIDUAL_ERROR].data = qos_rib[p_qos->rib_id]->p_error;
		}

	if (IDRP_IDRP_MASK_TEST(p_qos,IDRP_ATTBT_EXPENSE))
		{	
		p_atts->idrp_mask |= IDRP_ATTBT_EXPENSE;
		p_atts->attrib[IDRP_ATTR_EXPENSE].present = TRUE;
		p_atts->attrib[IDRP_ATTR_EXPENSE].flags = IDRP_ATTRFLG_EXPENSE;
		p_atts->attrib[IDRP_ATTR_EXPENSE].length = IDRP_EXPENSE_LENGTH;
		p_atts->attrib[IDRP_ATTR_EXPENSE].data = qos_rib[p_qos->rib_id]->p_expense;
		}

	if (IDRP_IDRP_MASK_TEST(p_qos,IDRP_ATTBT_SECURITY))
		{	
		/* only FAA uses security right now 
	 	 */
		p_atts->idrp_mask |= IDRP_ATTBT_SECURITY;
		p_atts->attrib[IDRP_ATTR_SECURITY].present = TRUE;
		p_atts->attrib[IDRP_ATTR_SECURITY].flags = IDRP_ATTRFLG_SECURITY;
		p_atts->attrib[IDRP_ATTR_SECURITY].length = FAA_SECURITY_LENGTH;
		p_atts->attrib[IDRP_ATTR_SECURITY].data = qos_rib[p_qos->rib_id]->p_security;
		}

	if (IDRP_IDRP_MASK_TEST(p_qos,IDRP_ATTBT_PRIORITY)) 
		{
		p_atts->idrp_mask |= IDRP_ATTBT_PRIORITY;
		p_atts->attrib[IDRP_ATTR_PRIORITY].present = TRUE;
		p_atts->attrib[IDRP_ATTR_PRIORITY].flags = IDRP_ATTRFLG_PRIORITY;
		p_atts->attrib[IDRP_ATTR_PRIORITY].length = IDRP_PRIORITY_LENGTH;
		p_atts->attrib[IDRP_ATTR_EXPENSE].data = qos_rib[p_qos->rib_id]->p_priority;
		}	
}
#endif


idrp_canon_rdpath *
create_local_rd_path(rdi_len,p_rdi_str)
int	rdi_len;
byte	*p_rdi_str;
{
idrp_canon_rdpath	*p_rd;
rdi			*p_rdi;

	p_rd = (idrp_canon_rdpath *) idrp_local_mem_fit(sizeof(idrp_canon_rdpath));

	/* create an RDI and if new, it will be added
	 */
 
	p_rdi = (rdi *) idrp_local_mem_fit(sizeof(rdi));
	bcopy(p_rdi_str,&p_rdi->rdi.isoa_genaddr[0],rdi_len);
	p_rdi->rdi.isoa_len = rdi_len;
	p_rdi->rdi.isoa_family = AF_ISO;
	p_rdi = idrp_insert_global_rdi(&p_rdi);
	p_rd->p_rdi = p_rdi;  	
	return (p_rd);
}

sockaddr_un *
idrp_create_local_gw(p_gw_str,gw_byte_cnt,family)
u_char	*p_gw_str;
int	gw_byte_cnt;
int	family;
{
idrp_next_hop	*p_nhop,*p_last_nhop;
int	nlri_id;
struct	iso_net_addr	gw;	
sockaddr_un	*p_opts_gw;

	bzero(&gw,sizeof(gw));
	p_opts_gw = (sockaddr_un *) &gw;
	p_opts_gw->a.sa_family = family;
	p_opts_gw->a.sa_len = gw_byte_cnt;
	nlri_id = family_to_nlri_id(family);
	switch (nlri_id)
		{
		case IDRP_NLRI_ISO:
			bcopy(p_gw_str,&p_opts_gw->iso.siso_addr,gw_byte_cnt);
			break;
		case IDRP_NLRI_IP:
			p_opts_gw->in.sin_port = 0;
			bcopy(p_gw_str,&p_opts_gw->in.sin_addr,gw_byte_cnt);
			break;
		}
	
	return (sockdup(p_opts_gw));
}

sockaddr_un *
idrp_copy_opts_nexthop(p_opts,p_next_hop)
idrpRoute_options	*p_opts;
sockaddr_un		*p_next_hop;
{
int	nlri_id;
idrp_next_hop	*p_nhop = NULL;
idrp_next_hop	*p_last_nhop = NULL;

	nlri_id = family_to_nlri_id(p_next_hop->a.sa_family);
	if (p_opts->next_hop[nlri_id].cnt)
		{
		for (p_nhop = p_opts->next_hop[nlri_id].p_next; p_nhop; p_nhop = p_nhop->p_next)
			{
			p_last_nhop = p_nhop;
			}
		p_nhop  = p_last_nhop->p_next = (idrp_next_hop *) idrp_local_mem_fit(sizeof(idrp_next_hop));
		}
	else
		{
		p_nhop = &p_opts->next_hop[nlri_id]; 
		}

	p_nhop->p_net = p_next_hop;
	p_opts->next_hop[nlri_id].cnt++;
	return(p_nhop->p_net);
}


void
create_local_snpa_entry(pp_snpa_list,len,ptr)
snpa_list	**pp_snpa_list;
int		len;
u_char		*ptr;
{
snpa_entry *p_ent;
snpa_list  *p_snpa_list;

	if (*pp_snpa_list) 
		{
		p_snpa_list = *pp_snpa_list;
		}
	else
		{
		p_snpa_list = (snpa_list *) idrp_local_mem_fit(sizeof(*p_snpa_list));
		bzero((caddr_t) pp_snpa_list, sizeof(*p_snpa_list));
		*pp_snpa_list = p_snpa_list;
		}

	if (p_snpa_list->cnt)
		{
 		/* allocate snpa lists and we had better free them later */
		p_ent = p_snpa_list->snpa1.p_next;
       		if (p_ent)
			{
			/* loop getting the tail of the list */
			while (p_ent->p_next)
				{	
				p_ent = p_ent->p_next;
				}	
			}
		else
			{
			p_ent = &p_snpa_list->snpa1;
			}

		p_ent->p_next= (snpa_entry *) idrp_local_mem_fit(sizeof(snpa_entry));

                /* set the p_ent pointer to the snpa entry to fill */

		p_ent = p_ent->p_next;
		}
	else
		{
		/* 1st snpa  is in line space  */

		p_ent = &p_snpa_list->snpa1;
		p_snpa_list->pdu_len = 0;
		}

	p_snpa_list->cnt++;
	p_snpa_list->pdu_len += len;
	p_ent->len = len;
	bcopy(ptr, &p_ent->snpa,len);
	p_ent->p_next = (snpa_entry *) 0;
}	


void
idrp_local_route_reset()
{
idrp_attribute_record	*p_att;
int			rib_id = 0 ;

	/* loop flaging all the local attribute records
	 * and routes that reconfiguration has occurred 
	 */

	QOS_RIB_LIST(rib_id)
		{
		ATTR_LIST(p_att,rib_id)
		  {
		      idrp_flag_local_att(p_att);
		  }
		ATTR_LIST_END
		} QOS_RIB_LIST_END;

}

	

int 
idrp_local_route_clean()
{
idrp_attribute_record	*p_att;
int			changes = 0;
int			rib_id = 0; 

	QOS_RIB_LIST(rib_id)
	   {
	   ATTR_LIST(p_att,rib_id)
		  {
	 	  changes += idrp_clean_local_att(p_att);
		  } ATTR_LIST_END;
	   }QOS_RIB_LIST_END;	
}

void 
idrp_local_clear_reconfig()
{
idrp_attribute_record 	*p_att;
idrpRoute	*p_irt;
idrpRoute_entry	*p_rte;
int		i,rib_id;
int		changes	= 0;	

	
     QOS_RIB_LIST(rib_id)
	{
	ATTR_LIST(p_att,rib_id)
		{
		for (p_rte = p_att->route_id_list; p_rte; p_rte = p_rte->p_next)
			{
			 /*
			 * clean route chain of RECONFIG status flag
			 */

			NLRI_FAMILY_LOOP(i)
				{
				for (p_irt = p_rte->p_route[i]; p_irt; p_irt = p_irt->p_next_nlri)
					{
					IDRP_STATUS_BIT_CLEAR(p_irt,IDRP_STATUS_RECONFIGURE); 
					}
				} NLRI_FAMILY_LOOP_END;
			}
		} ATTR_LIST_END;
	} QOS_RIB_LIST_END;

}
	


/* free the attribute  space created for local attribute records */


void
idrp_free_local_att(p_att)
idrp_attribute_record	*p_att;
{
idrpRoute_entry	*p_rte,*p_rte2;
int		cnt;
	
        /* free the the attribute records pieces
         * 1) free all route_id_list entries
	 * 2) free all options
         * 3) free any rd_canon path
         */


         /* 1) free the local route chains
         */

	cnt = idrp_free_routeid_chain(p_att);
 	trace_tf (idrp_trace_options, 0, TR_NORMAL, ("idrp local route-id  freed %d routes", cnt));

	/* 2) free the route options
	 */
	 
	if (p_att->p_opts)
		{
		idrp_free_opts(p_att->p_opts);
		}	

	/* 3) free canon rdpath
	 */
	
	idrp_free_canon_rdpath(p_att->rd_path);

        /* 4) free the transitive attribute
	 */

       	if (p_att->p_transitive)
                {
		trace_tf (idrp_trace_options, LOG_ERR,0, ("transitive in local routes"));
                idrp_free_trans(p_att->p_transitive);
                }


	/*
	 *  free the attribute record space
	 * - decrement the reference count 
	 *  
	 */

	free_local_att(p_att);

}

void
free_local_att(p_att)
idrp_attribute_record *p_att;
{
int i;

	/* free the opath - specific to the local node
	 */

	if (p_att->p_rd_opath)
		{
		p_my_rdpath->refcnt--;
		}


	/* do the remainder of the attribute space
	 * - IDRP_ATTR_ROUTE SEPARTOR has local data - do not free
	 * - IDRP_ATTR_RD_PATH - has local data - do not free
	 * - IDRP_MULTI_EXIT_DISC - has local data - do not free
	 * - IDRP_ATTR_HOP_COUNT - has local data - do not free
	 * That leaves:
	 * NEXT_HOP, IDRP_DIST_LIST_INCL, IDRP_DIST_LIST_EXCL
	 * in this version of idrp 
	 * And in the future-  TRANSIT_DELAY, EXPENSE, LOCALLY_DEF_QOS   
 	 * SECURITY, CAPACITY and PRIORITY
	 */	
		
	for (i = IDRP_ATTR_NEXT_HOP; i < IDRP_ATTR_MULTI_EXIT_DISC; i++)
		{ 
		if (p_att->attrib[i].data)
			{
			idrp_mem_fit_free((void **) &p_att->attrib[i].data, p_att->attrib[i].length);	 
			}
		}

}


void 
idrp_flag_local_att(p_att)
idrp_attribute_record *p_att;
{
idrpRoute_entry	*p_rte;
idrpRoute	*p_irt;
int		i;

	/* walk all route_id_list and
	 * flag all routes as needing
	 * reconfiguration 
	 */
	p_rte = p_att->route_id_list;

	/* loop through the local_route_attr_record
	 * free the local route chains
	 */

	for (p_rte = p_att->route_id_list; p_rte; p_rte = p_rte->p_next)	
		{
		p_rte->status |= IDRP_LOCAL_ROUTE_RECONFIG; 
		NLRI_FAMILY_LOOP(i)
			{
			for (p_irt = p_rte->p_route[i]; p_irt; p_irt = p_irt->p_next_nlri)
				{
				p_irt->status |= IDRP_STATUS_RECONFIGURE;
				}
			} 
		}	
}


int
idrp_clean_local_att(p_att)
idrp_attribute_record *p_att;
{
idrpRoute_entry	*p_rte,*p_rte_last;
int		changes = 0;


	/* loop through the local_route_attr_record
	 * cleaning out the local route chains
	 * if no nlri exists on local route chain - free it
	 */

	p_rte_last = 0;
	p_rte = p_att->route_id_list;
	while (p_rte)
		{
		/* here we need to flag if we
		 * need to keep the route chain
		 */
		p_rte_last = p_rte;
		p_rte = p_rte->p_next;
		if (p_rte_last->status & IDRP_ATTR_ROUTE_ID_OSILOCAL)
			{
			changes = clean_local_route_chain(p_rte_last);
			}
		}
	return(changes);
}



int
clean_local_route_chain(p_rte)
idrpRoute_entry	*p_rte;
{
idrpRoute	*p_irt,*p_last_rt;
int		i;
int		changes	= 0;	

	NLRI_FAMILY_LOOP(i)
		{
		p_irt = p_rte->p_route[i];
		while (p_irt)
			{
			p_last_rt = p_irt;
			p_irt = p_irt->p_next_nlri;
			IDRP_STATUS_BIT_TEST(p_last_rt, IDRP_STATUS_RECONFIGURE)
				{
				IDRP_STATUS_BIT_CLEAR(p_last_rt,IDRP_STATUS_RECONFIGURE);
				/* delete the gated route
				 * delete the route out of route lists and attribute record 
				 * delete idrpRoute
				 */

				IDRP_STATUS_BIT_TEST(p_last_rt,IDRP_STATUS_LOCAL_DAMP_DEL)
					{
					/* hit this code before,
					 * and so we must have add/delete/add/delete within
					 * the min advterisment timer
					 */
					IDRP_STATUS_BIT_SET(p_last_rt,IDRP_STATUS_DELETE);
					}
				else
					{
					if (IS_IDRP_DAMPED_ROUTE(p_last_rt))
						{
						/* the route is damped, and this is a damped route.
						 * - for this it has to have been anounced.
						 *   and be a phase3 route location
						 * - set the flag that says -	
						 * LOCAL OSI route to be deleted
						 * after minimum route timer goes off
						 * - clear reconfigure so we know  
						 * we've processed it
						 * - clear out the link that gated expects
						 *    in rt_data 
						 * - we must do delete to change the
						 * phase3 status, but
						 * min adver needs the timer
						 * 
						 */
						IDRP_STATUS_BIT_SET(p_last_rt, (IDRP_STATUS_LOCAL_DAMP_DEL | IDRP_STATUS_DELETE));
						p_last_rt->p_rt->rt_data = NULL;
						idrp_del_rt_gated(p_last_rt,IDRP_NO_RESET_RT_BIT);
						}
					else
						{
						/* not damped route 
						 */
	
						IDRP_STATUS_BIT_TEST(p_last_rt,IDRP_STATUS_LOC_RIB)
							{
							IDRP_STATUS_BIT_SET(p_last_rt, (IDRP_STATUS_DELETE));
							p_last_rt->p_rt->rt_data = NULL;
							idrp_del_rt_gated(p_last_rt,IDRP_NO_RESET_RT_BIT);
							}
						else
							{
							/* not in local rib and it will
							 *
							 */
							idrp_free_outlist(p_last_rt);
							idrp_free_nlri_att_rec(p_last_rt,NLRI_LINKED_P_NEXT);	
					
							/* clear the rt data entry so gated won't try
							 * to free non-task memory 
							 * test to make sure gated route is there 
							 * 
							 */
	
							assert(p_last_rt->p_rt != NULL);
							p_last_rt->p_rt->rt_data = NULL;
							p_last_rt->p_rt->rt_idrp = NULL;
							idrp_del_rt_gated(p_last_rt,IDRP_RESET_RT_BIT);
							IDRP_MEM_FIT_FREE(p_last_rt);
							}
						}
					}
				changes++;
				}
			}
		}

	return(changes);	
}
	



void_t _MEM[100000];
static int _MC = 0;

u_char *
idrp_local_mem_fit(len)
int len;
{
	int found = 0;
	int i = 0;
	
  	u_char *p;	/* hack -- clean up first byte which was used in free list
			 * link stuff. CHL */

  	if (len <= IDRP_SMALL_BLOCK_SIZE) {
		p = idrp_small_blk_alloc();
#ifdef MEM_TRACE
        	trace_tf(idrp_trace_options, TR_NORMAL, 0, 
			("MEM_TRACE small_blk_alloc %x (length %d)", 
			p, len));
#endif
		bzero (p,IDRP_SMALL_BLOCK_SIZE);
	} else if (len <= IDRP_MEDIUM_BLOCK_SIZE) {
		p = idrp_med_blk_alloc();
#ifdef MEM_TRACE
        	trace_tf(idrp_trace_options, TR_NORMAL, 0, 
			("MEM_TRACE med_blk_alloc %x (length %d)", 
			p, len));
#endif
		bzero (p,IDRP_MEDIUM_BLOCK_SIZE);
	} else if (len <= IDRP_BIG_BLOCK_SIZE) {
		p = idrp_big_blk_alloc();
#ifdef MEM_TRACE
        	trace_tf(idrp_trace_options, TR_NORMAL, 0, 
			("MEM_TRACE big_blk_alloc %x (length %d)", 
			p, len));
#endif
		bzero (p, IDRP_BIG_BLOCK_SIZE);
	} else if (len <= IDRP_HUGE_BLOCK_SIZE) {
		p = idrp_huge_blk_alloc();
#ifdef MEM_TRACE
        	trace_tf(idrp_trace_options, TR_NORMAL, 0, 
			("MEM_TRACE huge_blk_alloc %x (length %d)", 
			p, len));
#endif
		bzero (p, IDRP_HUGE_BLOCK_SIZE);
	} else {
	  	trace_tf (idrp_trace_options, TR_NORMAL, LOG_WARNING, ("ALLOC FAILED -- SIZE %d bigger than largest!", len));
	  	exit (-1);
	}

	for (i=0; (i < _MC) && (found == 0); i++) 
		if (_MEM[i] == (void_t) p)
		{
			found = 1;
		}

	if (found) {
        	trace_tf(idrp_trace_options, TR_NORMAL, 0, 
			("MEM_TRACE DANGER, WILL ROBINSON! reallocated pointer %x (length %d)", 
			 p, len));
	}
	else
	{
	if (_MC > 100000)
		{
	        trace_tf(idrp_trace_options, TR_NORMAL, 0, 
			("MEM_TRACE DANGER, WILL ROBINSON! _MC in MEM over top (length %d)", 
			 i));
		}
	else
		{	
		_MEM[_MC++] = p;
		}
	}
	
	return (p);
}

void
idrp_mem_fit_free(pp_mem,len)
void **pp_mem;
int	len;
{
	int found = 0;
	int i = 0;
	
	if (!pp_mem || !(*pp_mem)) {
        	trace_tf(idrp_trace_options, TR_NORMAL, 0, 
			("MEM_TRACE DANGER, WILL ROBINSON! attempt to free NULL pointer (length %d)", 
			 len));
		return;
	}

	for (i=0; i< _MC && (!found) ; i++) 
		if (_MEM[i] == (void_t) *pp_mem)
		{
			found = 1;
			_MEM[i] = (void *) NULL;
		}
	/*
	assert (found == 1);
	*/
	if (!found) {
        	trace_tf(idrp_trace_options, TR_NORMAL, 0, 
			("MEM_TRACE DANGER, WILL ROBINSON! attempt to free UNALLOCATED pointer %x (length %d)", 
			 *pp_mem, len));
		return;
	}

	if (len <= IDRP_SMALL_BLOCK_SIZE) {
		idrp_small_blk_free((u_char *) *pp_mem);
#ifdef MEM_TRACE
        	trace_tf(idrp_trace_options, TR_NORMAL, 0, 
			("MEM_TRACE small_blk_free %x (length %d)", 
			*pp_mem, len));
#endif
	} else if (len <= IDRP_MEDIUM_BLOCK_SIZE) {
		idrp_med_blk_free((u_char *) *pp_mem);
#ifdef MEM_TRACE
        	trace_tf(idrp_trace_options, TR_NORMAL, 0, 
			("MEM_TRACE med_blk_free %x (length %d)", 
			*pp_mem, len));
#endif
	} else if (len <= IDRP_BIG_BLOCK_SIZE) {
		idrp_big_blk_free((u_char *) *pp_mem);
#ifdef MEM_TRACE
        	trace_tf(idrp_trace_options, TR_NORMAL, 0, 
			("MEM_TRACE big_blk_free %x (length %d)", 
			*pp_mem, len));
#endif
	} else if (len <= IDRP_HUGE_BLOCK_SIZE) {
		idrp_huge_blk_free((u_char *) *pp_mem);
#ifdef MEM_TRACE
        	trace_tf(idrp_trace_options, TR_NORMAL, 0, 
			("MEM_TRACE huge_blk_free %x (length %d)", 
			*pp_mem, len));
#endif
	} else {
		trace_tf(idrp_trace_options, TR_NORMAL, LOG_WARNING, 
			("FREE FAILED -- SIZE %d bigger than largest!", len));
		exit(-1);
	}

	/* SET THIS DE-ALLOCATED THING TO NULL!!! */
	*pp_mem = (void *) NULL;

	return;
}

int rdi_canon_length(p_rdi,p_req)
idrp_canon_rdpath	*p_rdi;
idrp_rdi_mem		*p_req;
{
idrp_canon_rdpath	*p_rd;
int			len;
int			cnt;

	for (p_rd = p_rdi,cnt = 0, len = 0 ; p_rd; p_rd = p_rd->p_next,cnt++)
		{
		/* add in the length of the rdi */
		len += p_rd->p_rdi->rdi.isoa_len + 1;
		}
	p_req->cnt = cnt;
	p_req->mem_need = len;

return (len);
}

void
idrp_local_rdi_print(p_rdi)
idrp_canon_rdpath 	*p_rdi;
{
	trace_tf(idrp_trace_options, TR_NORMAL,0, ("got to idrp_local_rdi_print\n"));
}		


void
idrp_test_stopper()
{
	trace_tf (idrp_trace_options, TR_NORMAL,0,("I got to the test stopper"));
}


int idrp_net_cnf_prefix()
{
int     i;
int     changes = 0;

u_char  *p_net;
int     net_cnt,family,len;
idrpRoute_options       *p_opts;
idrp_attribute_record   *p_att;
idrp_iso_gw             *p_idrp_gw = idrp_this_node.p_local_iso_gw;
int			rib_id = RIB_ID_DEFAULT;

        p_opts = idrp_this_node.p_local_info;

        /* create ISO prefix out of NET from box
	 * only for the default rib
         */

        if (rt_net_cnt > 1 &&  p_idrp_gw == (idrp_iso_gw *) NULL)
                {
                p_idrp_gw = idrp_this_node.p_local_iso_gw = (idrp_iso_gw *) idrp_local_mem_fit(sizeof(idrp_iso_gw));
                for (i = 1 ; i < rt_net_cnt; i++)
                        {
                        bcopy(&idrp_this_node.iso_gw,&p_idrp_gw->gw[i-1],sizeof(gw_entry));
                        bcopy(&rt_net[i],&p_idrp_gw->net[i-1],sizeof(struct iso_net_addr));
                        p_idrp_gw->net[i-1].isoa_len +=2;
                        p_idrp_gw->net[i-1].isoa_family = AF_ISO;
                        p_idrp_gw->gw[i-1].gw_addr = (sockaddr_un *) &p_idrp_gw->net[i-1];
                        }
                }


        for (i = 0; i < rt_net_cnt; i++)
                {
                gw_entry        *p_intf = NULL;

                p_net = (u_char *) &rt_net[i-1].isoa_genaddr[0];
                if (i > 0)
                        {
                        p_intf = &idrp_this_node.p_local_iso_gw->gw[i-1];
                        }

                net_cnt = rt_net[i].isoa_len-1 ;
                family  = AF_ISO;

                if (idrp_local_rt(p_net,net_cnt,(8 * net_cnt),family,p_net,net_cnt+1,IDRP_LOCAL_STATIC,p_opts))
                        {
                        changes++;
                        }
                }

        /*  fix the length for these new routes */

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

        ATTR_LIST(p_att,rib_id)
                {
                /* reset the length - we may have done
                 * - it earlier in idrp_local_peer_inti
                 * - but  reset for these new routes
                 */

                if (p_att->local_mask & IDRP_LOCAL_RDPATH_RESET_LENGTH)
                        {
                        p_att->attrib[IDRP_ATTR_RD_PATH].length = len;
			p_att->p_rd_opath = p_my_rdpath;
                        }
                } ATTR_LIST_END;


        return(changes);
}
	
