/*
 * idrp_policy.c  sjr $Id: idrp_policy.c,v 1.3 1995/08/01 20:25:51 sjr Exp $
 */

#define	INCLUDE_CTYPE
#include "include.h"
#include "parse.h"

adv_psfunc idrp_adv_psfunc = {
	&idrp_ps_rtmatch,
	&idrp_ps_dstmatch,
	NULL,
	&idrp_ps_print,
	&idrp_ps_free
};

/*
 * idrp_set_import_return_vals just OVERLAYS the (idrp_ps_t *) ps_data fields
 * "idrp_pref" and "route_options" with the values in (idrp_ps_t *) ps_policy, 
 * if ps_policy is non-NULL.
 *
 * NOTE THAT THIS MEANS THAT YOU MUST CALL THIS FUNCTION WITH THE GLOBAL 
 * (DEFAULT) VALUES, IF ANY, THEN CALL THIS FUNCTION WITH THE MORE-SPECIFIC
 * VALUES, IF ANY.
 *
 * Note that 'ps_data' must be non-NULL; the user has to have allocated
 * this beforehand.
 *
 * Note also that the idrp_pref is an integer; this allows the return of
 * the IDRP_INVALID_ROUTE_PREF value < 0 (-1), to distinguish between
 * valid pref (0 is valid!) and invalid/no pref.
 */
void
idrp_set_import_return_vals __PF4(adv_proto, proto_t,
			    	  adv_flag, flag_t,
			   	  ps_policy, void_t,
			   	  ps_data, void_t)
{
	idrpRoute_info *p_idrp_return_info, *p_idrp_policy_info;
	idrpRoute *p_idrp_route;

/*
 * Taken out due to parse_proto silliness in parser.y...
	if (adv_proto != RTPROTO_IDRP) {
		trace_tf(idrp_trace_options, TR_NORMAL|TR_POLICY, 0,
			("%s (%d):  Incorrect adv_proto = %d (should have RTPROTO_IDRP); bailing.\n", 
			__FILE__, __LINE__, adv_flag));
		exit(-1);
	}
*/

	if (!BIT_TEST(adv_flag, ADVFT_DM)) {
		trace_tf(idrp_trace_options, TR_NORMAL|TR_POLICY, 0,
			("%s (%d):  Incorrect adv_flag = %lx (should have ADVFT_DM); bailing.\n", 
			__FILE__, __LINE__, adv_flag));
		exit(-1);
	}

	if (!ps_data) {
		trace_tf(idrp_trace_options, TR_NORMAL|TR_POLICY, 0,
			("%s (%d):  No ps_data; can't pass up results for IDRP!  Bailing...\n", 
			__FILE__, __LINE__));
		exit(-1);
	}

	p_idrp_return_info = (idrpRoute_info *) ps_data;
	p_idrp_policy_info = (idrpRoute_info *) ps_policy;

	if (p_idrp_policy_info) {
		/* Only reset these fields if the new info is valid */
		if (p_idrp_policy_info->idrp_pref != IDRP_INVALID_ROUTE_PREF) {
			p_idrp_return_info->idrp_pref 
				= p_idrp_policy_info->idrp_pref;
		}
		if (p_idrp_policy_info->route_options) {
			p_idrp_return_info->p_idrp_rt->p_import_opts
				= p_idrp_policy_info->route_options;
		}
	}

	return;
}

void
idrp_set_export_return_vals __PF4(adv_proto, proto_t,
			    	  adv_flag, flag_t,
			   	  ps_policy, void_t,
			   	  p_route, idrpRoute *)
{
	idrpRoute_info *p_idrp_policy_info;

/*
 * Taken out due to parse_proto silliness in parser.y...
	if (adv_proto != RTPROTO_IDRP) {
		trace_tf(idrp_trace_options, TR_NORMAL|TR_POLICY, 0,
			("%s (%d):  Incorrect adv_proto = %d (should have RTPROTO_IDRP); bailing.\n", 
			__FILE__, __LINE__, adv_flag));
		exit(-1);
	}
*/

	if (!BIT_TEST(adv_flag, ADVFT_DM)) {
		trace_tf(idrp_trace_options, TR_NORMAL|TR_POLICY, 0,
			("%s (%d):  Incorrect adv_flag = %lx (should have ADVFT_DM); bailing.\n", 
			__FILE__, __LINE__, adv_flag));
		exit(-1);
	}

	if (!p_route) {
		trace_tf(idrp_trace_options, TR_NORMAL|TR_POLICY, 0,
			("%s (%d):  No p_route; can't pass up results for IDRP!  Bailing...\n", 
			__FILE__, __LINE__));
		exit(-1);
	}

	p_idrp_policy_info = (idrpRoute_info *) ps_policy;

	if (p_idrp_policy_info) {
		/* Only reset these fields if the new info is valid */
		if (p_idrp_policy_info->route_options) {
			p_route->p_export_opts 
				= p_idrp_policy_info->route_options;
		}
	}

	return;
}

int
policy_rdpath_cmp __PF2(p_rdpath1, const struct _policy_rdpath *,  
			p_rdpath2, const struct _policy_rdpath *)
{
	int test;

	for (;;
	     p_rdpath1 = p_rdpath1->p_next, p_rdpath2 = p_rdpath2->p_next)
	{
		/* if both are not NULL, then test */
	     	if ((p_rdpath1) && (p_rdpath2)) {
			if (p_rdpath1->status == p_rdpath2->status)
				{
				/* now test to see  rdi and path seq
				*/

                               if (p_rdpath1->status == IDRP_RDPATH_SEQ ||
                                   p_rdpath1->status == IDRP_RDPATH_RDC_ENTRY_SEQ)
                                       {
                                       test = RDI_CMP(p_rdpath1->p_rdi, p_rdpath2->p_rdi);

                                       /* if the rdis are note the same, return
                                        */

                                       if (test)
                                               {
                                               return (test);
                                               }
                                       }
				else
					{
					/* not sequences - use the RDI_CMP
					 */

					test = RDI_CMP(p_rdpath1->p_rdi, p_rdpath2->p_rdi);
					}
                               }

		/* if only one is NULL, then die */
		} else if (!(p_rdpath1)) {
			return (-1);
		} else if (!(p_rdpath2)) {
#ifdef	IDRP_ANSI_FIX
			return (1);
#else
			return (+1);
#endif  /* IDRP_ANSI_FIX */ 
		}
			
	}

	/* Must be equal */
	return (0);
}


int
rdpath_adv_match __PF2(p_policy_rdpath, policy_rdpath *, 
		       p_actual_path, struct _rdpath_list *) 
{
	return(policy_and_actual_rdpath_cmp(p_policy_rdpath, p_actual_path));
}
		   

void
rdi_adv_free __PF1(p_rdi, struct iso_net_addr *)
{

        IDRP_MEM_FIT_FREE(p_rdi);
        return;
}

